package wallet

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

// AdminCreditCoinSellerStock 只调整 COIN_SELLER_COIN 库存；USDT 进货、USDT 冲回和金币补偿使用不同账务类型。
func (s *Service) AdminCreditCoinSellerStock(ctx context.Context, command ledger.CoinSellerStockCreditCommand) (ledger.CoinSellerStockCreditReceipt, error) {
	if command.CommandID == "" || command.SellerUserID <= 0 || command.OperatorUserID <= 0 {
		return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.InvalidArgument, "coin seller stock command is incomplete")
	}
	if command.SellerCountryID <= 0 || command.SellerRegionID <= 0 {
		return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.InvalidArgument, "seller country and region are required")
	}
	if len(command.CommandID) > 128 {
		return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.InvalidArgument, "command_id is too long")
	}
	if command.CoinAmount <= 0 {
		return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.CoinSellerStockAmountInvalid, "coin_amount must be positive")
	}
	command.StockType = ledger.NormalizeCoinSellerStockType(command.StockType)
	if command.StockType == "" {
		return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.CoinSellerStockTypeInvalid, "stock_type is invalid")
	}
	command.PaidCurrencyCode = strings.ToUpper(strings.TrimSpace(command.PaidCurrencyCode))
	command.PaymentRef = strings.TrimSpace(command.PaymentRef)
	command.EvidenceRef = strings.TrimSpace(command.EvidenceRef)
	command.Reason = strings.TrimSpace(command.Reason)
	if len(command.PaidCurrencyCode) > 8 || len(command.PaymentRef) > 128 || len(command.EvidenceRef) > 256 || len(command.Reason) > 512 {
		return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.InvalidArgument, "coin seller stock text fields are too long")
	}
	switch command.StockType {
	case ledger.StockTypeUSDTPurchase, ledger.StockTypeUSDTDeduction:
		if command.PaidCurrencyCode == "" {
			command.PaidCurrencyCode = ledger.PaidCurrencyUSDT
		}
		if command.PaidCurrencyCode != ledger.PaidCurrencyUSDT || command.PaidAmountMicro <= 0 {
			return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.CoinSellerStockAmountInvalid, "usdt stock adjustment requires paid amount")
		}
	case ledger.StockTypeCoinCompensation:
		if command.PaidCurrencyCode != "" || command.PaidAmountMicro != 0 || command.PaymentRef != "" {
			return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.CoinSellerStockAmountInvalid, "coin compensation must not include paid amount")
		}
	default:
		return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.CoinSellerStockTypeInvalid, "stock_type is invalid")
	}
	if s.repository == nil {
		return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	ctx = appcode.WithContext(ctx, command.AppCode)

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

// TransferCoinFromSeller 执行币商专用金币转普通金币；身份和区域都由 gateway/user-service 校验并传入。
func (s *Service) TransferCoinFromSeller(ctx context.Context, command ledger.CoinSellerTransferCommand) (ledger.CoinSellerTransferReceipt, error) {
	if command.CommandID == "" || command.SellerUserID <= 0 || command.TargetUserID <= 0 || command.Amount <= 0 {
		return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.InvalidArgument, "coin seller transfer command is incomplete")
	}
	if command.SellerRegionID <= 0 || command.TargetRegionID <= 0 {
		return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.InvalidArgument, "seller and target region are required")
	}
	if command.TargetCountryID <= 0 {
		return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.InvalidArgument, "target country is required")
	}
	if command.SellerRegionID != command.TargetRegionID {
		return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.Conflict, "seller and target region must match")
	}
	if strings.TrimSpace(command.Reason) == "" {
		return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.InvalidArgument, "reason is required")
	}
	if s.repository == nil {
		return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	command.Reason = strings.TrimSpace(command.Reason)
	ctx = appcode.WithContext(ctx, command.AppCode)

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

// TransferCoinSellerStockToChild 执行父子币商专用金币库存转账；父子关系和权限由 gateway 在调用前校验。
func (s *Service) TransferCoinSellerStockToChild(ctx context.Context, command ledger.CoinSellerSubTransferCommand) (ledger.CoinSellerSubTransferReceipt, error) {
	if command.CommandID == "" || command.ParentUserID <= 0 || command.ChildUserID <= 0 || command.Amount <= 0 {
		return ledger.CoinSellerSubTransferReceipt{}, xerr.New(xerr.InvalidArgument, "coin seller sub transfer command is incomplete")
	}
	if command.ParentUserID == command.ChildUserID {
		return ledger.CoinSellerSubTransferReceipt{}, xerr.New(xerr.InvalidArgument, "parent and child must be different")
	}
	if command.RegionID <= 0 {
		return ledger.CoinSellerSubTransferReceipt{}, xerr.New(xerr.InvalidArgument, "region_id is required")
	}
	command.Reason = strings.TrimSpace(command.Reason)
	if command.Reason == "" {
		command.Reason = "coin seller sub transfer"
	}
	if len(command.CommandID) > 128 || len(command.Reason) > 512 {
		return ledger.CoinSellerSubTransferReceipt{}, xerr.New(xerr.InvalidArgument, "coin seller sub transfer text fields are too long")
	}
	if s.repository == nil {
		return ledger.CoinSellerSubTransferReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	ctx = appcode.WithContext(ctx, command.AppCode)

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

// ListCoinSellerSalaryExchangeRateTiers 返回指定区域的工资转币商比例区间；gateway 用它给 H5 展示预计到账金币。
func (s *Service) ListCoinSellerSalaryExchangeRateTiers(ctx context.Context, appCode string, regionID int64, includeDisabled bool) ([]ledger.CoinSellerSalaryExchangeRateTier, error) {
	if regionID <= 0 {
		return nil, xerr.New(xerr.InvalidArgument, "region_id is required")
	}
	if s.repository == nil {
		return nil, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	appCode = appcode.Normalize(appCode)
	ctx = appcode.WithContext(ctx, appCode)
	return s.repository.ListCoinSellerSalaryExchangeRateTiers(ctx, appCode, regionID, includeDisabled)
}

// ExchangeSalaryToCoin 校验工资兑换命令；身份归属由 gateway 校验，wallet 只接受明确的工资资产和正向美分金额。
func (s *Service) ExchangeSalaryToCoin(ctx context.Context, command ledger.SalaryExchangeCommand) (ledger.SalaryExchangeReceipt, error) {
	if command.CommandID == "" || command.UserID <= 0 || command.SalaryUSDMinor <= 0 {
		return ledger.SalaryExchangeReceipt{}, xerr.New(xerr.InvalidArgument, "salary exchange command is incomplete")
	}
	command.SalaryAssetType = strings.ToUpper(strings.TrimSpace(command.SalaryAssetType))
	if !ledger.ValidSalaryAssetType(command.SalaryAssetType) {
		return ledger.SalaryExchangeReceipt{}, xerr.New(xerr.InvalidArgument, "salary_asset_type is invalid")
	}
	command.Reason = strings.TrimSpace(command.Reason)
	if command.Reason == "" {
		command.Reason = "salary exchange"
	}
	if len(command.CommandID) > 128 || len(command.Reason) > 512 {
		return ledger.SalaryExchangeReceipt{}, xerr.New(xerr.InvalidArgument, "salary exchange text fields are too long")
	}
	if s.repository == nil {
		return ledger.SalaryExchangeReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	ctx = appcode.WithContext(ctx, command.AppCode)

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

// TransferSalaryToCoinSeller 校验工资转币商命令；比例区间命中和双边入账由 repository 在同一事务内完成。
func (s *Service) TransferSalaryToCoinSeller(ctx context.Context, command ledger.SalaryTransferToCoinSellerCommand) (ledger.SalaryTransferToCoinSellerReceipt, error) {
	if command.CommandID == "" || command.SourceUserID <= 0 || command.SellerUserID <= 0 || command.SalaryUSDMinor <= 0 {
		return ledger.SalaryTransferToCoinSellerReceipt{}, xerr.New(xerr.InvalidArgument, "salary transfer command is incomplete")
	}
	if command.RegionID <= 0 {
		return ledger.SalaryTransferToCoinSellerReceipt{}, xerr.New(xerr.InvalidArgument, "region_id is required")
	}
	command.SalaryAssetType = strings.ToUpper(strings.TrimSpace(command.SalaryAssetType))
	if !ledger.ValidSalaryAssetType(command.SalaryAssetType) {
		return ledger.SalaryTransferToCoinSellerReceipt{}, xerr.New(xerr.InvalidArgument, "salary_asset_type is invalid")
	}
	command.Reason = strings.TrimSpace(command.Reason)
	if command.Reason == "" {
		command.Reason = "salary transfer"
	}
	if len(command.CommandID) > 128 || len(command.Reason) > 512 {
		return ledger.SalaryTransferToCoinSellerReceipt{}, xerr.New(xerr.InvalidArgument, "salary transfer text fields are too long")
	}
	if s.repository == nil {
		return ledger.SalaryTransferToCoinSellerReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	ctx = appcode.WithContext(ctx, command.AppCode)

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