package app

import (
	"encoding/json"
	"strings"

	"hyapp/pkg/appcode"
	"hyapp/pkg/walletmq"
	broadcastdomain "hyapp/services/activity-service/internal/domain/broadcast"
	cumulativerechargedomain "hyapp/services/activity-service/internal/domain/cumulativerecharge"
	firstrechargedomain "hyapp/services/activity-service/internal/domain/firstrecharge"
)

func firstRechargeEventFromWalletMessage(body []byte) (firstrechargedomain.RechargeEvent, bool, error) {
	message, err := walletmq.DecodeWalletOutboxMessage(body)
	if err != nil {
		return firstrechargedomain.RechargeEvent{}, false, err
	}
	if message.EventType != firstrechargedomain.RechargeEventWalletRecorded {
		return firstrechargedomain.RechargeEvent{}, false, nil
	}
	sequence, rechargeType := rechargeFactFromWalletPayload(message.PayloadJSON)
	return firstrechargedomain.RechargeEvent{
		AppCode:            appcode.Normalize(message.AppCode),
		EventID:            message.EventID,
		EventType:          message.EventType,
		TransactionID:      message.TransactionID,
		CommandID:          message.CommandID,
		UserID:             message.UserID,
		RechargeCoinAmount: message.AvailableDelta,
		RechargeSequence:   sequence,
		RechargeType:       rechargeType,
		PayloadJSON:        message.PayloadJSON,
		OccurredAtMS:       message.OccurredAtMS,
	}, true, nil
}

func cumulativeRechargeEventFromWalletMessage(body []byte) (cumulativerechargedomain.RechargeEvent, bool, error) {
	message, err := walletmq.DecodeWalletOutboxMessage(body)
	if err != nil {
		return cumulativerechargedomain.RechargeEvent{}, false, err
	}
	if message.EventType != cumulativerechargedomain.RechargeEventWalletRecorded {
		return cumulativerechargedomain.RechargeEvent{}, false, nil
	}
	// WalletRechargeRecorded 是累充唯一事实源；payload 里没有可折算 USD 金额时直接跳过，避免把普通钱包流水计入活动。
	fields := cumulativeRechargeFactFromWalletPayload(message.PayloadJSON, message.AvailableDelta)
	if fields.qualifyingUSDMinor <= 0 {
		return cumulativerechargedomain.RechargeEvent{}, false, nil
	}
	return cumulativerechargedomain.RechargeEvent{
		AppCode:            appcode.Normalize(message.AppCode),
		EventID:            message.EventID,
		EventType:          message.EventType,
		TransactionID:      message.TransactionID,
		CommandID:          message.CommandID,
		UserID:             message.UserID,
		RechargeCoinAmount: fields.coinAmount,
		RechargeSequence:   fields.sequence,
		RechargeType:       fields.rechargeType,
		QualifyingUSDMinor: fields.qualifyingUSDMinor,
		PayloadJSON:        message.PayloadJSON,
		OccurredAtMS:       message.OccurredAtMS,
	}, true, nil
}

func redPacketEventFromWalletMessage(body []byte) (broadcastdomain.RedPacketWalletEvent, bool, error) {
	message, err := walletmq.DecodeWalletOutboxMessage(body)
	if err != nil {
		return broadcastdomain.RedPacketWalletEvent{}, false, err
	}
	if message.EventType != "WalletRedPacketCreated" && message.EventType != "WalletRedPacketClaimed" && message.EventType != "WalletRedPacketRefunded" {
		return broadcastdomain.RedPacketWalletEvent{}, false, nil
	}
	fields := redPacketFieldsFromWalletPayload(message.PayloadJSON, message.EventType)
	if fields.PacketID == "" {
		return broadcastdomain.RedPacketWalletEvent{}, false, nil
	}
	return broadcastdomain.RedPacketWalletEvent{
		AppCode:         appcode.Normalize(message.AppCode),
		EventID:         message.EventID,
		EventType:       message.EventType,
		TransactionID:   message.TransactionID,
		CommandID:       message.CommandID,
		PayloadJSON:     message.PayloadJSON,
		PacketID:        fields.PacketID,
		PacketType:      fields.PacketType,
		RoomID:          fields.RoomID,
		RegionID:        fields.RegionID,
		RegionCode:      fields.RegionCode,
		SenderUserID:    fields.SenderUserID,
		TotalAmount:     fields.TotalAmount,
		TotalCount:      fields.TotalCount,
		RemainingAmount: fields.RemainingAmount,
		RemainingCount:  fields.RemainingCount,
		RefundedAmount:  fields.RefundedAmount,
		Status:          fields.Status,
		OpenAtMS:        fields.OpenAtMS,
		ExpiresAtMS:     fields.ExpiresAtMS,
		CreatedAtMS:     message.OccurredAtMS,
	}, true, nil
}

func rechargeFactFromWalletPayload(payload string) (int64, string) {
	var decoded map[string]any
	if err := json.Unmarshal([]byte(payload), &decoded); err != nil {
		return 0, firstrechargedomain.RechargeTypeCoinSeller
	}
	var sequence int64
	switch value := decoded["recharge_sequence"].(type) {
	case float64:
		sequence = int64(value)
	case int64:
		sequence = value
	case json.Number:
		sequence, _ = value.Int64()
	}
	rechargeType := firstrechargedomain.RechargeTypeCoinSeller
	if value, ok := decoded["recharge_type"].(string); ok && value != "" {
		rechargeType = value
	}
	return sequence, rechargeType
}

type cumulativeRechargePayloadFields struct {
	sequence           int64
	rechargeType       string
	coinAmount         int64
	qualifyingUSDMinor int64
}

func cumulativeRechargeFactFromWalletPayload(payload string, availableDelta int64) cumulativeRechargePayloadFields {
	var decoded map[string]any
	if err := json.Unmarshal([]byte(payload), &decoded); err != nil {
		decoded = map[string]any{}
	}
	// 来源字段兼容 wallet 历史 payload；没有明确来源时按币商转账处理，因为币商链路通常只带金币增量。
	rechargeType := firstNonEmptyString(
		stringFromDecoded(decoded, "recharge_type"),
		stringFromDecoded(decoded, "channel"),
		stringFromDecoded(decoded, "provider"),
		cumulativerechargedomain.RechargeTypeCoinSeller,
	)
	// coinAmount 用于审计和币商折算，优先使用 payload 明细，最后回退 wallet outbox 的 available_delta。
	coinAmount := firstNonZeroInt64(
		int64FromDecoded(decoded, "coin_amount"),
		int64FromDecoded(decoded, "amount"),
		int64FromDecoded(decoded, "available_delta"),
		availableDelta,
	)
	qualifyingUSDMinor := cumulativeRechargeUSDMinorFromPayload(decoded, rechargeType, coinAmount)
	return cumulativeRechargePayloadFields{
		sequence:           int64FromDecoded(decoded, "recharge_sequence"),
		rechargeType:       rechargeType,
		coinAmount:         coinAmount,
		qualifyingUSDMinor: qualifyingUSDMinor,
	}
}

func cumulativeRechargeUSDMinorFromPayload(decoded map[string]any, rechargeType string, coinAmount int64) int64 {
	if isCumulativeCoinSellerRecharge(rechargeType) {
		// 币商给用户转账按 90000 coins = 1 USD 折算；这里返回美分并向下取整，尾差只留在原始金币字段审计。
		return coinAmount * 100 / 90000
	}
	// Google/Mifapay 充值优先使用支付侧传入的美元美分，避免用金币包配置反推造成汇率误差。
	if value := firstNonZeroInt64(
		int64FromDecoded(decoded, "recharge_usd_minor"),
		int64FromDecoded(decoded, "usd_minor_amount"),
		int64FromDecoded(decoded, "exchange_usd_minor_amount"),
		int64FromDecoded(decoded, "amount_usd_minor"),
	); value > 0 {
		return value
	}
	if isCumulativeGoogleRecharge(rechargeType) {
		// Google Billing 常见 amount_micro 是 USD 微单位，除以 10000 后得到美分。
		return int64FromDecoded(decoded, "amount_micro") / 10000
	}
	return 0
}

func isCumulativeCoinSellerRecharge(value string) bool {
	switch strings.ToLower(strings.TrimSpace(value)) {
	case "coin_seller_transfer", "coin_seller":
		return true
	default:
		return false
	}
}

func isCumulativeGoogleRecharge(value string) bool {
	switch strings.ToLower(strings.TrimSpace(value)) {
	case "google", "google_play":
		return true
	default:
		return false
	}
}

type redPacketPayloadFields struct {
	PacketID        string
	PacketType      string
	RoomID          string
	RegionID        int64
	RegionCode      string
	SenderUserID    int64
	TotalAmount     int64
	TotalCount      int32
	RemainingAmount int64
	RemainingCount  int32
	RefundedAmount  int64
	Status          string
	OpenAtMS        int64
	ExpiresAtMS     int64
}

func redPacketFieldsFromWalletPayload(payload string, eventType string) redPacketPayloadFields {
	var decoded map[string]any
	if err := json.Unmarshal([]byte(payload), &decoded); err != nil {
		return redPacketPayloadFields{}
	}
	packetID := stringFromDecoded(decoded, "packet_id")
	if packetID == "" {
		packetID = stringFromDecoded(decoded, "packetId")
	}
	packetType := stringFromDecoded(decoded, "packet_type")
	roomID := stringFromDecoded(decoded, "room_id")
	regionID := int64FromDecoded(decoded, "region_id")
	status := stringFromDecoded(decoded, "status")
	openAtMS := int64FromDecoded(decoded, "open_at_ms")
	expiresAtMS := int64FromDecoded(decoded, "expires_at_ms")
	if eventType == "WalletRedPacketClaimed" || eventType == "WalletRedPacketRefunded" {
		status = stringFromDecoded(decoded, "packet_status")
	}
	totalCount := int32FromDecoded(decoded, "packet_count")
	remainingCount := int32FromDecoded(decoded, "remaining_count")
	if remainingCount == 0 && eventType == "WalletRedPacketCreated" {
		remainingCount = totalCount
	}
	return redPacketPayloadFields{
		PacketID:        packetID,
		PacketType:      packetType,
		RoomID:          roomID,
		RegionID:        regionID,
		RegionCode:      stringFromDecoded(decoded, "region_code"),
		SenderUserID:    int64FromDecoded(decoded, "sender_user_id"),
		TotalAmount:     int64FromDecoded(decoded, "total_amount"),
		TotalCount:      totalCount,
		RemainingAmount: int64FromDecoded(decoded, "remaining_amount"),
		RemainingCount:  remainingCount,
		RefundedAmount:  int64FromDecoded(decoded, "refund_amount"),
		Status:          status,
		OpenAtMS:        openAtMS,
		ExpiresAtMS:     expiresAtMS,
	}
}

func stringFromDecoded(decoded map[string]any, key string) string {
	value, _ := decoded[key].(string)
	return value
}

func firstNonEmptyString(values ...string) string {
	for _, value := range values {
		if value = strings.TrimSpace(value); value != "" {
			return value
		}
	}
	return ""
}

func firstNonZeroInt64(values ...int64) int64 {
	for _, value := range values {
		if value != 0 {
			return value
		}
	}
	return 0
}

func int64FromDecoded(decoded map[string]any, key string) int64 {
	switch value := decoded[key].(type) {
	case float64:
		return int64(value)
	case int64:
		return value
	case json.Number:
		parsed, _ := value.Int64()
		return parsed
	default:
		return 0
	}
}

func int32FromDecoded(decoded map[string]any, key string) int32 {
	return int32(int64FromDecoded(decoded, key))
}
