package coinledger

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

	"hyapp-admin-server/internal/appctx"
	"hyapp-admin-server/internal/integration/walletclient"
	"hyapp-admin-server/internal/middleware"
	"hyapp-admin-server/internal/modules/shared"
	"hyapp-admin-server/internal/response"

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

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

func New(userDB *sql.DB, walletDB *sql.DB, adminDB *sql.DB, walletClient walletclient.Client, audit shared.OperationLogger) *Handler {
	return &Handler{service: NewService(userDB, walletDB, adminDB, walletClient), audit: audit}
}

func (h *Handler) ListCoinLedger(c *gin.Context) {
	query, ok := parseListQuery(c)
	if !ok {
		return
	}
	items, total, err := h.service.ListCoinLedger(c.Request.Context(), appctx.FromContext(c.Request.Context()), query)
	if err != nil {
		response.ServerError(c, "获取金币流水失败")
		return
	}
	response.OK(c, response.Page{Items: items, Page: query.Page, PageSize: query.PageSize, Total: total})
}

func (h *Handler) ListCoinSellerLedger(c *gin.Context) {
	query, ok := parseCoinSellerLedgerQuery(c)
	if !ok {
		return
	}
	items, total, err := h.service.ListCoinSellerLedger(c.Request.Context(), appctx.FromContext(c.Request.Context()), query)
	if err != nil {
		if errors.Is(err, errInvalidCoinSellerLedgerType) {
			response.BadRequest(c, "流水类型不正确")
			return
		}
		response.ServerError(c, "获取币商流水失败")
		return
	}
	response.OK(c, response.Page{Items: items, Page: query.Page, PageSize: query.PageSize, Total: total})
}

func (h *Handler) ExportCoinSellerLedger(c *gin.Context) {
	query, ok := parseCoinSellerLedgerQuery(c)
	if !ok {
		return
	}
	export, err := h.service.ExportCoinSellerLedger(c.Request.Context(), appctx.FromContext(c.Request.Context()), query)
	if err != nil {
		if errors.Is(err, errInvalidCoinSellerLedgerType) {
			response.BadRequest(c, "流水类型不正确")
			return
		}
		response.ServerError(c, "导出币商流水失败")
		return
	}

	shared.OperationLog(c, h.audit, "export-coin-seller-ledger", "wallet_entries", "success", fmt.Sprintf("%d entries", export.Count))
	c.Header("Content-Disposition", "attachment; filename="+export.FileName)
	c.Header("Content-Type", "text/csv; charset=utf-8")
	c.Writer.WriteHeader(200)
	_, _ = c.Writer.Write(export.Content)
}

func (h *Handler) ListCoinAdjustments(c *gin.Context) {
	query, ok := parseListQuery(c)
	if !ok {
		return
	}
	items, total, err := h.service.ListCoinAdjustments(c.Request.Context(), appctx.FromContext(c.Request.Context()), query)
	if err != nil {
		response.ServerError(c, "获取金币增减列表失败")
		return
	}
	response.OK(c, response.Page{Items: items, Page: query.Page, PageSize: query.PageSize, Total: total})
}

func (h *Handler) LookupCoinAdjustmentTarget(c *gin.Context) {
	user, err := h.service.LookupCoinAdjustmentTarget(c.Request.Context(), appctx.FromContext(c.Request.Context()), firstQuery(c, "user_id", "userId", "keyword"))
	if err != nil {
		if errors.Is(err, errCoinAdjustmentTargetNotFound) {
			response.BadRequest(c, "用户不存在")
			return
		}
		response.ServerError(c, "查询用户失败")
		return
	}
	response.OK(c, user)
}

func (h *Handler) CreateCoinAdjustment(c *gin.Context) {
	var req coinAdjustmentRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "金币增减参数不正确")
		return
	}
	result, err := h.service.CreateCoinAdjustment(
		c.Request.Context(),
		appctx.FromContext(c.Request.Context()),
		int64(shared.ActorFromContext(c).UserID),
		middleware.CurrentRequestID(c),
		req,
	)
	if err != nil {
		if errors.Is(err, errCoinAdjustmentTargetNotFound) {
			response.BadRequest(c, "用户不存在")
			return
		}
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLogWithResourceID(c, h.audit, "coin-adjustment-create", "wallet_entries", result.TransactionID, "success",
		fmt.Sprintf("target_user_id=%v amount=%d transaction_id=%s reason=%q remark=%q", req.TargetUserID, req.Amount, result.TransactionID, strings.TrimSpace(req.Reason), strings.TrimSpace(req.Remark)))
	response.Created(c, result)
}

func parseListQuery(c *gin.Context) (listQuery, bool) {
	options := shared.ListOptions(c)
	startAtMS, ok := optionalInt64(c, "start_at_ms", "startAtMs")
	if !ok {
		response.BadRequest(c, "开始时间不正确")
		return listQuery{}, false
	}
	endAtMS, ok := optionalInt64(c, "end_at_ms", "endAtMs")
	if !ok {
		response.BadRequest(c, "结束时间不正确")
		return listQuery{}, false
	}
	if startAtMS > 0 && endAtMS > 0 && startAtMS >= endAtMS {
		response.BadRequest(c, "时间区间不正确")
		return listQuery{}, false
	}
	return normalizeListQuery(listQuery{
		Page:        options.Page,
		PageSize:    options.PageSize,
		UserKeyword: strings.TrimSpace(firstQuery(c, "user_keyword", "userKeyword", "user_id", "userId", "keyword")),
		UserFilter:  shared.UserIdentityFilterFromQuery(c, ""),
		BizType:     firstQuery(c, "biz_type", "bizType"),
		StartAtMS:   startAtMS,
		EndAtMS:     endAtMS,
	}), true
}

func parseCoinSellerLedgerQuery(c *gin.Context) (coinSellerLedgerQuery, bool) {
	options := shared.ListOptions(c)
	// 行内抽屉传 seller_user_id 做精确锁定，二级页面不传该字段时才走 seller_keyword 的币商本人搜索；
	// 两个入口共用同一个查询结构，可以保证页面筛选和行内抽屉使用完全一致的流水类型、时间边界和分页语义。
	sellerUserID, ok := optionalInt64(c, "seller_user_id", "sellerUserId")
	if !ok {
		response.BadRequest(c, "币商 ID 不正确")
		return coinSellerLedgerQuery{}, false
	}
	startAtMS, ok := optionalInt64(c, "start_at_ms", "startAtMs")
	if !ok {
		response.BadRequest(c, "开始时间不正确")
		return coinSellerLedgerQuery{}, false
	}
	endAtMS, ok := optionalInt64(c, "end_at_ms", "endAtMs")
	if !ok {
		response.BadRequest(c, "结束时间不正确")
		return coinSellerLedgerQuery{}, false
	}
	if startAtMS > 0 && endAtMS > 0 && startAtMS >= endAtMS {
		response.BadRequest(c, "时间区间不正确")
		return coinSellerLedgerQuery{}, false
	}

	// 列表时间统一保持 [start_at_ms, end_at_ms)，开始毫秒包含、结束毫秒不包含，避免相邻筛选区间重复展示同一条分录；
	// 非法流水类型在入口层直接拒绝，避免 SQL 拼出无意义类型条件，也让调用方尽早拿到明确的 400 错误。
	query := normalizeCoinSellerLedgerQuery(coinSellerLedgerQuery{
		Page:          options.Page,
		PageSize:      options.PageSize,
		SellerUserID:  sellerUserID,
		SellerKeyword: firstQuery(c, "seller_keyword", "sellerKeyword", "keyword"),
		SellerFilter: shared.UserIdentityFilter{
			DisplayUserID: strings.TrimSpace(firstQuery(c, "seller_display_user_id", "sellerDisplayUserId")),
			UserID:        strings.TrimSpace(firstQuery(c, "seller_filter_user_id", "sellerFilterUserId")),
			Username:      strings.TrimSpace(firstQuery(c, "seller_username", "sellerUsername")),
		},
		LedgerType: firstQuery(c, "ledger_type", "ledgerType"),
		StartAtMS:  startAtMS,
		EndAtMS:    endAtMS,
	})
	if _, err := coinSellerLedgerBizTypes(query.LedgerType); err != nil {
		response.BadRequest(c, "流水类型不正确")
		return coinSellerLedgerQuery{}, false
	}
	return query, true
}

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)
	if err != nil || parsed < 0 {
		return 0, false
	}
	return parsed, true
}

func firstQuery(c *gin.Context, keys ...string) string {
	for _, key := range keys {
		if value := c.Query(key); value != "" {
			return value
		}
	}
	return ""
}
