package handler

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"math/rand"
	"net/http"
	"strings"
	"time"
	"xboard-go/internal/database"
	"xboard-go/internal/model"

	"github.com/gin-gonic/gin"
)

// AdminGiftCardFetch handles fetching of gift card templates and batch info.
func AdminGiftCardFetch(c *gin.Context) {
	params := getFetchParams(c)
	id := params["id"]
	if id != "" {
		var template model.GiftCardTemplate
		if err := database.DB.Where("id = ?", id).First(&template).Error; err != nil {
			Fail(c, http.StatusNotFound, "Template not found")
			return
		}
		Success(c, template)
		return
	}

	var data []model.GiftCardTemplate
	database.DB.Order("sort ASC, id DESC").Find(&data)
	Success(c, data)
}

// AdminGiftCardSave creates or updates a gift card template.
func AdminGiftCardSave(c *gin.Context) {
	var payload model.GiftCardTemplate
	if err := c.ShouldBindJSON(&payload); err != nil {
		Fail(c, http.StatusBadRequest, "invalid request body")
		return
	}

	if payload.ID > 0 {
		if err := database.DB.Model(&model.GiftCardTemplate{}).Where("id = ?", payload.ID).Updates(payload).Error; err != nil {
			Fail(c, http.StatusInternalServerError, "failed to update template")
			return
		}
	} else {
		payload.Status = true
		if err := database.DB.Create(&payload).Error; err != nil {
			Fail(c, http.StatusInternalServerError, "failed to create template")
			return
		}
	}

	Success(c, true)
}

// AdminGiftCardGenerate batches generation of codes for a template.
func AdminGiftCardGenerate(c *gin.Context) {
	var payload struct {
		TemplateID int    `json:"template_id"`
		Count      int    `json:"count"`
		Prefix     string `json:"prefix"`
		ExpiresAt  int64  `json:"expires_at"`
	}
	if err := c.ShouldBindJSON(&payload); err != nil || payload.TemplateID <= 0 || payload.Count <= 0 {
		Fail(c, http.StatusBadRequest, "template_id and count are required")
		return
	}

	batchID := fmt.Sprintf("batch_%d", time.Now().Unix())
	prefix := payload.Prefix
	if prefix == "" {
		prefix = "GC"
	}

	tx := database.DB.Begin()
	for i := 0; i < payload.Count; i++ {
		code := generateGiftCode(prefix)
		item := model.GiftCardCode{
			TemplateID: payload.TemplateID,
			Code:       code,
			BatchID:    batchID,
			Status:     0, // Unused
			MaxUsage:   1,
			ExpiresAt:  &payload.ExpiresAt,
		}
		if payload.ExpiresAt == 0 {
			item.ExpiresAt = nil
		}
		if err := tx.Create(&item).Error; err != nil {
			tx.Rollback()
			Fail(c, http.StatusInternalServerError, "failed to generate codes")
			return
		}
	}
	tx.Commit()

	Success(c, gin.H{"batch_id": batchID})
}

func AdminGiftCardDeleteTemplate(c *gin.Context) {
	var payload struct {
		ID int `json:"id"`
	}
	if err := c.ShouldBindJSON(&payload); err != nil || payload.ID <= 0 {
		Fail(c, http.StatusBadRequest, "template id is required")
		return
	}
	if err := database.DB.Delete(&model.GiftCardTemplate{}, payload.ID).Error; err != nil {
		Fail(c, http.StatusInternalServerError, "failed to delete template")
		return
	}
	Success(c, true)
}

func generateGiftCode(prefix string) string {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	hash := md5.Sum([]byte(fmt.Sprintf("%d%d", time.Now().UnixNano(), r.Int63())))
	return prefix + strings.ToUpper(hex.EncodeToString(hash[:])[:12])
}
