package cpweeklyrank

import (
	"strconv"
	"strings"
	"time"

	"hyapp-admin-server/internal/appctx"
	"hyapp-admin-server/internal/integration/activityclient"
	"hyapp-admin-server/internal/middleware"
	"hyapp-admin-server/internal/modules/shared"
	"hyapp-admin-server/internal/response"
	activityv1 "hyapp.local/api/proto/activity/v1"

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

type Handler struct {
	activity activityclient.Client
	audit    shared.OperationLogger
}

func New(activity activityclient.Client, audit shared.OperationLogger) *Handler {
	return &Handler{activity: activity, audit: audit}
}

type configRequest struct {
	Enabled  bool        `json:"enabled"`
	TopCount int32       `json:"top_count"`
	Rewards  []rewardDTO `json:"rewards"`
}

type configDTO struct {
	AppCode          string      `json:"app_code"`
	ActivityCode     string      `json:"activity_code"`
	Enabled          bool        `json:"enabled"`
	RelationType     string      `json:"relation_type"`
	TopCount         int32       `json:"top_count"`
	Rewards          []rewardDTO `json:"rewards"`
	UpdatedByAdminID int64       `json:"updated_by_admin_id,string"`
	CreatedAtMS      int64       `json:"created_at_ms"`
	UpdatedAtMS      int64       `json:"updated_at_ms"`
}

type rewardDTO struct {
	RankNo          int32 `json:"rank_no"`
	ResourceGroupID int64 `json:"resource_group_id"`
}

type settlementDTO struct {
	SettlementID    string `json:"settlement_id"`
	PeriodStartMS   int64  `json:"period_start_ms"`
	PeriodEndMS     int64  `json:"period_end_ms"`
	RankNo          int32  `json:"rank_no"`
	RelationshipID  string `json:"relationship_id"`
	UserID          int64  `json:"user_id,string"`
	Score           int64  `json:"score"`
	ResourceGroupID int64  `json:"resource_group_id"`
	WalletCommandID string `json:"wallet_command_id"`
	WalletGrantID   string `json:"wallet_grant_id"`
	Status          string `json:"status"`
	FailureReason   string `json:"failure_reason"`
	AttemptCount    int32  `json:"attempt_count"`
	CreatedAtMS     int64  `json:"created_at_ms"`
	UpdatedAtMS     int64  `json:"updated_at_ms"`
}

func (h *Handler) GetConfig(c *gin.Context) {
	resp, err := h.activity.GetCPWeeklyRankConfig(c.Request.Context(), &activityv1.GetCPWeeklyRankConfigRequest{Meta: h.meta(c)})
	if err != nil {
		response.ServerError(c, "获取CP排行活动配置失败")
		return
	}
	response.OK(c, configFromProto(resp.GetConfig()))
}

func (h *Handler) UpdateConfig(c *gin.Context) {
	var req configRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "CP排行活动配置参数不正确")
		return
	}
	resp, err := h.activity.UpdateCPWeeklyRankConfig(c.Request.Context(), &activityv1.UpdateCPWeeklyRankConfigRequest{
		Meta:            h.meta(c),
		Config:          req.toProto(),
		OperatorAdminId: int64(middleware.CurrentUserID(c)),
	})
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	item := configFromProto(resp.GetConfig())
	shared.OperationLogWithResourceID(c, h.audit, "update-cp-weekly-rank-config", "cp_weekly_rank_configs", item.AppCode, "success", "")
	response.OK(c, item)
}

func (h *Handler) ListSettlements(c *gin.Context) {
	periodStartMS := parseInt64Query(c, "period_start_ms")
	periodEndMS := parseInt64Query(c, "period_end_ms")
	resp, err := h.activity.ListCPWeeklyRankSettlements(c.Request.Context(), &activityv1.ListCPWeeklyRankSettlementsRequest{
		Meta:          h.meta(c),
		PeriodStartMs: periodStartMS,
		PeriodEndMs:   periodEndMS,
	})
	if err != nil {
		response.ServerError(c, "获取CP排行活动发奖记录失败")
		return
	}
	items := make([]settlementDTO, 0, len(resp.GetSettlements()))
	for _, settlement := range resp.GetSettlements() {
		items = append(items, settlementFromProto(settlement))
	}
	response.OK(c, gin.H{"items": items, "total": len(items), "period_start_ms": periodStartMS, "period_end_ms": periodEndMS})
}

func (h *Handler) meta(c *gin.Context) *activityv1.RequestMeta {
	return &activityv1.RequestMeta{
		RequestId: middleware.CurrentRequestID(c),
		Caller:    "admin-server",
		AppCode:   appctx.FromContext(c.Request.Context()),
		SentAtMs:  time.Now().UTC().UnixMilli(),
	}
}

func (r configRequest) toProto() *activityv1.CPWeeklyRankConfig {
	topCount := r.TopCount
	if topCount <= 0 {
		topCount = 3
	}
	rewards := make([]*activityv1.CPWeeklyRankReward, 0, len(r.Rewards))
	for _, reward := range r.Rewards {
		// activity-service 会按 top_count 归一化和校验；admin-server 只做传输层适配，
		// 保留原 rank/resource_group 组合，避免两个服务出现不同的配置裁决口径。
		rewards = append(rewards, &activityv1.CPWeeklyRankReward{RankNo: reward.RankNo, ResourceGroupId: reward.ResourceGroupID})
	}
	return &activityv1.CPWeeklyRankConfig{
		ActivityCode: "cp_weekly_rank",
		Enabled:      r.Enabled,
		RelationType: "cp",
		TopCount:     topCount,
		Rewards:      rewards,
	}
}

func configFromProto(config *activityv1.CPWeeklyRankConfig) configDTO {
	if config == nil {
		return configDTO{ActivityCode: "cp_weekly_rank", Enabled: true, RelationType: "cp", TopCount: 3, Rewards: []rewardDTO{}}
	}
	rewards := make([]rewardDTO, 0, len(config.GetRewards()))
	for _, reward := range config.GetRewards() {
		rewards = append(rewards, rewardDTO{RankNo: reward.GetRankNo(), ResourceGroupID: reward.GetResourceGroupId()})
	}
	return configDTO{
		AppCode:          config.GetAppCode(),
		ActivityCode:     config.GetActivityCode(),
		Enabled:          config.GetEnabled(),
		RelationType:     config.GetRelationType(),
		TopCount:         config.GetTopCount(),
		Rewards:          rewards,
		UpdatedByAdminID: config.GetUpdatedByAdminId(),
		CreatedAtMS:      config.GetCreatedAtMs(),
		UpdatedAtMS:      config.GetUpdatedAtMs(),
	}
}

func settlementFromProto(settlement *activityv1.CPWeeklyRankSettlement) settlementDTO {
	if settlement == nil {
		return settlementDTO{}
	}
	return settlementDTO{
		SettlementID:    settlement.GetSettlementId(),
		PeriodStartMS:   settlement.GetPeriodStartMs(),
		PeriodEndMS:     settlement.GetPeriodEndMs(),
		RankNo:          settlement.GetRankNo(),
		RelationshipID:  settlement.GetRelationshipId(),
		UserID:          settlement.GetUserId(),
		Score:           settlement.GetScore(),
		ResourceGroupID: settlement.GetResourceGroupId(),
		WalletCommandID: settlement.GetWalletCommandId(),
		WalletGrantID:   settlement.GetWalletGrantId(),
		Status:          settlement.GetStatus(),
		FailureReason:   settlement.GetFailureReason(),
		AttemptCount:    settlement.GetAttemptCount(),
		CreatedAtMS:     settlement.GetCreatedAtMs(),
		UpdatedAtMS:     settlement.GetUpdatedAtMs(),
	}
}

func parseInt64Query(c *gin.Context, key string) int64 {
	value, _ := strconv.ParseInt(strings.TrimSpace(c.Query(key)), 10, 64)
	return value
}
