package admin

import (
	"net/http"
	"strconv"
	"time"

	"bindbox-game/internal/code"
	"bindbox-game/internal/pkg/core"
	"bindbox-game/internal/pkg/validation"
	"bindbox-game/internal/repository/mysql/model"
)

type createSystemCouponRequest struct {
	Name          string `json:"name" binding:"required"`
	Status        *int32 `json:"status"`
	CouponType    *int32 `json:"coupon_type"`
	DiscountType  *int32 `json:"discount_type"`
	DiscountValue *int64 `json:"discount_value"`
	MinAmount     *int64 `json:"min_amount"`
	ValidDays     *int   `json:"valid_days"`
	TotalQuantity *int64 `json:"total_quantity"`
}

type createSystemCouponResponse struct {
	ID      int64  `json:"id"`
	Message string `json:"message"`
}

func (h *handler) CreateSystemCoupon() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(createSystemCouponRequest)
		res := new(createSystemCouponResponse)
		if err := ctx.ShouldBindJSON(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}
		if ctx.SessionUserInfo().IsSuper != 1 {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
			return
		}
		now := time.Now()
		m := &model.SystemCoupons{
			Name:          req.Name,
			ScopeType:     getInt32OrDefault(req.CouponType, 1),
			DiscountType:  getInt32OrDefault(req.DiscountType, 1),
			DiscountValue: getInt64OrDefault(req.DiscountValue, 0),
			MinSpend:      getInt64OrDefault(req.MinAmount, 0),
			Status:        getInt32OrDefault(req.Status, 1),
		}
		if req.ValidDays != nil && *req.ValidDays > 0 {
			m.ValidStart = now
			m.ValidEnd = now.Add(time.Duration(*req.ValidDays) * 24 * time.Hour)
		}
		if err := h.writeDB.SystemCoupons.WithContext(ctx.RequestContext()).Create(m); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
			return
		}
		if req.TotalQuantity != nil {
			if _, err := h.writeDB.SystemCoupons.WithContext(ctx.RequestContext()).Where(h.writeDB.SystemCoupons.ID.Eq(m.ID)).Updates(map[string]any{"total_quantity": *req.TotalQuantity}); err != nil {
				ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
				return
			}
		}
		res.ID = m.ID
		res.Message = "操作成功"
		ctx.Payload(res)
	}
}

type modifySystemCouponRequest struct {
	Name          *string `json:"name"`
	Status        *int32  `json:"status"`
	CouponType    *int32  `json:"coupon_type"`
	DiscountType  *int32  `json:"discount_type"`
	DiscountValue *int64  `json:"discount_value"`
	MinAmount     *int64  `json:"min_amount"`
	ValidDays     *int    `json:"valid_days"`
	TotalQuantity *int64  `json:"total_quantity"`
}

func (h *handler) ModifySystemCoupon() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(modifySystemCouponRequest)
		if err := ctx.ShouldBindJSON(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}
		idStr := ctx.Param("coupon_id")
		id, _ := strconv.ParseInt(idStr, 10, 64)
		if ctx.SessionUserInfo().IsSuper != 1 {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
			return
		}
		set := map[string]any{}
		if req.Name != nil {
			set["name"] = *req.Name
		}
		if req.Status != nil {
			set["status"] = *req.Status
		}
		if req.CouponType != nil {
			set["scope_type"] = *req.CouponType
		}
		if req.DiscountType != nil {
			set["discount_type"] = *req.DiscountType
		}
		if req.DiscountValue != nil {
			set["discount_value"] = *req.DiscountValue
		}
		if req.MinAmount != nil {
			set["min_spend"] = *req.MinAmount
		}
		if req.ValidDays != nil && *req.ValidDays > 0 {
			now := time.Now()
			set["valid_start"] = now
			set["valid_end"] = now.Add(time.Duration(*req.ValidDays) * 24 * time.Hour)
		}
		if req.TotalQuantity != nil {
			set["total_quantity"] = *req.TotalQuantity
		}
		if len(set) == 0 {
			ctx.Payload(pcSimpleMessage{Message: "操作成功"})
			return
		}
		if _, err := h.writeDB.SystemCoupons.WithContext(ctx.RequestContext()).Where(h.writeDB.SystemCoupons.ID.Eq(id)).Updates(set); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
			return
		}
		ctx.Payload(pcSimpleMessage{Message: "操作成功"})
	}
}

func (h *handler) DeleteSystemCoupon() core.HandlerFunc {
    return func(ctx core.Context) {
        idStr := ctx.Param("coupon_id")
        id, _ := strconv.ParseInt(idStr, 10, 64)
        if ctx.SessionUserInfo().IsSuper != 1 {
            ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
            return
        }
        uid := int64(ctx.SessionUserInfo().Id)
        set := map[string]any{"deleted_at": time.Now(), "deleted_by": uid}
        if _, err := h.writeDB.SystemCoupons.WithContext(ctx.RequestContext()).Where(h.writeDB.SystemCoupons.ID.Eq(id)).Updates(set); err != nil {
            ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
            return
        }
        ctx.Payload(pcSimpleMessage{Message: "操作成功"})
    }
}

type listSystemCouponsRequest struct {
	Name     string `form:"name"`
	Status   *int32 `form:"status"`
	Page     int    `form:"page"`
	PageSize int    `form:"page_size"`
}

type systemCouponItem struct {
	ID            int64  `json:"id"`
	Name          string `json:"name"`
	Status        int32  `json:"status"`
	CouponType    int32  `json:"coupon_type"`
	DiscountType  int32  `json:"discount_type"`
	DiscountValue int64  `json:"discount_value"`
	MinAmount     int64  `json:"min_amount"`
	MaxDiscount   int64  `json:"max_discount"`
	ValidDays     int    `json:"valid_days"`
	TotalQuantity int64  `json:"total_quantity"`
	UsedQuantity  int64  `json:"used_quantity"`
	CreatedAt     string `json:"created_at"`
}

type listSystemCouponsResponse struct {
	Page     int                `json:"page"`
	PageSize int                `json:"page_size"`
	Total    int64              `json:"total"`
	List     []systemCouponItem `json:"list"`
}

func (h *handler) ListSystemCoupons() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(listSystemCouponsRequest)
		res := new(listSystemCouponsResponse)
		if err := ctx.ShouldBindForm(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}
		if req.Page <= 0 {
			req.Page = 1
		}
		if req.PageSize <= 0 {
			req.PageSize = 20
		}
		q := h.readDB.SystemCoupons.WithContext(ctx.RequestContext()).ReadDB()
		if req.Name != "" {
			q = q.Where(h.readDB.SystemCoupons.Name.Like("%" + req.Name + "%"))
		}
		if req.Status != nil {
			q = q.Where(h.readDB.SystemCoupons.Status.Eq(*req.Status))
		}
		total, err := q.Count()
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ServerError, err.Error()))
			return
		}
		type dbRow struct {
			ID            int64
			Name          string
			Status        int32
			ScopeType     int32
			DiscountType  int32
			DiscountValue int64
			MinSpend      int64
			ValidStart    time.Time
			ValidEnd      time.Time
			CreatedAt     time.Time
			TotalQuantity int64
		}
		var rows []dbRow
		if err := q.Order(h.readDB.SystemCoupons.ID.Desc()).Limit(req.PageSize).Offset((req.Page - 1) * req.PageSize).Scan(&rows); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ServerError, err.Error()))
			return
		}
		res.Page = req.Page
		res.PageSize = req.PageSize
		res.Total = total
		res.List = make([]systemCouponItem, len(rows))
		for i, v := range rows {
			validDays := 0
			if !v.ValidStart.IsZero() && !v.ValidEnd.IsZero() {
				diff := v.ValidEnd.Sub(v.ValidStart)
				validDays = int(diff.Hours() / 24)
			}
			// 统计已发放数量（用户持券数）
			usedCnt, _ := h.readDB.UserCoupons.WithContext(ctx.RequestContext()).Where(h.readDB.UserCoupons.CouponID.Eq(v.ID)).Count()
			res.List[i] = systemCouponItem{
				ID:            v.ID,
				Name:          v.Name,
				Status:        v.Status,
				CouponType:    v.ScopeType,
				DiscountType:  v.DiscountType,
				DiscountValue: v.DiscountValue,
				MinAmount:     v.MinSpend,
				MaxDiscount:   0,
				ValidDays:     validDays,
				TotalQuantity: v.TotalQuantity,
				UsedQuantity:  usedCnt,
				CreatedAt:     v.CreatedAt.Format("2006-01-02 15:04:05"),
			}
		}
		ctx.Payload(res)
	}
}

func getInt32OrDefault(v *int32, d int32) int32 {
	if v != nil {
		return *v
	}
	return d
}
func getInt64OrDefault(v *int64, d int64) int64 {
	if v != nil {
		return *v
	}
	return d
}
