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"
	"bindbox-game/internal/service/user"
)

type listUsersRequest struct {
	Page       int    `form:"page"`
	PageSize   int    `form:"page_size"`
	Nickname   string `form:"nickname"`
	InviteCode string `form:"inviteCode"`
	StartDate  string `form:"startDate"`
	EndDate    string `form:"endDate"`
}
type listUsersResponse struct {
	Page     int             `json:"page"`
	PageSize int             `json:"page_size"`
	Total    int64           `json:"total"`
	List     []adminUserItem `json:"list"`
}

// ListAppUsers 管理端用户列表
// @Summary 管理端用户列表
// @Description 查看APP端用户分页列表
// @Tags 管理端.用户
// @Accept json
// @Produce json
// @Param page query int true "页码" default(1)
// @Param page_size query int true "每页数量，最多100" default(20)
// @Param nickname query string false "用户昵称"
// @Param inviteCode query string false "邀请码"
// @Param startDate query string false "开始日期(YYYY-MM-DD)"
// @Param endDate query string false "结束日期(YYYY-MM-DD)"
// @Success 200 {object} listUsersResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/users [get]
// @Security LoginVerifyToken
func (h *handler) ListAppUsers() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(listUsersRequest)
		rsp := new(listUsersResponse)
		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
		}
		if req.PageSize > 100 {
			req.PageSize = 100
		}
		q := h.readDB.Users.WithContext(ctx.RequestContext()).ReadDB()
		
		// 应用搜索条件
		if req.Nickname != "" {
			q = q.Where(h.readDB.Users.Nickname.Like("%" + req.Nickname + "%"))
		}
		if req.InviteCode != "" {
			q = q.Where(h.readDB.Users.InviteCode.Eq(req.InviteCode))
		}
		if req.StartDate != "" {
			if startTime, err := time.Parse("2006-01-02", req.StartDate); err == nil {
				q = q.Where(h.readDB.Users.CreatedAt.Gte(startTime))
			}
		}
		if req.EndDate != "" {
			if endTime, err := time.Parse("2006-01-02", req.EndDate); err == nil {
				// 设置结束时间为当天的23:59:59
				endTime = endTime.Add(24 * time.Hour).Add(-time.Second)
				q = q.Where(h.readDB.Users.CreatedAt.Lte(endTime))
			}
		}
		
		total, err := q.Count()
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, 20101, err.Error()))
			return
		}
		rows, err := q.Order(h.readDB.Users.ID.Desc()).Offset((req.Page - 1) * req.PageSize).Limit(req.PageSize).Find()
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, 20102, err.Error()))
			return
		}
		rsp.Page = req.Page
		rsp.PageSize = req.PageSize
		rsp.Total = total
		rsp.List = make([]adminUserItem, len(rows))
		for i, v := range rows {
			rsp.List[i] = adminUserItem{ID: v.ID, Nickname: v.Nickname, Avatar: v.Avatar, InviteCode: v.InviteCode, InviterID: v.InviterID, CreatedAt: v.CreatedAt.Format("2006-01-02 15:04:05")}
		}
		ctx.Payload(rsp)
	}
}

type listInvitesRequest struct {
	Page     int `form:"page"`
	PageSize int `form:"page_size"`
}
type listInvitesResponse struct {
	Page     int             `json:"page"`
	PageSize int             `json:"page_size"`
	Total    int64           `json:"total"`
	List     []adminUserItem `json:"list"`
}

// ListUserInvites 查看用户邀请列表
// @Summary 查看用户邀请列表
// @Description 查看指定用户邀请的用户列表
// @Tags 管理端.用户
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Param page query int true "页码" default(1)
// @Param page_size query int true "每页数量，最多100" default(20)
// @Success 200 {object} listInvitesResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/users/{user_id}/invites [get]
// @Security LoginVerifyToken
func (h *handler) ListUserInvites() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(listInvitesRequest)
		rsp := new(listInvitesResponse)
		if err := ctx.ShouldBindForm(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}
		userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
			return
		}
		rows, total, err := h.user.ListInvites(ctx.RequestContext(), userID, req.Page, req.PageSize)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, 20103, err.Error()))
			return
		}
		rsp.Page = req.Page
		rsp.PageSize = req.PageSize
		rsp.Total = total
		rsp.List = make([]adminUserItem, len(rows))
		for i, v := range rows {
			rsp.List[i] = adminUserItem{ID: v.ID, Nickname: v.Nickname, Avatar: v.Avatar, InviteCode: v.InviteCode, InviterID: v.InviterID, CreatedAt: v.CreatedAt.Format("2006-01-02 15:04:05")}
		}
		ctx.Payload(rsp)
	}
}

type listOrdersRequest struct {
	Page     int `form:"page"`
	PageSize int `form:"page_size"`
}
type listOrdersResponse struct {
    Page     int                    `json:"page"`
    PageSize int                    `json:"page_size"`
    Total    int64                  `json:"total"`
    List     []*user.OrderWithItems `json:"list"`
}

type listInventoryRequest struct {
    Page     int `form:"page"`
    PageSize int `form:"page_size"`
}
type listInventoryResponse struct {
    Page     int                              `json:"page"`
    PageSize int                              `json:"page_size"`
    Total    int64                            `json:"total"`
    List     []*user.InventoryWithProduct     `json:"list"`
}

// ListUserOrders 查看用户订单列表
// @Summary 查看用户订单列表
// @Description 查看指定用户的订单记录
// @Tags 管理端.用户
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Param page query int true "页码" default(1)
// @Param page_size query int true "每页数量，最多100" default(20)
// @Success 200 {object} listOrdersResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/users/{user_id}/orders [get]
// @Security LoginVerifyToken
func (h *handler) ListUserOrders() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(listOrdersRequest)
		rsp := new(listOrdersResponse)
		if err := ctx.ShouldBindForm(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}
		userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
			return
		}
		items, total, err := h.user.ListOrdersWithItems(ctx.RequestContext(), userID, req.Page, req.PageSize)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, 20104, err.Error()))
			return
		}
		rsp.Page = req.Page
		rsp.PageSize = req.PageSize
		rsp.Total = total
		rsp.List = items
		ctx.Payload(rsp)
	}
}

// 查看用户资产列表
// @Summary 查看用户资产列表
// @Description 查看指定用户的资产记录
// @Tags 管理端.用户
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Param page query int true "页码" default(1)
// @Param page_size query int true "每页数量，最多100" default(20)
// @Success 200 {object} listInventoryResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/users/{user_id}/inventory [get]
// @Security LoginVerifyToken
func (h *handler) ListUserInventory() core.HandlerFunc {
    return func(ctx core.Context) {
        req := new(listInventoryRequest)
        rsp := new(listInventoryResponse)
        if err := ctx.ShouldBindForm(req); err != nil {
            ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
            return
        }
        userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
        if err != nil {
            ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
            return
        }
        rows, total, err := h.user.ListInventoryWithProduct(ctx.RequestContext(), userID, req.Page, req.PageSize)
        if err != nil {
            ctx.AbortWithError(core.Error(http.StatusBadRequest, 20105, err.Error()))
            return
        }
        rsp.Page = req.Page
        rsp.PageSize = req.PageSize
        rsp.Total = total
        rsp.List = rows
        ctx.Payload(rsp)
    }
}

type listUserItemCardsRequest struct {
    Page     int `form:"page"`
    PageSize int `form:"page_size"`
}

type listUserItemCardsResponse struct {
    Page     int                              `json:"page"`
    PageSize int                              `json:"page_size"`
    Total    int64                            `json:"total"`
    List     []*user.ItemCardWithTemplate     `json:"list"`
}

// ListUserItemCards 查看用户道具卡列表
// @Summary 查看用户道具卡列表
// @Description 查看指定用户的道具卡持有记录
// @Tags 管理端.用户
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Param page query int true "页码" default(1)
// @Param page_size query int true "每页数量，最多100" default(20)
// @Success 200 {object} listUserItemCardsResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/users/{user_id}/item_cards [get]
// @Security LoginVerifyToken
func (h *handler) ListUserItemCards() core.HandlerFunc {
    return func(ctx core.Context) {
        req := new(listUserItemCardsRequest)
        rsp := new(listUserItemCardsResponse)
        if err := ctx.ShouldBindForm(req); err != nil {
            ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
            return
        }
        userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
        if err != nil {
            ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
            return
        }
        items, total, err := h.user.ListUserItemCardsWithTemplate(ctx.RequestContext(), userID, req.Page, req.PageSize)
        if err != nil {
            ctx.AbortWithError(core.Error(http.StatusBadRequest, 20106, err.Error()))
            return
        }
        rsp.Page = req.Page
        rsp.PageSize = req.PageSize
        rsp.Total = total
        rsp.List = items
        ctx.Payload(rsp)
    }
}

type listCouponsRequest struct {
	Page     int `form:"page"`
	PageSize int `form:"page_size"`
}
type adminUserCouponItem struct {
    ID            int64  `json:"id"`
    CouponID      int64  `json:"coupon_id"`
    Status        int32  `json:"status"`
    UsedOrderID   int64  `json:"used_order_id"`
    UsedAt        string `json:"used_at"`
    ValidStart    string `json:"valid_start"`
    ValidEnd      string `json:"valid_end"`
    Name          string `json:"name"`
    ScopeType     int32  `json:"scope_type"`
    DiscountType  int32  `json:"discount_type"`
    DiscountValue int64  `json:"discount_value"`
    MinSpend      int64  `json:"min_spend"`
}

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

// ListUserCoupons 查看用户优惠券列表
// @Summary 查看用户优惠券列表
// @Description 查看指定用户持有的优惠券列表
// @Tags 管理端.用户
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Param page query int true "页码" default(1)
// @Param page_size query int true "每页数量，最多100" default(20)
// @Success 200 {object} listCouponsResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/users/{user_id}/coupons [get]
// @Security LoginVerifyToken
func (h *handler) ListUserCoupons() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(listCouponsRequest)
		rsp := new(listCouponsResponse)
		if err := ctx.ShouldBindForm(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}
		userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
			return
		}
        // 统计总数
        base := h.readDB.UserCoupons.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.UserCoupons.UserID.Eq(userID))
        total, err := base.Count()
        if err != nil {
            ctx.AbortWithError(core.Error(http.StatusBadRequest, 20105, err.Error()))
            return
        }
        // 联表查询 system_coupons 获取优惠券模板信息
        type row struct {
            ID            int64
            CouponID      int64
            Status        int32
            UsedOrderID   int64
            UsedAt        *string
            ValidStart    *string
            ValidEnd      *string
            Name          string
            ScopeType     int32
            DiscountType  int32
            DiscountValue int64
            MinSpend      int64
        }
        q := h.readDB.UserCoupons.WithContext(ctx.RequestContext()).ReadDB().
            LeftJoin(h.readDB.SystemCoupons, h.readDB.SystemCoupons.ID.EqCol(h.readDB.UserCoupons.CouponID)).
            Select(
                h.readDB.UserCoupons.ID, h.readDB.UserCoupons.CouponID, h.readDB.UserCoupons.Status,
                h.readDB.UserCoupons.UsedOrderID, h.readDB.UserCoupons.UsedAt, h.readDB.UserCoupons.ValidStart, h.readDB.UserCoupons.ValidEnd,
                h.readDB.SystemCoupons.Name, h.readDB.SystemCoupons.ScopeType, h.readDB.SystemCoupons.DiscountType,
                h.readDB.SystemCoupons.DiscountValue, h.readDB.SystemCoupons.MinSpend,
            ).
            Where(h.readDB.UserCoupons.UserID.Eq(userID)).
            Order(h.readDB.UserCoupons.ID.Desc()).
            Limit(req.PageSize).Offset((req.Page-1)*req.PageSize)

        var rows []row
        if err := q.Scan(&rows); err != nil {
            ctx.AbortWithError(core.Error(http.StatusBadRequest, 20105, err.Error()))
            return
        }

        rsp.Page = req.Page
        rsp.PageSize = req.PageSize
        rsp.Total = total
        rsp.List = make([]adminUserCouponItem, len(rows))
        for i, v := range rows {
            rsp.List[i] = adminUserCouponItem{
                ID: v.ID,
                CouponID: v.CouponID,
                Status: v.Status,
                UsedOrderID: v.UsedOrderID,
                UsedAt: nullableToString(v.UsedAt),
                ValidStart: nullableToString(v.ValidStart),
                ValidEnd: nullableToString(v.ValidEnd),
                Name: v.Name,
                ScopeType: v.ScopeType,
                DiscountType: v.DiscountType,
                DiscountValue: v.DiscountValue,
                MinSpend: v.MinSpend,
            }
        }
        ctx.Payload(rsp)
    }
}

func nullableToString(s *string) string {
    if s == nil {
        return ""
    }
    return *s
}

type listPointsRequest struct {
	Page     int `form:"page"`
	PageSize int `form:"page_size"`
}
type listPointsResponse struct {
	Page     int                       `json:"page"`
	PageSize int                       `json:"page_size"`
	Total    int64                     `json:"total"`
	List     []*model.UserPointsLedger `json:"list"`
}

// ListUserPoints 查看用户积分记录
// @Summary 查看用户积分记录
// @Description 查看指定用户的积分流水记录
// @Tags 管理端.用户
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Param page query int true "页码" default(1)
// @Param page_size query int true "每页数量，最多100" default(20)
// @Success 200 {object} listPointsResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/users/{user_id}/points [get]
// @Security LoginVerifyToken
func (h *handler) ListUserPoints() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(listPointsRequest)
		rsp := new(listPointsResponse)
		if err := ctx.ShouldBindForm(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}
		userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
			return
		}
		items, total, err := h.user.ListPointsLedger(ctx.RequestContext(), userID, req.Page, req.PageSize)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, 20106, err.Error()))
			return
		}
		rsp.Page = req.Page
		rsp.PageSize = req.PageSize
		rsp.Total = total
		rsp.List = items
		ctx.Payload(rsp)
	}
}

type pointsBalanceResponse struct {
	Balance int64 `json:"balance"`
}

type adminUserItem struct {
	ID         int64  `json:"id"`
	Nickname   string `json:"nickname"`
	Avatar     string `json:"avatar"`
	InviteCode string `json:"invite_code"`
	InviterID  int64  `json:"inviter_id"`
	CreatedAt  string `json:"created_at"`
}

// GetUserPointsBalance 查看用户积分余额
// @Summary 查看用户积分余额
// @Description 查看指定用户当前积分余额（过滤过期）
// @Tags 管理端.用户
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Success 200 {object} pointsBalanceResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/users/{user_id}/points/balance [get]
// @Security LoginVerifyToken
func (h *handler) GetUserPointsBalance() core.HandlerFunc {
	return func(ctx core.Context) {
		rsp := new(pointsBalanceResponse)
		userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
			return
		}
		total, err := h.user.GetPointsBalance(ctx.RequestContext(), userID)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, 20107, err.Error()))
			return
		}
		rsp.Balance = total
		ctx.Payload(rsp)
	}
}

type addPointsRequest struct {
	Points    int64  `json:"points" binding:"required"`
	Kind      string `json:"kind"`
	Remark    string `json:"remark"`
	ValidDays *int   `json:"valid_days"`
}
type addPointsResponse struct {
	Success bool `json:"success"`
}

// AddUserPoints 给用户添加积分
// @Summary 给用户添加积分
// @Description 管理端为指定用户发放积分，支持设置有效期
// @Tags 管理端.用户
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Param RequestBody body addPointsRequest true "请求参数"
// @Success 200 {object} addPointsResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/users/{user_id}/points/add [post]
// @Security LoginVerifyToken
func (h *handler) AddUserPoints() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(addPointsRequest)
		rsp := new(addPointsResponse)
		if err := ctx.ShouldBindJSON(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}
		userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
			return
		}
		var validStart *time.Time
		var validEnd *time.Time
		now := time.Now()
		validStart = &now
		if req.ValidDays != nil && *req.ValidDays > 0 {
			ve := now.Add(time.Duration(*req.ValidDays) * 24 * time.Hour)
			validEnd = &ve
		}
		if err := h.user.AddPoints(ctx.RequestContext(), userID, req.Points, req.Kind, req.Remark, validStart, validEnd); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, 20108, err.Error()))
			return
		}
		rsp.Success = true
		ctx.Payload(rsp)
	}
}

type addCouponRequest struct {
	CouponID int64 `json:"coupon_id" binding:"required"`
}
type addCouponResponse struct {
	Success bool `json:"success"`
}

// AddUserCoupon 给用户添加优惠券
// @Summary 给用户添加优惠券
// @Description 管理端为指定用户发放优惠券
// @Tags 管理端.用户
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Param RequestBody body addCouponRequest true "请求参数"
// @Success 200 {object} addCouponResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/users/{user_id}/coupons/add [post]
// @Security LoginVerifyToken
func (h *handler) AddUserCoupon() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(addCouponRequest)
		rsp := new(addCouponResponse)
		if err := ctx.ShouldBindJSON(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}
		userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
			return
		}
		if err := h.user.AddCoupon(ctx.RequestContext(), userID, req.CouponID); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, 20109, err.Error()))
			return
		}
		rsp.Success = true
		ctx.Payload(rsp)
	}
}
