package handlers

import (
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"

	"mengyastore-backend/internal/models"
)

type productPayload struct {
	Name            string   `json:"name"`
	Price           float64  `json:"price"`
	DiscountPrice   float64  `json:"discountPrice"`
	Tags            string   `json:"tags"`
	CoverURL        string   `json:"coverUrl"`
	Codes           []string `json:"codes"`
	ScreenshotURLs  []string `json:"screenshotUrls"`
	Description     string   `json:"description"`
	Active          *bool    `json:"active"`
	RequireLogin    bool     `json:"requireLogin"`
	MaxPerAccount   int      `json:"maxPerAccount"`
	DeliveryMode    string   `json:"deliveryMode"`
	FulfillmentType string   `json:"fulfillmentType"`
	FixedContent    string   `json:"fixedContent"`
	ShowNote        bool     `json:"showNote"`
	ShowContact     bool     `json:"showContact"`
}

func normalizeFulfillmentPayload(payload *productPayload) string {
	ft := strings.TrimSpace(strings.ToLower(payload.FulfillmentType))
	if ft == "fixed" {
		return "fixed"
	}
	return "card"
}

type togglePayload struct {
	Active bool `json:"active"`
}

// VerifyAdminToken checks whether the supplied token is correct.
// Returns {"valid": true/false} without leaking the real token value.
func (h *AdminHandler) VerifyAdminToken(c *gin.Context) {
	var payload struct {
		Token string `json:"token"`
	}
	if err := c.ShouldBindJSON(&payload); err != nil || payload.Token == "" {
		c.JSON(http.StatusOK, gin.H{"valid": false})
		return
	}
	c.JSON(http.StatusOK, gin.H{"valid": payload.Token == h.cfg.AdminToken})
}

func (h *AdminHandler) ListAllProducts(c *gin.Context) {
	if !h.requireAdmin(c) {
		return
	}
	items, err := h.store.ListAll()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"data": items})
}

func (h *AdminHandler) CreateProduct(c *gin.Context) {
	if !h.requireAdmin(c) {
		return
	}
	var payload productPayload
	if err := c.ShouldBindJSON(&payload); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数有误"})
		return
	}
	screenshotURLs, valid := normalizeScreenshotURLs(payload.ScreenshotURLs)
	if !valid {
		c.JSON(http.StatusBadRequest, gin.H{"error": "截图链接最多 5 条"})
		return
	}
	active := true
	if payload.Active != nil {
		active = *payload.Active
	}
	ft := normalizeFulfillmentPayload(&payload)
	if ft == "fixed" && strings.TrimSpace(payload.FixedContent) == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "固定内容发货须填写发货内容（如网盘链接、说明文字）"})
		return
	}
	dm := strings.TrimSpace(payload.DeliveryMode)
	if dm == "" {
		dm = "auto"
	}
	product := models.Product{
		Name:            payload.Name,
		Price:           payload.Price,
		DiscountPrice:   payload.DiscountPrice,
		Tags:            normalizeTags(payload.Tags),
		CoverURL:        strings.TrimSpace(payload.CoverURL),
		Codes:           payload.Codes,
		ScreenshotURLs:  screenshotURLs,
		Description:     payload.Description,
		Active:          active,
		RequireLogin:    payload.RequireLogin,
		MaxPerAccount:   payload.MaxPerAccount,
		DeliveryMode:    dm,
		FulfillmentType: ft,
		FixedContent:    payload.FixedContent,
		ShowNote:        payload.ShowNote,
		ShowContact:     payload.ShowContact,
	}
	created, err := h.store.Create(product)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"data": created})
}

func (h *AdminHandler) UpdateProduct(c *gin.Context) {
	if !h.requireAdmin(c) {
		return
	}
	id := c.Param("id")
	var payload productPayload
	if err := c.ShouldBindJSON(&payload); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数有误"})
		return
	}
	screenshotURLs, valid := normalizeScreenshotURLs(payload.ScreenshotURLs)
	if !valid {
		c.JSON(http.StatusBadRequest, gin.H{"error": "截图链接最多 5 条"})
		return
	}
	active := false
	if payload.Active != nil {
		active = *payload.Active
	}
	ft := normalizeFulfillmentPayload(&payload)
	if ft == "fixed" && strings.TrimSpace(payload.FixedContent) == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "固定内容发货须填写发货内容（如网盘链接、说明文字）"})
		return
	}
	dm := strings.TrimSpace(payload.DeliveryMode)
	if dm == "" {
		dm = "auto"
	}
	patch := models.Product{
		Name:            payload.Name,
		Price:           payload.Price,
		DiscountPrice:   payload.DiscountPrice,
		Tags:            normalizeTags(payload.Tags),
		CoverURL:        strings.TrimSpace(payload.CoverURL),
		Codes:           payload.Codes,
		ScreenshotURLs:  screenshotURLs,
		Description:     payload.Description,
		Active:          active,
		RequireLogin:    payload.RequireLogin,
		MaxPerAccount:   payload.MaxPerAccount,
		DeliveryMode:    dm,
		FulfillmentType: ft,
		FixedContent:    payload.FixedContent,
		ShowNote:        payload.ShowNote,
		ShowContact:     payload.ShowContact,
	}
	updated, err := h.store.Update(id, patch)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"data": updated})
}

func (h *AdminHandler) ToggleProduct(c *gin.Context) {
	if !h.requireAdmin(c) {
		return
	}
	id := c.Param("id")
	var payload togglePayload
	if err := c.ShouldBindJSON(&payload); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数有误"})
		return
	}
	updated, err := h.store.Toggle(id, payload.Active)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"data": updated})
}

func (h *AdminHandler) DeleteProduct(c *gin.Context) {
	if !h.requireAdmin(c) {
		return
	}
	id := c.Param("id")
	if err := h.store.Delete(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"data": gin.H{"ok": true}})
}

func normalizeScreenshotURLs(urls []string) ([]string, bool) {
	cleaned := make([]string, 0, len(urls))
	for _, url := range urls {
		trimmed := strings.TrimSpace(url)
		if trimmed == "" {
			continue
		}
		cleaned = append(cleaned, trimmed)
		if len(cleaned) > 5 {
			return nil, false
		}
	}
	return cleaned, true
}

func normalizeTags(tagsCSV string) []string {
	if tagsCSV == "" {
		return []string{}
	}
	parts := strings.Split(tagsCSV, ",")
	clean := make([]string, 0, len(parts))
	seen := map[string]bool{}
	for _, p := range parts {
		t := strings.TrimSpace(p)
		if t == "" {
			continue
		}
		key := strings.ToLower(t)
		if seen[key] {
			continue
		}
		seen[key] = true
		clean = append(clean, t)
		if len(clean) >= 20 {
			break
		}
	}
	return clean
}
