package gamemanagement

import (
	"strconv"
	"strings"

	"hyapp-admin-server/internal/integration/activityclient"
	"hyapp-admin-server/internal/integration/gameclient"
	"hyapp-admin-server/internal/integration/userclient"
	"hyapp-admin-server/internal/integration/walletclient"
	"hyapp-admin-server/internal/modules/shared"
	"hyapp-admin-server/internal/response"
	gamev1 "hyapp.local/api/proto/game/v1"

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

type Handler struct {
	game          gameclient.Client
	user          userclient.Client
	wallet        walletclient.Client
	activity      activityclient.Client
	audit         shared.OperationLogger
	robotProfiles RobotProfileSource
}

// Option 只开放模块初始化时的基础设施注入点，避免 handler 方法里散落环境配置读取。
type Option func(*Handler)

func New(game gameclient.Client, user userclient.Client, audit shared.OperationLogger, options ...Option) *Handler {
	h := &Handler{game: game, user: user, audit: audit}
	for _, option := range options {
		if option != nil {
			option(h)
		}
	}
	return h
}

// ListPlatforms 返回后台游戏平台筛选项和平台配置列表。
func (h *Handler) ListPlatforms(c *gin.Context) {
	resp, err := h.game.ListPlatforms(c.Request.Context(), &gamev1.ListPlatformsRequest{
		Meta:   requestMeta(c),
		Status: strings.TrimSpace(c.Query("status")),
	})
	if err != nil {
		response.ServerError(c, "获取游戏平台失败")
		return
	}
	items := make([]platformDTO, 0, len(resp.GetPlatforms()))
	for _, item := range resp.GetPlatforms() {
		items = append(items, platformFromProto(item))
	}
	response.OK(c, gin.H{"items": items, "serverTimeMs": resp.GetServerTimeMs()})
}

func (h *Handler) CreatePlatform(c *gin.Context) {
	h.upsertPlatform(c, "")
}

func (h *Handler) UpdatePlatform(c *gin.Context) {
	h.upsertPlatform(c, strings.TrimSpace(c.Param("platform_code")))
}

// upsertPlatform 创建或更新第三方游戏平台配置；callbackSecret 非空时才会轮换厂商密钥。
func (h *Handler) upsertPlatform(c *gin.Context, platformCode string) {
	var req platformRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "游戏平台参数不正确")
		return
	}
	resp, err := h.game.UpsertPlatform(c.Request.Context(), &gamev1.UpsertPlatformRequest{
		Meta:     requestMeta(c),
		Platform: req.toProto(platformCode),
	})
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	item := platformFromProto(resp.GetPlatform())
	h.auditLog(c, "upsert-game-platform", "game_platforms", item.PlatformCode, item.PlatformName)
	response.OK(c, item)
}

// ListCatalog 返回游戏目录；当前 game-service 使用 cursor 扩展点，后台先按 pageSize 截断。
func (h *Handler) ListCatalog(c *gin.Context) {
	pageSize := int32(parsePositiveInt(firstQuery(c, "pageSize", "page_size"), 50))
	resp, err := h.game.ListCatalog(c.Request.Context(), &gamev1.ListCatalogRequest{
		Meta:         requestMeta(c),
		PlatformCode: strings.TrimSpace(firstQuery(c, "platformCode", "platform_code")),
		Status:       strings.TrimSpace(c.Query("status")),
		PageSize:     pageSize,
		Cursor:       strings.TrimSpace(c.Query("cursor")),
	})
	if err != nil {
		response.ServerError(c, "获取游戏列表失败")
		return
	}
	items := make([]catalogDTO, 0, len(resp.GetGames()))
	for _, item := range resp.GetGames() {
		items = append(items, catalogFromProto(item))
	}
	response.OK(c, gin.H{
		"items":        items,
		"nextCursor":   resp.GetNextCursor(),
		"pageSize":     pageSize,
		"serverTimeMs": resp.GetServerTimeMs(),
	})
}

func (h *Handler) CreateCatalog(c *gin.Context) {
	h.upsertCatalog(c, "")
}

func (h *Handler) UpdateCatalog(c *gin.Context) {
	h.upsertCatalog(c, strings.TrimSpace(c.Param("game_id")))
}

// upsertCatalog 创建或更新内部 game_id 到 provider_game_id 的映射。
func (h *Handler) upsertCatalog(c *gin.Context, gameID string) {
	var req catalogRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "游戏参数不正确")
		return
	}
	resp, err := h.game.UpsertCatalog(c.Request.Context(), &gamev1.UpsertCatalogRequest{
		Meta: requestMeta(c),
		Game: req.toProto(gameID),
	})
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	item := catalogFromProto(resp.GetGame())
	h.auditLog(c, "upsert-game-catalog", "game_catalog", item.GameID, item.GameName)
	response.OK(c, item)
}

// SetGameStatus 只处理 active/maintenance/disabled 状态，不删除历史订单关联的游戏目录。
func (h *Handler) SetGameStatus(c *gin.Context) {
	gameID := strings.TrimSpace(c.Param("game_id"))
	if gameID == "" {
		response.BadRequest(c, "游戏 ID 参数不正确")
		return
	}
	var req statusRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "状态参数不正确")
		return
	}
	resp, err := h.game.SetGameStatus(c.Request.Context(), &gamev1.SetGameStatusRequest{
		Meta:   requestMeta(c),
		GameId: gameID,
		Status: strings.TrimSpace(req.Status),
	})
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	item := catalogFromProto(resp.GetGame())
	h.auditLog(c, "set-game-status", "game_catalog", item.GameID, item.Status)
	response.OK(c, item)
}

// DeleteCatalog 删除后台游戏目录记录，同时由 game-service 清理展示规则；历史订单和启动会话保留用于审计。
func (h *Handler) DeleteCatalog(c *gin.Context) {
	gameID := strings.TrimSpace(c.Param("game_id"))
	if gameID == "" {
		response.BadRequest(c, "游戏 ID 参数不正确")
		return
	}
	if _, err := h.game.DeleteCatalog(c.Request.Context(), &gamev1.DeleteCatalogRequest{
		Meta:   requestMeta(c),
		GameId: gameID,
	}); err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	h.auditLog(c, "delete-game-catalog", "game_catalog", gameID, "deleted")
	response.OK(c, gin.H{"gameId": gameID})
}

func (h *Handler) auditLog(c *gin.Context, action string, resource string, resourceID string, detail string) {
	shared.OperationLogWithResourceID(c, h.audit, action, resource, resourceID, "success", detail)
}

func parsePositiveInt(raw string, fallback int) int {
	value, err := strconv.Atoi(strings.TrimSpace(raw))
	if err != nil || value <= 0 {
		return fallback
	}
	if value > 200 {
		return 200
	}
	return value
}

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