package wallet

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

// CreditTaskReward 发放任务奖励资产；任务完成判断属于 activity-service，这里只负责账本幂等入账。
func (s *Service) CreditTaskReward(ctx context.Context, command ledger.TaskRewardCommand) (ledger.TaskRewardReceipt, error) {
	if command.CommandID == "" || command.TargetUserID <= 0 || command.Amount <= 0 || command.TaskID == "" || command.CycleKey == "" {
		return ledger.TaskRewardReceipt{}, xerr.New(xerr.InvalidArgument, "task reward command is incomplete")
	}
	command.AssetType = strings.ToUpper(strings.TrimSpace(command.AssetType))
	if command.AssetType == "" {
		command.AssetType = ledger.AssetCoin
	}
	if command.AssetType != ledger.AssetCoin && command.AssetType != ledger.AssetPoint {
		return ledger.TaskRewardReceipt{}, xerr.New(xerr.InvalidArgument, "task reward asset_type is invalid")
	}
	command.TaskType = strings.ToLower(strings.TrimSpace(command.TaskType))
	if command.TaskType != "daily" && command.TaskType != "exclusive" {
		return ledger.TaskRewardReceipt{}, xerr.New(xerr.InvalidArgument, "task_type is invalid")
	}
	command.Reason = strings.TrimSpace(command.Reason)
	if command.Reason == "" {
		return ledger.TaskRewardReceipt{}, xerr.New(xerr.InvalidArgument, "reason is required")
	}
	if s.repository == nil {
		return ledger.TaskRewardReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	ctx = appcode.WithContext(ctx, command.AppCode)

	return s.repository.CreditTaskReward(ctx, command)
}

// CreditLuckyGiftReward 发放幸运礼物中奖金币；抽奖资格和金额已由 activity-service 决策，钱包只做幂等入账。
func (s *Service) CreditLuckyGiftReward(ctx context.Context, command ledger.LuckyGiftRewardCommand) (ledger.LuckyGiftRewardReceipt, error) {
	if command.CommandID == "" || command.TargetUserID <= 0 || command.Amount <= 0 || command.DrawID == "" || command.RoomID == "" || command.GiftID == "" || command.PoolID == "" {
		return ledger.LuckyGiftRewardReceipt{}, xerr.New(xerr.InvalidArgument, "lucky gift reward command is incomplete")
	}
	command.Reason = strings.TrimSpace(command.Reason)
	if command.Reason == "" {
		return ledger.LuckyGiftRewardReceipt{}, xerr.New(xerr.InvalidArgument, "reason is required")
	}
	if s.repository == nil {
		return ledger.LuckyGiftRewardReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	command.DrawID = strings.TrimSpace(command.DrawID)
	command.RoomID = strings.TrimSpace(command.RoomID)
	command.GiftID = strings.TrimSpace(command.GiftID)
	command.PoolID = strings.TrimSpace(command.PoolID)
	ctx = appcode.WithContext(ctx, command.AppCode)

	return s.repository.CreditLuckyGiftReward(ctx, command)
}

// CreditWheelReward 发放转盘金币奖品；抽奖、RTP 和奖品命中归 activity-service，钱包只负责独立 reason 的幂等入账。
func (s *Service) CreditWheelReward(ctx context.Context, command ledger.WheelRewardCommand) (ledger.WheelRewardReceipt, error) {
	if command.CommandID == "" || command.TargetUserID <= 0 || command.Amount <= 0 || command.DrawID == "" || command.WheelID == "" || command.SelectedTierID == "" {
		return ledger.WheelRewardReceipt{}, xerr.New(xerr.InvalidArgument, "wheel reward command is incomplete")
	}
	command.Reason = strings.TrimSpace(command.Reason)
	if command.Reason == "" {
		return ledger.WheelRewardReceipt{}, xerr.New(xerr.InvalidArgument, "reason is required")
	}
	if s.repository == nil {
		return ledger.WheelRewardReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	command.DrawID = strings.TrimSpace(command.DrawID)
	command.WheelID = strings.TrimSpace(command.WheelID)
	command.SelectedTierID = strings.TrimSpace(command.SelectedTierID)
	ctx = appcode.WithContext(ctx, command.AppCode)

	return s.repository.CreditWheelReward(ctx, command)
}

// CreditRoomTurnoverReward 发放每周房间流水奖励金币；结算归 activity-service，钱包只负责幂等入账。
func (s *Service) CreditRoomTurnoverReward(ctx context.Context, command ledger.RoomTurnoverRewardCommand) (ledger.RoomTurnoverRewardReceipt, error) {
	// 钱包只接受 activity-service 已经生成好的结算命令；缺 settlement、room 或正向金额时直接拒绝，避免钱包自己推断活动规则。
	if command.CommandID == "" || command.TargetUserID <= 0 || command.Amount <= 0 || command.SettlementID == "" || command.RoomID == "" {
		return ledger.RoomTurnoverRewardReceipt{}, xerr.New(xerr.InvalidArgument, "room turnover reward command is incomplete")
	}
	// 周期、流水和档位是账务元数据的一部分，必须随交易落库，后续对账才能从钱包交易反查是哪一周、哪个房间、哪个档位。
	if command.PeriodStartMS <= 0 || command.PeriodEndMS <= command.PeriodStartMS || command.CoinSpent <= 0 || command.TierID <= 0 {
		return ledger.RoomTurnoverRewardReceipt{}, xerr.New(xerr.InvalidArgument, "room turnover reward period or tier is invalid")
	}
	command.Reason = strings.TrimSpace(command.Reason)
	if command.Reason == "" {
		return ledger.RoomTurnoverRewardReceipt{}, xerr.New(xerr.InvalidArgument, "reason is required")
	}
	if s.repository == nil {
		return ledger.RoomTurnoverRewardReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	command.SettlementID = strings.TrimSpace(command.SettlementID)
	command.RoomID = strings.TrimSpace(command.RoomID)
	command.TierCode = strings.TrimSpace(command.TierCode)
	// AppCode 归一化后写入 context，让 repository 的交易、账户和 outbox 都落到同一个 App 分区。
	ctx = appcode.WithContext(ctx, command.AppCode)

	return s.repository.CreditRoomTurnoverReward(ctx, command)
}

// CreditInviteActivityReward 发放邀请活动金币奖励；达标和重复领取判断属于 activity-service，钱包只负责幂等入账。
func (s *Service) CreditInviteActivityReward(ctx context.Context, command ledger.InviteActivityRewardCommand) (ledger.InviteActivityRewardReceipt, error) {
	// 钱包入口再次校验最小账务语义，避免上游 bug 生成空 claim 或 0 金额交易。
	if command.CommandID == "" || command.TargetUserID <= 0 || command.Amount <= 0 || command.ClaimID == "" || command.TierID <= 0 || command.CycleKey == "" {
		return ledger.InviteActivityRewardReceipt{}, xerr.New(xerr.InvalidArgument, "invite activity reward command is incomplete")
	}
	command.RewardType = strings.ToLower(strings.TrimSpace(command.RewardType))
	if command.RewardType != "recharge" && command.RewardType != "valid_invite" && command.RewardType != "invite_inviter" && command.RewardType != "invite_invitee" {
		return ledger.InviteActivityRewardReceipt{}, xerr.New(xerr.InvalidArgument, "invite activity reward_type is invalid")
	}
	command.Reason = strings.TrimSpace(command.Reason)
	if command.Reason == "" {
		return ledger.InviteActivityRewardReceipt{}, xerr.New(xerr.InvalidArgument, "reason is required")
	}
	if s.repository == nil {
		return ledger.InviteActivityRewardReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	command.ClaimID = strings.TrimSpace(command.ClaimID)
	command.TierCode = strings.TrimSpace(command.TierCode)
	command.CycleKey = strings.TrimSpace(command.CycleKey)
	ctx = appcode.WithContext(ctx, command.AppCode)

	return s.repository.CreditInviteActivityReward(ctx, command)
}

// CreditAgencyOpeningReward 发放代理开业流水档位金币奖励；命中的档位序号和金额由 activity-service 固化，钱包只做幂等入账。
func (s *Service) CreditAgencyOpeningReward(ctx context.Context, command ledger.AgencyOpeningRewardCommand) (ledger.AgencyOpeningRewardReceipt, error) {
	if command.CommandID == "" || command.TargetUserID <= 0 || command.Amount <= 0 || command.ApplicationID == "" || command.CycleID == "" || command.AgencyID <= 0 || command.RankNo <= 0 {
		return ledger.AgencyOpeningRewardReceipt{}, xerr.New(xerr.InvalidArgument, "agency opening reward command is incomplete")
	}
	if command.ScoreCoins <= 0 {
		return ledger.AgencyOpeningRewardReceipt{}, xerr.New(xerr.InvalidArgument, "agency opening score is required")
	}
	command.Reason = strings.TrimSpace(command.Reason)
	if command.Reason == "" {
		return ledger.AgencyOpeningRewardReceipt{}, xerr.New(xerr.InvalidArgument, "reason is required")
	}
	if s.repository == nil {
		return ledger.AgencyOpeningRewardReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	command.ApplicationID = strings.TrimSpace(command.ApplicationID)
	command.CycleID = strings.TrimSpace(command.CycleID)
	ctx = appcode.WithContext(ctx, command.AppCode)

	return s.repository.CreditAgencyOpeningReward(ctx, command)
}

// DebitCPBreakupFee 扣除解除关系费用；关系是否可解除仍由 user-service 的 pending/confirm 流程决定。
func (s *Service) DebitCPBreakupFee(ctx context.Context, command ledger.CPBreakupFeeCommand) (ledger.CPBreakupFeeReceipt, error) {
	if command.CommandID == "" || command.UserID <= 0 || strings.TrimSpace(command.RelationshipID) == "" || strings.TrimSpace(command.RelationType) == "" {
		return ledger.CPBreakupFeeReceipt{}, xerr.New(xerr.InvalidArgument, "cp breakup fee command is incomplete")
	}
	if len(command.CommandID) > 128 {
		return ledger.CPBreakupFeeReceipt{}, xerr.New(xerr.InvalidArgument, "command_id is too long")
	}
	if command.Amount <= 0 {
		return ledger.CPBreakupFeeReceipt{}, xerr.New(xerr.InvalidArgument, "cp breakup fee amount must be positive")
	}
	if s.repository == nil {
		return ledger.CPBreakupFeeReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	command.RelationshipID = strings.TrimSpace(command.RelationshipID)
	command.RelationType = strings.ToLower(strings.TrimSpace(command.RelationType))
	ctx = appcode.WithContext(ctx, command.AppCode)
	return s.repository.DebitCPBreakupFee(ctx, command)
}

// DebitWheelDraw 扣除转盘抽奖消耗金币；抽奖命中必须在 activity-service 完成，wallet 只提供可幂等复用的扣费事实。
func (s *Service) DebitWheelDraw(ctx context.Context, command ledger.WheelDrawDebitCommand) (ledger.WheelDrawDebitReceipt, error) {
	if command.CommandID == "" || command.UserID <= 0 || strings.TrimSpace(command.WheelID) == "" {
		return ledger.WheelDrawDebitReceipt{}, xerr.New(xerr.InvalidArgument, "wheel draw debit command is incomplete")
	}
	if len(command.CommandID) > 128 {
		return ledger.WheelDrawDebitReceipt{}, xerr.New(xerr.InvalidArgument, "command_id is too long")
	}
	if command.DrawCount <= 0 {
		return ledger.WheelDrawDebitReceipt{}, xerr.New(xerr.InvalidArgument, "draw_count must be positive")
	}
	if command.Amount <= 0 {
		return ledger.WheelDrawDebitReceipt{}, xerr.New(xerr.InvalidArgument, "wheel draw debit amount must be positive")
	}
	if s.repository == nil {
		return ledger.WheelDrawDebitReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	command.WheelID = strings.TrimSpace(command.WheelID)
	ctx = appcode.WithContext(ctx, command.AppCode)
	return s.repository.DebitWheelDraw(ctx, command)
}
