package teamsalarysettlement

import (
	"database/sql"
	"fmt"
	"strconv"
	"strings"

	"hyapp-admin-server/internal/appctx"
	"hyapp-admin-server/internal/modules/shared"
	"hyapp-admin-server/internal/response"

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

type Handler struct {
	audit   shared.OperationLogger
	service *Service
}

// New 只做 HTTP 层组装，具体工资口径全部下沉到 Service，避免 handler 里复制账务逻辑。
func New(adminDB *sql.DB, walletDB *sql.DB, userDB *sql.DB, audit shared.OperationLogger) *Handler {
	return &Handler{audit: audit, service: NewService(adminDB, walletDB, userDB)}
}

// Service 暴露给自动任务 runner 复用同一个结算引擎，保证手动和自动结算走同一套规则。
func (h *Handler) Service() *Service {
	if h == nil {
		return nil
	}
	return h.service
}

// ListPending 返回当前筛选条件下可产生正向工资差值的 BD/Admin 用户。
func (h *Handler) ListPending(c *gin.Context) {
	req, ok := parsePendingQuery(c)
	if !ok {
		return
	}
	items, total, err := h.service.ListPending(c.Request.Context(), appctx.FromContext(c.Request.Context()), req)
	if err != nil {
		response.ServerError(c, "获取待结算工资失败")
		return
	}
	response.OK(c, response.Page{Items: items, Page: req.Page, PageSize: req.PageSize, Total: total})
}

// ListRecords 返回已经生成 settlement_id 的 BD/Admin 结算记录，用于后台查账。
func (h *Handler) ListRecords(c *gin.Context) {
	req, ok := parseRecordQuery(c)
	if !ok {
		return
	}
	items, total, err := h.service.ListRecords(c.Request.Context(), appctx.FromContext(c.Request.Context()), req)
	if err != nil {
		response.ServerError(c, "获取 BD/Admin 结算记录失败")
		return
	}
	response.OK(c, response.Page{Items: items, Page: req.Page, PageSize: req.PageSize, Total: total})
}

// Settle 执行后台批量手动结算；前端传入 user_ids 后，Service 会再次按候选白名单过滤。
func (h *Handler) Settle(c *gin.Context) {
	var req settleRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "结算参数不正确")
		return
	}
	req.PolicyType = normalizePolicyType(req.PolicyType)
	req.TriggerMode = normalizeTriggerMode(req.TriggerMode)
	req.CycleKey = strings.TrimSpace(req.CycleKey)
	req.CountryCode = strings.ToUpper(strings.TrimSpace(req.CountryCode))
	if req.PolicyType == "" {
		response.BadRequest(c, "工资类型不正确")
		return
	}
	if req.TriggerMode == "" {
		response.BadRequest(c, "触发方式不正确")
		return
	}
	result, err := h.service.Settle(c.Request.Context(), appctx.FromContext(c.Request.Context()), int64(shared.ActorFromContext(c).UserID), req)
	if err != nil {
		response.ServerError(c, "工资结算失败")
		return
	}
	shared.OperationLog(c, h.audit, "settle-team-salary", "team_salary_settlement_records", "success", fmt.Sprintf("policy_type=%s cycle_key=%s success=%d skipped=%d failed=%d", result.PolicyType, result.CycleKey, result.SuccessCount, result.SkippedCount, result.FailureCount))
	response.OK(c, result)
}

// parsePendingQuery 兼容 snake_case/camelCase 查询参数，便于前端直接传 API DTO 或内部模型字段。
func parsePendingQuery(c *gin.Context) (pendingQuery, bool) {
	options := shared.ListOptions(c)
	req := pendingQuery{
		Page:        options.Page,
		PageSize:    options.PageSize,
		PolicyType:  normalizePolicyType(firstQuery(c, "policy_type", "policyType")),
		TriggerMode: normalizeTriggerMode(firstQuery(c, "trigger_mode", "triggerMode")),
		CycleKey:    strings.TrimSpace(firstQuery(c, "cycle_key", "cycleKey")),
		CountryCode: strings.ToUpper(strings.TrimSpace(firstQuery(c, "country_code", "countryCode"))),
		UserFilter:  shared.UserIdentityFilterFromQuery(c, ""),
	}
	var ok bool
	if req.RegionID, ok = optionalInt64(c, "region_id", "regionId"); !ok {
		response.BadRequest(c, "区域 ID 不正确")
		return pendingQuery{}, false
	}
	if req.CountryID, ok = optionalInt64(c, "country_id", "countryId"); !ok {
		response.BadRequest(c, "国家 ID 不正确")
		return pendingQuery{}, false
	}
	if req.UserID, ok = optionalInt64(c, "user_id", "userId"); !ok {
		response.BadRequest(c, "用户 ID 不正确")
		return pendingQuery{}, false
	}
	if raw := strings.TrimSpace(firstQuery(c, "policy_type", "policyType")); raw != "" && req.PolicyType == "" {
		response.BadRequest(c, "工资类型不正确")
		return pendingQuery{}, false
	}
	if raw := strings.TrimSpace(firstQuery(c, "trigger_mode", "triggerMode")); raw != "" && req.TriggerMode == "" {
		response.BadRequest(c, "触发方式不正确")
		return pendingQuery{}, false
	}
	return normalizePendingQuery(req), true
}

// parseRecordQuery 统一记录列表的分页、枚举和时间区间校验，避免把非法筛选传到 SQL 组装层。
func parseRecordQuery(c *gin.Context) (recordQuery, bool) {
	options := shared.ListOptions(c)
	req := recordQuery{
		Page:        options.Page,
		PageSize:    options.PageSize,
		PolicyType:  normalizePolicyType(firstQuery(c, "policy_type", "policyType")),
		TriggerMode: normalizeTriggerMode(firstQuery(c, "trigger_mode", "triggerMode")),
		CycleKey:    strings.TrimSpace(firstQuery(c, "cycle_key", "cycleKey")),
		Status:      normalizeStatus(firstQuery(c, "status")),
		CountryCode: strings.ToUpper(strings.TrimSpace(firstQuery(c, "country_code", "countryCode"))),
		UserFilter:  shared.UserIdentityFilterFromQuery(c, ""),
	}
	var ok bool
	if req.RegionID, ok = optionalInt64(c, "region_id", "regionId"); !ok {
		response.BadRequest(c, "区域 ID 不正确")
		return recordQuery{}, false
	}
	if req.CountryID, ok = optionalInt64(c, "country_id", "countryId"); !ok {
		response.BadRequest(c, "国家 ID 不正确")
		return recordQuery{}, false
	}
	if req.UserID, ok = optionalInt64(c, "user_id", "userId"); !ok {
		response.BadRequest(c, "用户 ID 不正确")
		return recordQuery{}, false
	}
	if req.PolicyID, ok = optionalUint64(c, "policy_id", "policyId"); !ok {
		response.BadRequest(c, "政策 ID 不正确")
		return recordQuery{}, false
	}
	if req.StartAtMS, ok = optionalInt64(c, "start_at_ms", "startAtMs"); !ok {
		response.BadRequest(c, "开始时间不正确")
		return recordQuery{}, false
	}
	if req.EndAtMS, ok = optionalInt64(c, "end_at_ms", "endAtMs"); !ok {
		response.BadRequest(c, "结束时间不正确")
		return recordQuery{}, false
	}
	if req.StartAtMS > 0 && req.EndAtMS > 0 && req.StartAtMS >= req.EndAtMS {
		response.BadRequest(c, "时间区间不正确")
		return recordQuery{}, false
	}
	if raw := strings.TrimSpace(firstQuery(c, "policy_type", "policyType")); raw != "" && req.PolicyType == "" {
		response.BadRequest(c, "工资类型不正确")
		return recordQuery{}, false
	}
	if raw := strings.TrimSpace(firstQuery(c, "trigger_mode", "triggerMode")); raw != "" && req.TriggerMode == "" {
		response.BadRequest(c, "触发方式不正确")
		return recordQuery{}, false
	}
	if raw := strings.TrimSpace(firstQuery(c, "status")); raw != "" && strings.ToLower(raw) != "all" && req.Status == "" {
		response.BadRequest(c, "状态不正确")
		return recordQuery{}, false
	}
	return normalizeRecordQuery(req), true
}

// optionalInt64 解析可选正整数查询参数；空值代表不筛选。
func optionalInt64(c *gin.Context, keys ...string) (int64, bool) {
	value := strings.TrimSpace(firstQuery(c, keys...))
	if value == "" {
		return 0, true
	}
	parsed, err := strconv.ParseInt(value, 10, 64)
	return parsed, err == nil && parsed >= 0
}

// optionalUint64 解析可选无符号整数，当前用于 policy_id。
func optionalUint64(c *gin.Context, keys ...string) (uint64, bool) {
	value := strings.TrimSpace(firstQuery(c, keys...))
	if value == "" {
		return 0, true
	}
	parsed, err := strconv.ParseUint(value, 10, 64)
	return parsed, err == nil
}

// firstQuery 按优先级读取同义查询参数，避免每个字段重复写 snake/camel fallback。
func firstQuery(c *gin.Context, keys ...string) string {
	for _, key := range keys {
		if value := strings.TrimSpace(c.Query(key)); value != "" {
			return value
		}
	}
	return ""
}
