package vipconfig

import (
	"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"
	walletv1 "hyapp.local/api/proto/wallet/v1"

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

type Handler struct {
	wallet walletclient.Client
	audit  shared.OperationLogger
}

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

type configRequest struct {
	Levels []vipLevelDTO `json:"levels"`
}

type grantVipRequest struct {
	CommandID    string `json:"commandId"`
	TargetUserID any    `json:"targetUserId"`
	Level        int32  `json:"level"`
	Reason       string `json:"reason"`
}

type configDTO struct {
	Levels       []vipLevelDTO `json:"levels"`
	ServerTimeMS int64         `json:"serverTimeMs"`
}

type grantVipDTO struct {
	TransactionID string             `json:"transactionId"`
	VIP           userVipDTO         `json:"vip"`
	RewardItems   []vipRewardItemDTO `json:"rewardItems"`
	ServerTimeMS  int64              `json:"serverTimeMs"`
}

type userVipDTO struct {
	UserID      string `json:"userId"`
	Level       int32  `json:"level"`
	Name        string `json:"name"`
	Active      bool   `json:"active"`
	StartedAtMS int64  `json:"startedAtMs"`
	ExpiresAtMS int64  `json:"expiresAtMs"`
	UpdatedAtMS int64  `json:"updatedAtMs"`
}

type vipLevelDTO struct {
	Level                      int32  `json:"level"`
	Name                       string `json:"name"`
	Status                     string `json:"status"`
	PriceCoin                  int64  `json:"priceCoin"`
	DurationMS                 int64  `json:"durationMs"`
	RewardResourceGroupID      int64  `json:"rewardResourceGroupId"`
	SortOrder                  int32  `json:"sortOrder"`
	RechargeGateRequired       bool   `json:"rechargeGateRequired"`
	RequiredRechargeCoinAmount int64  `json:"requiredRechargeCoinAmount"`
	UserRechargeCoinAmount     int64  `json:"userRechargeCoinAmount"`
	PurchaseLockedReason       string `json:"purchaseLockedReason"`
	CreatedAtMS                int64  `json:"createdAtMs"`
	UpdatedAtMS                int64  `json:"updatedAtMs"`
}

type vipRewardItemDTO struct {
	ResourceID   string `json:"resourceId"`
	ResourceCode string `json:"resourceCode"`
	ResourceType string `json:"resourceType"`
	Name         string `json:"name"`
	Quantity     int64  `json:"quantity"`
	ExpiresAtMS  int64  `json:"expiresAtMs"`
}

func (h *Handler) ListLevels(c *gin.Context) {
	resp, err := h.wallet.ListAdminVipLevels(c.Request.Context(), &walletv1.ListAdminVipLevelsRequest{
		RequestId: middleware.CurrentRequestID(c),
		AppCode:   appctx.FromContext(c.Request.Context()),
	})
	if err != nil {
		response.ServerError(c, "获取 VIP 配置失败")
		return
	}
	response.OK(c, configDTO{Levels: vipLevelsFromProto(resp.GetLevels()), ServerTimeMS: resp.GetServerTimeMs()})
}

func (h *Handler) GrantVIP(c *gin.Context) {
	var req grantVipRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "VIP 赠送参数不正确")
		return
	}
	targetUserID, ok := parseFlexibleUserID(req.TargetUserID)
	if !ok || req.Level <= 0 {
		response.BadRequest(c, "VIP 赠送参数不正确")
		return
	}
	reason := strings.TrimSpace(req.Reason)
	if reason == "" {
		response.BadRequest(c, "赠送原因不能为空")
		return
	}
	commandID := strings.TrimSpace(req.CommandID)
	if commandID == "" {
		commandID = "admin_vip_grant:" + middleware.CurrentRequestID(c)
	}
	resp, err := h.wallet.GrantVip(c.Request.Context(), &walletv1.GrantVipRequest{
		CommandId:      commandID,
		AppCode:        appctx.FromContext(c.Request.Context()),
		TargetUserId:   targetUserID,
		Level:          req.Level,
		GrantSource:    "admin_grant",
		OperatorUserId: int64(middleware.CurrentUserID(c)),
		Reason:         reason,
	})
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLogWithResourceID(c, h.audit, "grant-vip", "user_vip_memberships", strconv.FormatInt(targetUserID, 10), "success", "level="+strconv.Itoa(int(req.Level)))
	response.Created(c, grantVipFromProto(resp))
}

func (h *Handler) UpdateLevels(c *gin.Context) {
	var req configRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "VIP 配置参数不正确")
		return
	}
	input := make([]*walletv1.AdminVipLevelInput, 0, len(req.Levels))
	for _, level := range req.Levels {
		input = append(input, &walletv1.AdminVipLevelInput{
			Level:                      level.Level,
			Name:                       strings.TrimSpace(level.Name),
			Status:                     strings.TrimSpace(level.Status),
			PriceCoin:                  level.PriceCoin,
			DurationMs:                 level.DurationMS,
			RewardResourceGroupId:      level.RewardResourceGroupID,
			RequiredRechargeCoinAmount: level.RequiredRechargeCoinAmount,
			SortOrder:                  level.SortOrder,
		})
	}
	resp, err := h.wallet.UpdateAdminVipLevels(c.Request.Context(), &walletv1.UpdateAdminVipLevelsRequest{
		RequestId:      middleware.CurrentRequestID(c),
		AppCode:        appctx.FromContext(c.Request.Context()),
		Levels:         input,
		OperatorUserId: int64(middleware.CurrentUserID(c)),
	})
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLogWithResourceID(c, h.audit, "update-vip-config", "vip_levels", appctx.FromContext(c.Request.Context()), "success", strconv.Itoa(len(resp.GetLevels())))
	response.OK(c, configDTO{Levels: vipLevelsFromProto(resp.GetLevels()), ServerTimeMS: resp.GetServerTimeMs()})
}

func vipLevelsFromProto(items []*walletv1.VipLevel) []vipLevelDTO {
	levels := make([]vipLevelDTO, 0, len(items))
	for _, item := range items {
		if item == nil {
			continue
		}
		levels = append(levels, vipLevelDTO{
			Level:                      item.GetLevel(),
			Name:                       item.GetName(),
			Status:                     item.GetStatus(),
			PriceCoin:                  item.GetPriceCoin(),
			DurationMS:                 item.GetDurationMs(),
			RewardResourceGroupID:      item.GetRewardResourceGroupId(),
			SortOrder:                  item.GetSortOrder(),
			RechargeGateRequired:       item.GetRechargeGateRequired(),
			RequiredRechargeCoinAmount: item.GetRequiredRechargeCoinAmount(),
			UserRechargeCoinAmount:     item.GetUserRechargeCoinAmount(),
			PurchaseLockedReason:       item.GetPurchaseLockedReason(),
			CreatedAtMS:                item.GetCreatedAtMs(),
			UpdatedAtMS:                item.GetUpdatedAtMs(),
		})
	}
	return levels
}

func grantVipFromProto(resp *walletv1.GrantVipResponse) grantVipDTO {
	if resp == nil {
		return grantVipDTO{}
	}
	return grantVipDTO{
		TransactionID: resp.GetTransactionId(),
		VIP:           userVipFromProto(resp.GetVip()),
		RewardItems:   vipRewardItemsFromProto(resp.GetRewardItems()),
		ServerTimeMS:  resp.GetServerTimeMs(),
	}
}

func userVipFromProto(item *walletv1.UserVip) userVipDTO {
	if item == nil {
		return userVipDTO{}
	}
	return userVipDTO{
		UserID:      strconv.FormatInt(item.GetUserId(), 10),
		Level:       item.GetLevel(),
		Name:        item.GetName(),
		Active:      item.GetActive(),
		StartedAtMS: item.GetStartedAtMs(),
		ExpiresAtMS: item.GetExpiresAtMs(),
		UpdatedAtMS: item.GetUpdatedAtMs(),
	}
}

func vipRewardItemsFromProto(items []*walletv1.VipRewardItem) []vipRewardItemDTO {
	rewards := make([]vipRewardItemDTO, 0, len(items))
	for _, item := range items {
		if item == nil {
			continue
		}
		rewards = append(rewards, vipRewardItemDTO{
			ResourceID:   strconv.FormatInt(item.GetResourceId(), 10),
			ResourceCode: item.GetResourceCode(),
			ResourceType: item.GetResourceType(),
			Name:         item.GetName(),
			Quantity:     item.GetQuantity(),
			ExpiresAtMS:  item.GetExpiresAtMs(),
		})
	}
	return rewards
}

func parseFlexibleUserID(value any) (int64, bool) {
	switch typed := value.(type) {
	case float64:
		userID := int64(typed)
		return userID, userID > 0 && float64(userID) == typed
	case string:
		userID, err := strconv.ParseInt(strings.TrimSpace(typed), 10, 64)
		return userID, err == nil && userID > 0
	default:
		return 0, false
	}
}
