package handlers

import (
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"

	"mengyastore-backend/internal/config"
	"mengyastore-backend/internal/models"
	"mengyastore-backend/internal/storage"
)

type AdminHandler struct {
	store *storage.JSONStore
	cfg   *config.Config
}

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"`
}

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

func NewAdminHandler(store *storage.JSONStore, cfg *config.Config) *AdminHandler {
	return &AdminHandler{store: store, cfg: cfg}
}

func (h *AdminHandler) GetAdminToken(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"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": "invalid payload"})
		return
	}
	screenshotURLs, valid := normalizeScreenshotURLs(payload.ScreenshotURLs)
	if !valid {
		c.JSON(http.StatusBadRequest, gin.H{"error": "screenshot urls must be 5 or fewer"})
		return
	}
	active := true
	if payload.Active != nil {
		active = *payload.Active
	}
	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,
	}
	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": "invalid payload"})
		return
	}
	screenshotURLs, valid := normalizeScreenshotURLs(payload.ScreenshotURLs)
	if !valid {
		c.JSON(http.StatusBadRequest, gin.H{"error": "screenshot urls must be 5 or fewer"})
		return
	}
	active := false
	if payload.Active != nil {
		active = *payload.Active
	}
	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,
	}
	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": "invalid payload"})
		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{"status": "deleted"})
}

func (h *AdminHandler) requireAdmin(c *gin.Context) bool {
	token := c.Query("token")
	if token == "" {
		token = c.GetHeader("Authorization")
	}
	if token == h.cfg.AdminToken {
		return true
	}
	c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
	return false
}

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
}
