package handlers

import (
	"bytes"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"

	"crm-go/internal/storage"
	"crm-go/models"

	"github.com/xuri/excelize/v2"
)

type CustomerHandler struct {
	storage       storage.CustomerStorage
	feishuWebhook string
}

func NewCustomerHandler(storage storage.CustomerStorage, feishuWebhook string) *CustomerHandler {
	return &CustomerHandler{
		storage:       storage,
		feishuWebhook: feishuWebhook,
	}
}

func (h *CustomerHandler) GetCustomers(w http.ResponseWriter, r *http.Request) {
	page := 1
	pageSize := 10

	if pageStr := r.URL.Query().Get("page"); pageStr != "" {
		if p, err := strconv.Atoi(pageStr); err == nil && p > 0 {
			page = p
		}
	}

	if pageSizeStr := r.URL.Query().Get("pageSize"); pageSizeStr != "" {
		if ps, err := strconv.Atoi(pageSizeStr); err == nil && ps > 0 {
			pageSize = ps
		}
	}

	customers, err := h.storage.GetAllCustomers()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	total := len(customers)
	totalPages := (total + pageSize - 1) / pageSize

	start := (page - 1) * pageSize
	end := start + pageSize

	if start >= total {
		customers = []models.Customer{}
	} else if end > total {
		customers = customers[start:]
	} else {
		customers = customers[start:end]
	}

	response := map[string]interface{}{
		"customers":  customers,
		"total":      total,
		"page":       page,
		"pageSize":   pageSize,
		"totalPages": totalPages,
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

func (h *CustomerHandler) GetCustomerByID(w http.ResponseWriter, r *http.Request) {
	// Extract customer ID from URL path
	urlPath := r.URL.Path
	// The path should be /api/customers/{id}
	pathParts := strings.Split(urlPath, "/")

	if len(pathParts) < 4 {
		http.Error(w, "Invalid URL format", http.StatusBadRequest)
		return
	}

	id := pathParts[3] // Get the ID from the path

	// Remove query parameters if any
	if idx := strings.Index(id, "?"); idx != -1 {
		id = id[:idx]
	}

	customer, err := h.storage.GetCustomerByID(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if customer == nil {
		http.Error(w, "Customer not found", http.StatusNotFound)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(customer)
}

func (h *CustomerHandler) CreateCustomer(w http.ResponseWriter, r *http.Request) {
	var req models.CreateCustomerRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	customer := models.Customer{
		CustomerName:    req.CustomerName,
		IntendedProduct: req.IntendedProduct,
		Version:         req.Version,
		Description:     req.Description,
		Solution:        req.Solution,
		Type:            req.Type,
		Module:          req.Module,
		StatusProgress:  req.StatusProgress,
		Reporter:        req.Reporter,
		CreatedAt:       time.Now(),
	}

	if err := h.storage.CreateCustomer(customer); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(customer)
}

func (h *CustomerHandler) UpdateCustomer(w http.ResponseWriter, r *http.Request) {
	// Extract customer ID from URL path
	urlPath := r.URL.Path
	// The path should be /api/customers/{id}
	pathParts := strings.Split(urlPath, "/")

	if len(pathParts) < 4 {
		http.Error(w, "Invalid URL format", http.StatusBadRequest)
		return
	}

	id := pathParts[3] // Get the ID from the path

	// Remove query parameters if any
	if idx := strings.Index(id, "?"); idx != -1 {
		id = id[:idx]
	}

	var req models.UpdateCustomerRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	// Get customer info for notification
	customer, err := h.storage.GetCustomerByID(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if err := h.storage.UpdateCustomer(id, req); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Send Feishu notification if reporter (trial period) is updated
	if req.Reporter != nil && *req.Reporter != "" && h.feishuWebhook != "" && customer != nil {
		go h.sendTrialNotification(customer.CustomerName, *req.Reporter)
	}

	w.WriteHeader(http.StatusOK)
}

func (h *CustomerHandler) DeleteCustomer(w http.ResponseWriter, r *http.Request) {
	// Extract customer ID from URL path
	urlPath := r.URL.Path
	// The path should be /api/customers/{id}
	pathParts := strings.Split(urlPath, "/")

	if len(pathParts) < 4 {
		http.Error(w, "Invalid URL format", http.StatusBadRequest)
		return
	}

	id := pathParts[3] // Get the ID from the path

	// Remove query parameters if any
	if idx := strings.Index(id, "?"); idx != -1 {
		id = id[:idx]
	}

	if err := h.storage.DeleteCustomer(id); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
}

func (h *CustomerHandler) ImportCustomers(w http.ResponseWriter, r *http.Request) {
	err := r.ParseMultipartForm(10 << 20) // 10 MB
	if err != nil {
		http.Error(w, "Unable to parse form", http.StatusBadRequest)
		return
	}

	file, handler, err := r.FormFile("file")
	if err != nil {
		http.Error(w, "Unable to get file", http.StatusBadRequest)
		return
	}
	defer file.Close()

	// Check file extension
	filename := handler.Filename
	isExcel := strings.HasSuffix(strings.ToLower(filename), ".xlsx")

	importedCount := 0
	duplicateCount := 0

	if isExcel {
		// Parse as Excel file
		f, err := excelize.OpenReader(file)
		if err != nil {
			http.Error(w, "Unable to open Excel file", http.StatusBadRequest)
			return
		}
		defer f.Close()

		// Get the first sheet
		sheets := f.GetSheetList()
		if len(sheets) == 0 {
			http.Error(w, "No sheets found in Excel file", http.StatusBadRequest)
			return
		}

		// Read all rows from the first sheet
		rows, err := f.GetRows(sheets[0])
		if err != nil {
			http.Error(w, "Unable to read Excel file", http.StatusBadRequest)
			return
		}

		// Skip header row if exists
		for i, row := range rows {
			if i == 0 {
				continue // Skip header row
			}

			if len(row) < 2 {
				continue // Skip rows with insufficient data
			}

			customer := models.Customer{
				ID:              "", // Will be generated by the storage
				CreatedAt:       time.Now(),
				CustomerName:    getValue(row, 0),
				IntendedProduct: getValue(row, 1),
				Version:         getValue(row, 2),
				Description:     getValue(row, 3),
				Solution:        getValue(row, 4),
				Type:            getValue(row, 5),
				Module:          getValue(row, 6),
				StatusProgress:  getValue(row, 7),
				Reporter:        "",
			}

			// Check for duplicate
			exists, err := h.storage.CustomerExists(customer)
			if err != nil {
				http.Error(w, "Error checking for duplicate customer", http.StatusInternalServerError)
				return
			}

			if exists {
				duplicateCount++
				continue // Skip duplicate
			}

			if err := h.storage.CreateCustomer(customer); err != nil {
				http.Error(w, "Error saving customer", http.StatusInternalServerError)
				return
			}

			importedCount++
		}
	} else {
		// Parse as CSV
		content, err := io.ReadAll(file)
		if err != nil {
			http.Error(w, "Unable to read file", http.StatusBadRequest)
			return
		}

		reader := csv.NewReader(strings.NewReader(string(content)))
		records, err := reader.ReadAll()
		if err != nil {
			http.Error(w, "Unable to parse CSV file", http.StatusBadRequest)
			return
		}

		// Skip header row if exists
		for i, row := range records {
			if i == 0 {
				continue // Skip header row
			}

			if len(row) < 2 {
				continue // Skip rows with insufficient data
			}

			customer := models.Customer{
				ID:              "", // Will be generated by the storage
				CreatedAt:       time.Now(),
				CustomerName:    getValue(row, 0),
				IntendedProduct: getValue(row, 1),
				Version:         getValue(row, 2),
				Description:     getValue(row, 3),
				Solution:        getValue(row, 4),
				Type:            getValue(row, 5),
				Module:          getValue(row, 6),
				StatusProgress:  getValue(row, 7),
				Reporter:        "",
			}

			// Check for duplicate
			exists, err := h.storage.CustomerExists(customer)
			if err != nil {
				http.Error(w, "Error checking for duplicate customer", http.StatusInternalServerError)
				return
			}

			if exists {
				duplicateCount++
				continue // Skip duplicate
			}

			if err := h.storage.CreateCustomer(customer); err != nil {
				http.Error(w, "Error saving customer", http.StatusInternalServerError)
				return
			}

			importedCount++
		}
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message":        "Customers imported successfully",
		"importedCount":  importedCount,
		"duplicateCount": duplicateCount,
	})
}

func getValue(row []string, index int) string {
	if index < len(row) {
		return row[index]
	}
	return ""
}

// sendTrialNotification sends a Feishu notification when trial period is set/updated
func (h *CustomerHandler) sendTrialNotification(customerName, trialPeriod string) {
	if h.feishuWebhook == "" {
		return
	}

	message := map[string]interface{}{
		"msg_type": "text",
		"content": map[string]string{
			"text": fmt.Sprintf("温馨提示：%s客户于明日试用到期，请及时跟进！\n试用时间：%s", customerName, trialPeriod),
		},
	}

	jsonData, err := json.Marshal(message)
	if err != nil {
		log.Printf("Failed to marshal Feishu message: %v", err)
		return
	}

	resp, err := http.Post(h.feishuWebhook, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		log.Printf("Failed to send Feishu notification: %v", err)
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		log.Printf("Feishu API returned status: %d", resp.StatusCode)
		return
	}

	log.Printf("Sent trial notification for customer: %s", customerName)
}
