package http

import (
	"hyapp/services/gateway-service/internal/transport/http/httpkit"
	"net/http"
	"strings"

	userv1 "hyapp.local/api/proto/user/v1"
	walletv1 "hyapp.local/api/proto/wallet/v1"
	"hyapp/pkg/appcode"
	"hyapp/services/gateway-service/internal/auth"
)

type rechargeProductData struct {
	ProductID         int64   `json:"product_id"`
	ProductCode       string  `json:"product_code"`
	ProductName       string  `json:"product_name"`
	Description       string  `json:"description"`
	Platform          string  `json:"platform"`
	Channel           string  `json:"channel"`
	CurrencyCode      string  `json:"currency_code"`
	CoinAmount        int64   `json:"coin_amount"`
	AmountMinor       int64   `json:"amount_minor"`
	AmountMicro       int64   `json:"amount_micro"`
	PolicyVersion     string  `json:"policy_version"`
	RegionIDs         []int64 `json:"region_ids"`
	ResourceAssetType string  `json:"resource_asset_type"`
	Status            string  `json:"status"`
	Enabled           bool    `json:"enabled"`
	SortOrder         int32   `json:"sort_order"`
}

type diamondExchangeRuleData struct {
	ExchangeType  string `json:"exchange_type"`
	FromAssetType string `json:"from_asset_type"`
	ToAssetType   string `json:"to_asset_type"`
	FromAmount    int64  `json:"from_amount"`
	ToAmount      int64  `json:"to_amount"`
	Enabled       bool   `json:"enabled"`
}

type walletOverviewData struct {
	Balances     []assetBalanceData     `json:"balances"`
	FeatureFlags walletFeatureFlagsData `json:"feature_flags"`
}

type walletFeatureFlagsData struct {
	RechargeEnabled        bool `json:"recharge_enabled"`
	DiamondExchangeEnabled bool `json:"diamond_exchange_enabled"`
	WithdrawEnabled        bool `json:"withdraw_enabled"`
}

type walletTransactionData struct {
	EntryID            int64  `json:"entry_id"`
	TransactionID      string `json:"transaction_id"`
	BizType            string `json:"biz_type"`
	AssetType          string `json:"asset_type"`
	AvailableDelta     int64  `json:"available_delta"`
	FrozenDelta        int64  `json:"frozen_delta"`
	AvailableAfter     int64  `json:"available_after"`
	FrozenAfter        int64  `json:"frozen_after"`
	CounterpartyUserID int64  `json:"counterparty_user_id"`
	RoomID             string `json:"room_id"`
	CreatedAtMS        int64  `json:"created_at_ms"`
}

type withdrawalApplyRequestBody struct {
	CommandID     string `json:"command_id"`
	CommandIDAlt  string `json:"commandId"`
	Amount        int64  `json:"amount"`
	PayoutAccount string `json:"payout_account"`
	PayoutAlt     string `json:"payoutAccount"`
	Reason        string `json:"reason"`
}

type withdrawalData struct {
	WithdrawalID  string `json:"withdrawal_id"`
	UserID        int64  `json:"user_id"`
	AssetType     string `json:"asset_type"`
	Amount        int64  `json:"amount"`
	Status        string `json:"status"`
	PayoutAccount string `json:"payout_account"`
	Reason        string `json:"reason"`
	CreatedAtMS   int64  `json:"created_at_ms"`
	UpdatedAtMS   int64  `json:"updated_at_ms"`
}

type vipPurchaseRequestBody struct {
	CommandID    string `json:"command_id"`
	CommandIDAlt string `json:"commandId"`
	Level        int32  `json:"level"`
}

type vipPackageData struct {
	Level                 int32               `json:"level"`
	Name                  string              `json:"name"`
	Status                string              `json:"status"`
	PriceCoin             int64               `json:"price_coin"`
	DurationMS            int64               `json:"duration_ms"`
	RewardResourceGroupID int64               `json:"reward_resource_group_id"`
	RewardItems           []vipRewardItemData `json:"reward_items"`
	CanPurchase           bool                `json:"can_purchase"`
	SortOrder             int32               `json:"sort_order"`
}

type vipRewardItemData struct {
	ResourceID   int64  `json:"resource_id"`
	ResourceCode string `json:"resource_code"`
	ResourceType string `json:"resource_type"`
	Name         string `json:"name"`
	Quantity     int64  `json:"quantity"`
	ExpiresAtMS  int64  `json:"expires_at_ms"`
}

// getWalletOverview 返回钱包二级页摘要；我的页首屏使用更轻的 WalletValueSummary。
func (h *Handler) getWalletOverview(writer http.ResponseWriter, request *http.Request) {
	if h.walletClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	resp, err := h.walletClient.GetWalletOverview(request.Context(), &walletv1.GetWalletOverviewRequest{
		RequestId: httpkit.RequestIDFromContext(request.Context()),
		AppCode:   appcode.FromContext(request.Context()),
		UserId:    auth.UserIDFromContext(request.Context()),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	httpkit.WriteOK(writer, request, walletOverviewFromProto(resp))
}

// listRechargeProducts 返回用户当前区域可用的充值档位。
func (h *Handler) listRechargeProducts(writer http.ResponseWriter, request *http.Request) {
	if h.walletClient == nil || h.userProfileClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	userID := auth.UserIDFromContext(request.Context())
	profileResp, err := h.userProfileClient.GetUser(request.Context(), &userv1.GetUserRequest{
		Meta:   authRequestMeta(request, ""),
		UserId: userID,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	resp, err := h.walletClient.ListRechargeProducts(request.Context(), &walletv1.ListRechargeProductsRequest{
		RequestId: httpkit.RequestIDFromContext(request.Context()),
		AppCode:   appcode.FromContext(request.Context()),
		UserId:    userID,
		RegionId:  profileResp.GetUser().GetRegionId(),
		Platform:  firstQueryOrHeader(request, "platform", "X-App-Platform", "X-Platform"),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	products := make([]rechargeProductData, 0, len(resp.GetProducts()))
	for _, product := range resp.GetProducts() {
		products = append(products, rechargeProductFromProto(product))
	}
	httpkit.WriteOK(writer, request, map[string]any{"channels": resp.GetChannels(), "products": products})
}

// getDiamondExchangeConfig 返回钻石兑换配置。
func (h *Handler) getDiamondExchangeConfig(writer http.ResponseWriter, request *http.Request) {
	if h.walletClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	resp, err := h.walletClient.GetDiamondExchangeConfig(request.Context(), &walletv1.GetDiamondExchangeConfigRequest{
		RequestId: httpkit.RequestIDFromContext(request.Context()),
		AppCode:   appcode.FromContext(request.Context()),
		UserId:    auth.UserIDFromContext(request.Context()),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	rules := make([]diamondExchangeRuleData, 0, len(resp.GetRules()))
	for _, rule := range resp.GetRules() {
		rules = append(rules, diamondExchangeRuleFromProto(rule))
	}
	httpkit.WriteOK(writer, request, map[string]any{"rules": rules})
}

// listWalletTransactions 返回当前用户钱包流水分页。
func (h *Handler) listWalletTransactions(writer http.ResponseWriter, request *http.Request) {
	h.listWalletTransactionsByAsset(writer, request, strings.TrimSpace(request.URL.Query().Get("asset_type")), 20)
}

// listCoinTransactions 返回当前用户金币流水分页；默认 page_size=30 对齐 App 最近 30 条展示。
func (h *Handler) listCoinTransactions(writer http.ResponseWriter, request *http.Request) {
	h.listWalletTransactionsByAsset(writer, request, "COIN", 30)
}

func (h *Handler) listWalletTransactionsByAsset(writer http.ResponseWriter, request *http.Request, assetType string, defaultPageSize int32) {
	if h.walletClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	page, ok := parsePositiveInt32Query(request, "page", 1)
	if !ok {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}
	pageSize, ok := parsePositiveInt32Query(request, "page_size", defaultPageSize)
	if !ok {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}
	resp, err := h.walletClient.ListWalletTransactions(request.Context(), &walletv1.ListWalletTransactionsRequest{
		RequestId: httpkit.RequestIDFromContext(request.Context()),
		AppCode:   appcode.FromContext(request.Context()),
		UserId:    auth.UserIDFromContext(request.Context()),
		AssetType: assetType,
		Page:      page,
		PageSize:  pageSize,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	items := make([]walletTransactionData, 0, len(resp.GetTransactions()))
	for _, item := range resp.GetTransactions() {
		items = append(items, walletTransactionFromProto(item))
	}
	httpkit.WriteOK(writer, request, map[string]any{"items": items, "total": resp.GetTotal(), "page": page, "page_size": pageSize})
}

// applyWithdrawal 创建待人工审核的提现申请。
func (h *Handler) applyWithdrawal(writer http.ResponseWriter, request *http.Request) {
	if h.walletClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	var body withdrawalApplyRequestBody
	if !decode(writer, request, &body) {
		return
	}
	commandID := strings.TrimSpace(body.CommandID)
	if commandID == "" {
		commandID = strings.TrimSpace(body.CommandIDAlt)
	}
	payoutAccount := strings.TrimSpace(body.PayoutAccount)
	if payoutAccount == "" {
		payoutAccount = strings.TrimSpace(body.PayoutAlt)
	}
	if commandID == "" || body.Amount <= 0 || payoutAccount == "" {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}
	resp, err := h.walletClient.ApplyWithdrawal(request.Context(), &walletv1.ApplyWithdrawalRequest{
		CommandId:     commandID,
		AppCode:       appcode.FromContext(request.Context()),
		UserId:        auth.UserIDFromContext(request.Context()),
		Amount:        body.Amount,
		PayoutAccount: payoutAccount,
		Reason:        strings.TrimSpace(body.Reason),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	httpkit.WriteOK(writer, request, map[string]any{
		"withdrawal": withdrawalFromProto(resp.GetWithdrawal()),
		"balance":    balanceFromProto(resp.GetBalance()),
	})
}

func rechargeProductFromProto(product *walletv1.RechargeProduct) rechargeProductData {
	if product == nil {
		return rechargeProductData{}
	}
	return rechargeProductData{
		ProductID:         product.GetProductId(),
		ProductCode:       product.GetProductCode(),
		ProductName:       product.GetProductName(),
		Description:       product.GetDescription(),
		Platform:          product.GetPlatform(),
		Channel:           product.GetChannel(),
		CurrencyCode:      product.GetCurrencyCode(),
		CoinAmount:        product.GetCoinAmount(),
		AmountMinor:       product.GetAmountMinor(),
		AmountMicro:       product.GetAmountMicro(),
		PolicyVersion:     product.GetPolicyVersion(),
		RegionIDs:         product.GetRegionIds(),
		ResourceAssetType: product.GetResourceAssetType(),
		Status:            product.GetStatus(),
		Enabled:           product.GetEnabled(),
		SortOrder:         product.GetSortOrder(),
	}
}

func diamondExchangeRuleFromProto(rule *walletv1.DiamondExchangeRule) diamondExchangeRuleData {
	if rule == nil {
		return diamondExchangeRuleData{}
	}
	return diamondExchangeRuleData{
		ExchangeType:  rule.GetExchangeType(),
		FromAssetType: rule.GetFromAssetType(),
		ToAssetType:   rule.GetToAssetType(),
		FromAmount:    rule.GetFromAmount(),
		ToAmount:      rule.GetToAmount(),
		Enabled:       rule.GetEnabled(),
	}
}

func walletOverviewFromProto(resp *walletv1.GetWalletOverviewResponse) walletOverviewData {
	if resp == nil {
		return walletOverviewData{}
	}
	balances := make([]assetBalanceData, 0, len(resp.GetBalances()))
	for _, balance := range resp.GetBalances() {
		balances = append(balances, balanceFromProto(balance))
	}
	flags := resp.GetFeatureFlags()
	return walletOverviewData{
		Balances: balances,
		FeatureFlags: walletFeatureFlagsData{
			RechargeEnabled:        flags.GetRechargeEnabled(),
			DiamondExchangeEnabled: flags.GetDiamondExchangeEnabled(),
			WithdrawEnabled:        flags.GetWithdrawEnabled(),
		},
	}
}

func walletTransactionFromProto(item *walletv1.WalletTransaction) walletTransactionData {
	if item == nil {
		return walletTransactionData{}
	}
	return walletTransactionData{
		EntryID:            item.GetEntryId(),
		TransactionID:      item.GetTransactionId(),
		BizType:            item.GetBizType(),
		AssetType:          item.GetAssetType(),
		AvailableDelta:     item.GetAvailableDelta(),
		FrozenDelta:        item.GetFrozenDelta(),
		AvailableAfter:     item.GetAvailableAfter(),
		FrozenAfter:        item.GetFrozenAfter(),
		CounterpartyUserID: item.GetCounterpartyUserId(),
		RoomID:             item.GetRoomId(),
		CreatedAtMS:        item.GetCreatedAtMs(),
	}
}

func withdrawalFromProto(item *walletv1.WithdrawalRequest) withdrawalData {
	if item == nil {
		return withdrawalData{}
	}
	return withdrawalData{
		WithdrawalID:  item.GetWithdrawalId(),
		UserID:        item.GetUserId(),
		AssetType:     item.GetAssetType(),
		Amount:        item.GetAmount(),
		Status:        item.GetStatus(),
		PayoutAccount: item.GetPayoutAccount(),
		Reason:        item.GetReason(),
		CreatedAtMS:   item.GetCreatedAtMs(),
		UpdatedAtMS:   item.GetUpdatedAtMs(),
	}
}

func balanceFromProto(balance *walletv1.AssetBalance) assetBalanceData {
	if balance == nil {
		return assetBalanceData{}
	}
	return assetBalanceData{
		AssetType:       balance.GetAssetType(),
		AvailableAmount: balance.GetAvailableAmount(),
		FrozenAmount:    balance.GetFrozenAmount(),
		Version:         balance.GetVersion(),
	}
}
