package walletapi

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

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

type assetBalanceData struct {
	AssetType       string `json:"asset_type"`
	AvailableAmount int64  `json:"available_amount"`
	FrozenAmount    int64  `json:"frozen_amount"`
	Version         int64  `json:"version"`
}

type coinSellerTransferData struct {
	TransactionID                string `json:"transaction_id"`
	SellerBalanceAfter           int64  `json:"seller_balance_after"`
	TargetBalanceAfter           int64  `json:"target_balance_after"`
	Amount                       int64  `json:"amount"`
	RechargeUSDMinor             int64  `json:"recharge_usd_minor"`
	RechargeCurrencyCode         string `json:"recharge_currency_code"`
	RechargePolicyID             int64  `json:"recharge_policy_id"`
	RechargePolicyVersion        string `json:"recharge_policy_version"`
	RechargePolicyCoinAmount     int64  `json:"recharge_policy_coin_amount"`
	RechargePolicyUSDMinorAmount int64  `json:"recharge_policy_usd_minor_amount"`
}

type coinSellerTransferRequestBody struct {
	CommandID                string `json:"command_id"`
	CommandIDCamel           string `json:"commandId"`
	TargetUserID             int64  `json:"target_user_id"`
	TargetUserIDCamel        int64  `json:"targetUserId"`
	TargetDisplayUserID      string `json:"target_display_user_id"`
	TargetDisplayUserIDCamel string `json:"targetDisplayUserId"`
	Amount                   int64  `json:"amount"`
	Reason                   string `json:"reason"`
}

func (b coinSellerTransferRequestBody) normalizedCommandID() string {
	if commandID := strings.TrimSpace(b.CommandID); commandID != "" {
		return commandID
	}
	return strings.TrimSpace(b.CommandIDCamel)
}

func (b coinSellerTransferRequestBody) normalizedTargetDisplayUserID() string {
	if displayUserID := strings.TrimSpace(b.TargetDisplayUserID); displayUserID != "" {
		return displayUserID
	}
	if displayUserID := strings.TrimSpace(b.TargetDisplayUserIDCamel); displayUserID != "" {
		return displayUserID
	}
	if b.TargetUserID > 0 {
		return strconv.FormatInt(b.TargetUserID, 10)
	}
	if b.TargetUserIDCamel > 0 {
		return strconv.FormatInt(b.TargetUserIDCamel, 10)
	}
	return ""
}

// getMyBalances 返回当前登录用户的钱包余额。
func (h *Handler) getMyBalances(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.GetBalances(request.Context(), &walletv1.GetBalancesRequest{
		RequestId:  httpkit.RequestIDFromContext(request.Context()),
		UserId:     auth.UserIDFromContext(request.Context()),
		AssetTypes: walletAssetTypes(request),
		AppCode:    appcode.FromContext(request.Context()),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}

	balances := make([]assetBalanceData, 0, len(resp.GetBalances()))
	for _, balance := range resp.GetBalances() {
		balances = append(balances, assetBalanceData{
			AssetType:       balance.GetAssetType(),
			AvailableAmount: balance.GetAvailableAmount(),
			FrozenAmount:    balance.GetFrozenAmount(),
			Version:         balance.GetVersion(),
		})
	}
	httpkit.WriteOK(writer, request, map[string]any{"balances": balances})
}

// transferCoinFromSeller 处理币商给玩家转金币的 App 入口。
func (h *Handler) transferCoinFromSeller(writer http.ResponseWriter, request *http.Request) {
	if h.walletClient == nil || h.userHostClient == nil || h.userProfileClient == nil || h.userIdentityClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	var body coinSellerTransferRequestBody
	if !httpkit.Decode(writer, request, &body) {
		return
	}
	commandID := body.normalizedCommandID()
	targetDisplayUserID := body.normalizedTargetDisplayUserID()
	reason := strings.TrimSpace(body.Reason)
	if commandID == "" || targetDisplayUserID == "" || body.Amount <= 0 || reason == "" {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}

	sellerUserID := auth.UserIDFromContext(request.Context())
	profileResp, err := h.userHostClient.GetCoinSellerProfile(request.Context(), &userv1.GetCoinSellerProfileRequest{
		Meta:   httpkit.UserMeta(request, ""),
		UserId: sellerUserID,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	profile := profileResp.GetCoinSellerProfile()
	if profile == nil || profile.GetStatus() != "active" || profile.GetMerchantAssetType() != "COIN_SELLER_COIN" {
		httpkit.WriteError(writer, request, http.StatusForbidden, httpkit.CodePermissionDenied, "permission denied")
		return
	}
	targetUserID, ok := h.resolveCoinSellerTransferTargetUserID(writer, request, targetDisplayUserID)
	if !ok {
		return
	}
	sellerRegionID, targetRegionID, targetCountryID, ok := h.coinSellerTransferRegions(writer, request, sellerUserID, targetUserID)
	if !ok {
		return
	}

	resp, err := h.walletClient.TransferCoinFromSeller(request.Context(), &walletv1.TransferCoinFromSellerRequest{
		CommandId:       commandID,
		SellerUserId:    sellerUserID,
		TargetUserId:    targetUserID,
		SellerRegionId:  sellerRegionID,
		TargetRegionId:  targetRegionID,
		TargetCountryId: targetCountryID,
		Amount:          body.Amount,
		Reason:          reason,
		AppCode:         appcode.FromContext(request.Context()),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	httpkit.WriteOK(writer, request, coinSellerTransferData{
		TransactionID:                resp.GetTransactionId(),
		SellerBalanceAfter:           resp.GetSellerBalanceAfter(),
		TargetBalanceAfter:           resp.GetTargetBalanceAfter(),
		Amount:                       resp.GetAmount(),
		RechargeUSDMinor:             resp.GetRechargeUsdMinor(),
		RechargeCurrencyCode:         resp.GetRechargeCurrencyCode(),
		RechargePolicyID:             resp.GetRechargePolicyId(),
		RechargePolicyVersion:        resp.GetRechargePolicyVersion(),
		RechargePolicyCoinAmount:     resp.GetRechargePolicyCoinAmount(),
		RechargePolicyUSDMinorAmount: resp.GetRechargePolicyUsdMinorAmount(),
	})
}

func (h *Handler) resolveCoinSellerTransferTargetUserID(writer http.ResponseWriter, request *http.Request, targetDisplayUserID string) (int64, bool) {
	resp, err := h.userIdentityClient.ResolveDisplayUserID(request.Context(), &userv1.ResolveDisplayUserIDRequest{
		Meta:          httpkit.UserMeta(request, ""),
		DisplayUserId: targetDisplayUserID,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return 0, false
	}
	identity := resp.GetIdentity()
	targetUserID := identity.GetUserId()
	if targetUserID <= 0 {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return 0, false
	}
	return targetUserID, true
}

func (h *Handler) coinSellerTransferRegions(writer http.ResponseWriter, request *http.Request, sellerUserID int64, targetUserID int64) (int64, int64, int64, bool) {
	sellerResp, err := h.userProfileClient.GetUser(request.Context(), &userv1.GetUserRequest{
		Meta:   httpkit.UserMeta(request, ""),
		UserId: sellerUserID,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return 0, 0, 0, false
	}
	seller := sellerResp.GetUser()
	sellerCountryID := seller.GetCountryId()
	sellerRegionID := seller.GetRegionId()
	if sellerUserID == targetUserID {
		if sellerCountryID <= 0 || sellerRegionID <= 0 {
			httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
			return 0, 0, 0, false
		}
		return sellerRegionID, sellerRegionID, sellerCountryID, true
	}
	targetResp, err := h.userProfileClient.GetUser(request.Context(), &userv1.GetUserRequest{
		Meta:   httpkit.UserMeta(request, ""),
		UserId: targetUserID,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return 0, 0, 0, false
	}
	target := targetResp.GetUser()
	targetCountryID := target.GetCountryId()
	targetRegionID := target.GetRegionId()
	if sellerRegionID <= 0 || targetCountryID <= 0 || targetRegionID <= 0 {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return 0, 0, 0, false
	}
	if sellerRegionID != targetRegionID {
		// 充值政策当前按单一区域生效；跨区转账必须先设计明确的结算区域，不能静默套用任意一方政策。
		httpkit.WriteError(writer, request, http.StatusConflict, string(xerr.Conflict), "seller and target are in different regions")
		return 0, 0, 0, false
	}
	return sellerRegionID, targetRegionID, targetCountryID, true
}

func walletAssetTypes(request *http.Request) []string {
	rawValues := request.URL.Query()["asset_type"]
	if len(rawValues) == 0 {
		rawValues = request.URL.Query()["asset_types"]
	}

	assetTypes := make([]string, 0, len(rawValues))
	for _, raw := range rawValues {
		for value := range strings.SplitSeq(raw, ",") {
			value = strings.TrimSpace(value)
			if value != "" {
				assetTypes = append(assetTypes, value)
			}
		}
	}
	if len(assetTypes) == 0 {
		return []string{"COIN"}
	}

	return assetTypes
}
