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"
)

// ==================== 次数卡发放 API ====================

type grantGamePassRequest struct {
	UserID     int64  `json:"user_id" binding:"required"`
	ActivityID *int64 `json:"activity_id"` // 可选，NULL表示全局通用
	Count      int32  `json:"count" binding:"required,min=1"`
	ValidDays  *int32 `json:"valid_days"` // 可选，NULL表示永久有效
	Remark     string `json:"remark"`
}

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

// GrantGamePass 为用户发放次数卡
// @Summary 发放次数卡
// @Description 管理员为用户发放游戏次数卡
// @Tags 管理端.次数卡
// @Accept json
// @Produce json
// @Param RequestBody body grantGamePassRequest true "请求参数"
// @Success 200 {object} grantGamePassResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/game-passes/grant [post]
// @Security LoginVerifyToken
func (h *handler) GrantGamePass() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(grantGamePassRequest)
		res := new(grantGamePassResponse)
		if err := ctx.ShouldBindJSON(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}

		// 检查用户是否存在
		user, err := h.readDB.Users.WithContext(ctx.RequestContext()).Where(h.readDB.Users.ID.Eq(req.UserID)).First()
		if err != nil || user == nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "用户不存在"))
			return
		}

		now := time.Now()
		m := &model.UserGamePasses{
			UserID:       req.UserID,
			Remaining:    req.Count,
			TotalGranted: req.Count,
			TotalUsed:    0,
			Source:       "admin",
			Remark:       req.Remark,
			CreatedAt:    now,
			UpdatedAt:    now,
		}

		if req.ActivityID != nil && *req.ActivityID > 0 {
			m.ActivityID = *req.ActivityID
		}

		if req.ValidDays != nil && *req.ValidDays > 0 {
			m.ExpiredAt = now.Add(time.Duration(*req.ValidDays) * 24 * time.Hour)
		}

		q := h.writeDB.UserGamePasses.WithContext(ctx.RequestContext())
		if m.ExpiredAt.IsZero() {
			q = q.Omit(h.writeDB.UserGamePasses.ExpiredAt)
		}
		if err := q.Create(m); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ServerError, err.Error()))
			return
		}

		res.ID = m.ID
		res.Message = "发放成功"
		ctx.Payload(res)
	}
}

// ==================== 次数卡列表 API ====================

type listGamePassesRequest struct {
	UserID     *int64 `form:"user_id"`
	ActivityID *int64 `form:"activity_id"`
	Page       int    `form:"page"`
	PageSize   int    `form:"page_size"`
}

type gamePassItem struct {
	ID           int64  `json:"id"`
	UserID       int64  `json:"user_id"`
	UserName     string `json:"user_name"`
	ActivityID   int64  `json:"activity_id"`
	ActivityName string `json:"activity_name"`
	Remaining    int32  `json:"remaining"`
	TotalGranted int32  `json:"total_granted"`
	TotalUsed    int32  `json:"total_used"`
	ExpiredAt    string `json:"expired_at"`
	Source       string `json:"source"`
	Remark       string `json:"remark"`
	CreatedAt    string `json:"created_at"`
}

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

// ListGamePasses 查询次数卡列表
// @Summary 次数卡列表
// @Description 查询用户次数卡列表，支持按用户、活动过滤
// @Tags 管理端.次数卡
// @Accept json
// @Produce json
// @Param user_id query integer false "用户ID"
// @Param activity_id query integer false "活动ID"
// @Param page query integer false "页码"
// @Param page_size query integer false "每页条数"
// @Success 200 {object} listGamePassesResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/game-passes/list [get]
// @Security LoginVerifyToken
func (h *handler) ListGamePasses() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(listGamePassesRequest)
		res := new(listGamePassesResponse)
		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.UserGamePasses.WithContext(ctx.RequestContext()).ReadDB()
		if req.UserID != nil && *req.UserID > 0 {
			q = q.Where(h.readDB.UserGamePasses.UserID.Eq(*req.UserID))
		}
		if req.ActivityID != nil && *req.ActivityID > 0 {
			q = q.Where(h.readDB.UserGamePasses.ActivityID.Eq(*req.ActivityID))
		}

		total, err := q.Count()
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ServerError, err.Error()))
			return
		}

		passes, err := q.Order(h.readDB.UserGamePasses.ID.Desc()).
			Limit(req.PageSize).
			Offset((req.Page - 1) * req.PageSize).
			Find()
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ServerError, err.Error()))
			return
		}

		// 批量获取用户名和活动名
		userIDs := make([]int64, 0)
		activityIDs := make([]int64, 0)
		for _, p := range passes {
			userIDs = append(userIDs, p.UserID)
			if p.ActivityID > 0 {
				activityIDs = append(activityIDs, p.ActivityID)
			}
		}

		userMap := make(map[int64]string)
		if len(userIDs) > 0 {
			users, _ := h.readDB.Users.WithContext(ctx.RequestContext()).Where(h.readDB.Users.ID.In(userIDs...)).Find()
			for _, u := range users {
				userMap[u.ID] = u.Nickname
			}
		}

		activityMap := make(map[int64]string)
		if len(activityIDs) > 0 {
			activities, _ := h.readDB.Activities.WithContext(ctx.RequestContext()).Where(h.readDB.Activities.ID.In(activityIDs...)).Find()
			for _, a := range activities {
				activityMap[a.ID] = a.Name
			}
		}

		res.Page = req.Page
		res.PageSize = req.PageSize
		res.Total = total
		res.List = make([]gamePassItem, len(passes))
		for i, p := range passes {
			expiredAt := ""
			if !p.ExpiredAt.IsZero() {
				expiredAt = p.ExpiredAt.Format("2006-01-02 15:04:05")
			}
			res.List[i] = gamePassItem{
				ID:           p.ID,
				UserID:       p.UserID,
				UserName:     userMap[p.UserID],
				ActivityID:   p.ActivityID,
				ActivityName: activityMap[p.ActivityID],
				Remaining:    p.Remaining,
				TotalGranted: p.TotalGranted,
				TotalUsed:    p.TotalUsed,
				ExpiredAt:    expiredAt,
				Source:       p.Source,
				Remark:       p.Remark,
				CreatedAt:    p.CreatedAt.Format("2006-01-02 15:04:05"),
			}
		}
		ctx.Payload(res)
	}
}

// ==================== 查询单个用户的次数卡 ====================

type getUserGamePassesResponse struct {
	UserID          int64          `json:"user_id"`
	TotalRemaining  int32          `json:"total_remaining"`
	GlobalRemaining int32          `json:"global_remaining"`
	ActivityPasses  []gamePassItem `json:"activity_passes"`
}

// GetUserGamePasses 查询单个用户的次数卡
// @Summary 查询用户次数卡
// @Description 查询指定用户的所有次数卡
// @Tags 管理端.次数卡
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Success 200 {object} getUserGamePassesResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/users/{user_id}/game-passes [get]
// @Security LoginVerifyToken
func (h *handler) GetUserGamePasses() core.HandlerFunc {
	return func(ctx core.Context) {
		userIDStr := ctx.Param("user_id")
		userID, _ := strconv.ParseInt(userIDStr, 10, 64)
		if userID <= 0 {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "用户ID无效"))
			return
		}

		res := new(getUserGamePassesResponse)
		res.UserID = userID

		now := time.Now()
		passes, err := h.readDB.UserGamePasses.WithContext(ctx.RequestContext()).
			Where(h.readDB.UserGamePasses.UserID.Eq(userID)).
			Where(h.readDB.UserGamePasses.Remaining.Gt(0)).
			Find()
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ServerError, err.Error()))
			return
		}

		// 获取活动名称
		activityIDs := make([]int64, 0)
		for _, p := range passes {
			if p.ActivityID > 0 {
				activityIDs = append(activityIDs, p.ActivityID)
			}
		}
		activityMap := make(map[int64]string)
		if len(activityIDs) > 0 {
			activities, _ := h.readDB.Activities.WithContext(ctx.RequestContext()).Where(h.readDB.Activities.ID.In(activityIDs...)).Find()
			for _, a := range activities {
				activityMap[a.ID] = a.Name
			}
		}

		res.ActivityPasses = make([]gamePassItem, 0)
		for _, p := range passes {
			// 检查是否过期
			if !p.ExpiredAt.IsZero() && p.ExpiredAt.Before(now) {
				continue
			}

			expiredAt := ""
			if !p.ExpiredAt.IsZero() {
				expiredAt = p.ExpiredAt.Format("2006-01-02 15:04:05")
			}

			item := gamePassItem{
				ID:           p.ID,
				UserID:       p.UserID,
				ActivityID:   p.ActivityID,
				ActivityName: activityMap[p.ActivityID],
				Remaining:    p.Remaining,
				TotalGranted: p.TotalGranted,
				TotalUsed:    p.TotalUsed,
				ExpiredAt:    expiredAt,
				Source:       p.Source,
				Remark:       p.Remark,
				CreatedAt:    p.CreatedAt.Format("2006-01-02 15:04:05"),
			}

			res.TotalRemaining += p.Remaining
			if p.ActivityID == 0 {
				res.GlobalRemaining += p.Remaining
			}
			res.ActivityPasses = append(res.ActivityPasses, item)
		}

		ctx.Payload(res)
	}
}

// ==================== 检查活动次数卡 ====================

type checkActivityGamePassesResponse struct {
	ActivityID     int64  `json:"activity_id"`
	UserCount      int64  `json:"user_count"`
	TotalRemaining int64  `json:"total_remaining"`
	CanDelete      bool   `json:"can_delete"`
	Message        string `json:"message"`
}

// CheckActivityGamePasses 检查活动是否有未使用的次数卡
// @Summary 检查活动次数卡
// @Description 检查指定活动是否有用户持有未使用的次数卡，用于下架/删除前校验
// @Tags 管理端.次数卡
// @Accept json
// @Produce json
// @Param activity_id path integer true "活动ID"
// @Success 200 {object} checkActivityGamePassesResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/activities/{activity_id}/game-passes/check [get]
// @Security LoginVerifyToken
func (h *handler) CheckActivityGamePasses() core.HandlerFunc {
	return func(ctx core.Context) {
		activityIDStr := ctx.Param("activity_id")
		activityID, _ := strconv.ParseInt(activityIDStr, 10, 64)
		if activityID <= 0 {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "活动ID无效"))
			return
		}

		res := new(checkActivityGamePassesResponse)
		res.ActivityID = activityID

		// 统计用户数和剩余次数
		type stats struct {
			UserCount      int64
			TotalRemaining int64
		}
		var s stats
		h.repo.GetDbR().Raw(`
			SELECT 
				COUNT(DISTINCT user_id) as user_count,
				COALESCE(SUM(remaining), 0) as total_remaining
			FROM user_game_passes 
			WHERE activity_id = ? AND remaining > 0
		`, activityID).Scan(&s)

		res.UserCount = s.UserCount
		res.TotalRemaining = s.TotalRemaining
		res.CanDelete = s.UserCount == 0

		if s.UserCount > 0 {
			res.Message = "有用户持有该活动的未使用次数卡，请先处理后再下架/删除"
		} else {
			res.Message = "无用户持有该活动的次数卡，可以安全下架/删除"
		}

		ctx.Payload(res)
	}
}
