package mysql

import (
	"fmt"
	"hyapp/pkg/appcode"
	"hyapp/services/wallet-service/internal/domain/ledger"
	"strings"
)

func giftDebitBizType(command ledger.DebitGiftCommand) string {
	if command.RobotGift {
		return bizTypeRobotGiftDebit
	}
	if command.DirectGift {
		return bizTypeDirectGiftDebit
	}
	return bizTypeGiftDebit
}

// giftSenderBalanceVersionAfter 预测本目标交易完成后的 sender 账户版本，并在插入交易 metadata 前固化。
// 钱包账户每执行一次 applyTrackedAccountDelta 都推进一个版本；机器人补足、实际扣费和自送礼返币
// 是三个独立分录，必须分别计数，才能让首次回执和后续幂等回放得到同一个精确版本。
func giftSenderBalanceVersionAfter(current int64, robotTopUp bool, debit bool, selfGiftIncome bool) int64 {
	next := current
	if robotTopUp {
		next++
	}
	if debit {
		next++
	}
	if selfGiftIncome {
		next++
	}
	return next
}

func aggregateGiftReceipts(targets []ledger.BatchGiftTargetReceipt) (ledger.Receipt, error) {
	aggregate := ledger.Receipt{}
	billingReceiptIDs := make([]string, 0, len(targets))
	transactionIDs := make([]string, 0, len(targets))
	for _, target := range targets {
		receipt := target.Receipt
		if receipt.BillingReceiptID != "" {
			billingReceiptIDs = append(billingReceiptIDs, receipt.BillingReceiptID)
		}
		if receipt.TransactionID != "" {
			transactionIDs = append(transactionIDs, receipt.TransactionID)
		}
		var err error
		if aggregate.CoinSpent, err = checkedAdd(aggregate.CoinSpent, receipt.CoinSpent); err != nil {
			return ledger.Receipt{}, err
		}
		if aggregate.ChargeAmount, err = checkedAdd(aggregate.ChargeAmount, receipt.ChargeAmount); err != nil {
			return ledger.Receipt{}, err
		}
		if aggregate.HeatValue, err = checkedAdd(aggregate.HeatValue, receipt.HeatValue); err != nil {
			return ledger.Receipt{}, err
		}
		if aggregate.HostPeriodDiamondAdded, err = checkedAdd(aggregate.HostPeriodDiamondAdded, receipt.HostPeriodDiamondAdded); err != nil {
			return ledger.Receipt{}, err
		}
		if aggregate.HostBaseAmount, err = checkedAdd(aggregate.HostBaseAmount, receipt.HostBaseAmount); err != nil {
			return ledger.Receipt{}, err
		}
		if aggregate.AgencyAmount, err = checkedAdd(aggregate.AgencyAmount, receipt.AgencyAmount); err != nil {
			return ledger.Receipt{}, err
		}
		if aggregate.HostPointAdded, err = checkedAdd(aggregate.HostPointAdded, receipt.HostPointAdded); err != nil {
			return ledger.Receipt{}, err
		}
		if aggregate.ChargeAssetType == "" {
			aggregate.ChargeAssetType = receipt.ChargeAssetType
		} else if receipt.ChargeAssetType != "" && aggregate.ChargeAssetType != receipt.ChargeAssetType {
			aggregate.ChargeAssetType = giftWallChargeAssetMixed
		}
		if aggregate.GiftTypeCode == "" {
			aggregate.GiftTypeCode = receipt.GiftTypeCode
		}
		if aggregate.CPRelationType == "" {
			aggregate.CPRelationType = receipt.CPRelationType
		}
		if aggregate.GiftName == "" {
			aggregate.GiftName = receipt.GiftName
		}
		if aggregate.GiftIconURL == "" {
			aggregate.GiftIconURL = receipt.GiftIconURL
		}
		if aggregate.GiftAnimationURL == "" {
			aggregate.GiftAnimationURL = receipt.GiftAnimationURL
		}
		if aggregate.PriceVersion == "" {
			aggregate.PriceVersion = receipt.PriceVersion
		}
		if aggregate.HostPeriodCycleKey == "" {
			aggregate.HostPeriodCycleKey = receipt.HostPeriodCycleKey
		}
		if aggregate.HostIncomePolicyType == "" {
			aggregate.HostIncomePolicyType = receipt.HostIncomePolicyType
		} else if receipt.HostIncomePolicyType != "" && aggregate.HostIncomePolicyType != receipt.HostIncomePolicyType {
			aggregate.HostIncomePolicyType = "MIXED"
		}
		if aggregate.IncomeAssetType == "" {
			aggregate.IncomeAssetType = receipt.IncomeAssetType
		} else if receipt.IncomeAssetType != "" && aggregate.IncomeAssetType != receipt.IncomeAssetType {
			aggregate.IncomeAssetType = "MIXED"
		}
		if aggregate.HostPointAssetType == "" {
			aggregate.HostPointAssetType = receipt.HostPointAssetType
		}
		if aggregate.HostPointPolicyInstanceCode == "" {
			aggregate.HostPointPolicyInstanceCode = receipt.HostPointPolicyInstanceCode
		}
		if aggregate.HostPointTemplateCode == "" {
			aggregate.HostPointTemplateCode = receipt.HostPointTemplateCode
		}
		if aggregate.HostPointTemplateVersion == "" {
			aggregate.HostPointTemplateVersion = receipt.HostPointTemplateVersion
		}
		if aggregate.PaidAtMS == 0 {
			aggregate.PaidAtMS = receipt.PaidAtMS
		} else if receipt.PaidAtMS > 0 && aggregate.PaidAtMS != receipt.PaidAtMS {
			// BatchDebitGift 在同一个 MySQL 事务、同一个 nowMs 创建全部目标交易；时间不一致说明
			// 回执集合被破坏，不能选一个时间继续让 lucky 把子抽分散到不同 UTC 风控窗口。
			return ledger.Receipt{}, fmt.Errorf("wallet batch gift paid_at_ms mismatch")
		}

		aggregate.BalanceAfter = receipt.BalanceAfter
		aggregate.BalanceVersion = receipt.BalanceVersion
		aggregate.HostPointBalanceAfter = receipt.HostPointBalanceAfter
		aggregate.HostIncomeBalanceAfter = receipt.HostIncomeBalanceAfter
		aggregate.AgencyIncomeBalanceAfter = receipt.AgencyIncomeBalanceAfter
	}
	aggregate.BillingReceiptID = strings.Join(billingReceiptIDs, ",")
	aggregate.TransactionID = strings.Join(transactionIDs, ",")
	return aggregate, nil
}

func debitRequestHash(command ledger.DebitGiftCommand) string {
	priceVersion := strings.TrimSpace(command.PriceVersion)
	if normalizeGiftChargeSource(command.ChargeSource, command.EntitlementID) == giftChargeSourceBag {
		// Bag pricing is always wallet-owned (pinned snapshot or latest legacy catalog). Caller price_version is
		// non-semantic and must not create a replay conflict or let a client select a favourable historical price.
		priceVersion = ""
	}

	if command.DirectGift {
		// direct gift 没有 Room Cell 命令，必须把场景写进幂等摘要，避免和空 room_id 的内部兼容调用互相复用。
		// region、Host 身份和 Agency 归属均由服务端实时解析并固化在首次回执，不属于客户端稳定意图；
		// 重试时这些派生值变化不能把已成功 command_id 误判为冲突。
		return stableHash(fmt.Sprintf("direct_gift|%s|%s|%d|%d|%s|%d|%s|%t|%s|%s",
			appcode.Normalize(command.AppCode),
			command.RoomID,
			command.SenderUserID,
			command.TargetUserID,
			command.GiftID,
			command.GiftCount,
			priceVersion,
			command.RobotGift,
			strings.TrimSpace(command.EntitlementID),
			normalizeGiftChargeSource(command.ChargeSource, command.EntitlementID),
		))
	}

	return stableHash(fmt.Sprintf("gift|%s|%s|%d|%d|%s|%d|%s|%t|%s|%s",
		appcode.Normalize(command.AppCode),
		command.RoomID,
		command.SenderUserID,
		command.TargetUserID,
		command.GiftID,
		command.GiftCount,
		priceVersion,
		command.RobotGift,
		strings.TrimSpace(command.EntitlementID),
		normalizeGiftChargeSource(command.ChargeSource, command.EntitlementID),
	))
}
