package mysql

import (
	"context"
	"database/sql"
	"encoding/json"
	"strings"

	"hyapp/pkg/appcode"
	"hyapp/services/wallet-service/internal/domain/ledger"
	resourcedomain "hyapp/services/wallet-service/internal/domain/resource"
)

func (r *Repository) receiptForGiftTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.Receipt, error) {
	var metadataJSON string
	var createdAtMS int64
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}'), created_at_ms
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON, &createdAtMS); err != nil {
		return ledger.Receipt{}, err
	}
	var metadata giftMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.Receipt{}, err
	}
	// wallet_transactions.created_at_ms 始终是 owner 权威时间。metadata 的副本只用于首次事务内
	// 直接构造回执；幂等回读无条件以主表覆盖，旧交易缺字段和异常副本都不能改变扣费归属。
	metadata.PaidAtMS = createdAtMS
	return receiptFromGiftMetadata(transactionID, metadata), nil
}

func receiptFromGiftMetadata(transactionID string, metadata giftMetadata) ledger.Receipt {
	chargeAssetType := ledger.NormalizeGiftChargeAssetType(metadata.ChargeAssetType)
	if metadata.RobotGift {
		chargeAssetType = ledger.AssetRobotCoin
	}
	chargeAmount := metadata.ChargeAmount
	if chargeAmount == 0 {
		chargeAmount = metadata.CoinSpent
	}
	return ledger.Receipt{
		BillingReceiptID:            metadata.BillingReceipt,
		TransactionID:               transactionID,
		CoinSpent:                   metadata.CoinSpent,
		ChargeAssetType:             chargeAssetType,
		ChargeAmount:                chargeAmount,
		GiftPointAdded:              0,
		HeatValue:                   metadata.HeatValue,
		GiftTypeCode:                metadata.GiftTypeCode,
		CPRelationType:              metadata.CPRelationType,
		GiftName:                    metadata.GiftName,
		GiftIconURL:                 metadata.GiftIconURL,
		GiftAnimationURL:            metadata.GiftAnimationURL,
		GiftEffectTypes:             normalizeGiftEffectTypes(metadata.GiftEffectTypes),
		PriceVersion:                metadata.PriceVersion,
		BalanceAfter:                metadata.BalanceAfter,
		BalanceVersion:              metadata.BalanceVersion,
		HostPeriodDiamondAdded:      metadata.HostPeriodDiamondAdded,
		HostIncomePolicyType:        metadata.HostIncomePolicyType,
		HostIncomeBalanceAfter:      metadata.HostIncomeBalanceAfter,
		IncomeAssetType:             metadata.IncomeAssetType,
		HostBaseAmount:              metadata.HostBaseAmount,
		AgencyAmount:                metadata.AgencyAmount,
		AgencyOwnerUserID:           metadata.TargetAgencyOwnerUserID,
		AgencyIncomeBalanceAfter:    metadata.AgencyIncomeBalanceAfter,
		HostIncomePolicyID:          metadata.HostSalaryPolicyID,
		HostIncomePolicyVersion:     metadata.HostSalaryPolicyVersion,
		HostPolicyCoefficient:       metadata.HostSalaryPolicyDiamondCoefficient,
		AgencyPointShareBPS:         metadata.AgencyPointShareBPS,
		HostPeriodCycleKey:          metadata.HostPeriodCycleKey,
		HostPointAdded:              metadata.HostPointAdded,
		HostPointBalanceAfter:       metadata.HostPointBalanceAfter,
		HostPointPolicyInstanceCode: metadata.HostPointPolicyInstanceCode,
		HostPointTemplateCode:       metadata.HostPointTemplateCode,
		HostPointTemplateVersion:    metadata.HostPointTemplateVersion,
		HostPointAssetType:          metadata.HostPointAssetType,
		EntitlementID:               strings.TrimSpace(metadata.EntitlementID),
		ChargeSource:                normalizeGiftChargeSource(metadata.ChargeSource, metadata.EntitlementID),
		GiftIncomeCoinAmount:        metadata.GiftIncomeCoinAmount,
		GiftIncomeBalanceAfter:      metadata.GiftIncomeBalanceAfter,
		RechargeSevenDayCoins:       metadata.RechargeSevenDayCoins,
		RechargeThirtyDayCoins:      metadata.RechargeThirtyDayCoins,
		LastRechargedAtMS:           metadata.LastRechargedAtMS,
		PaidAtMS:                    metadata.PaidAtMS,
	}
}

func giftDisplayIconURL(resource resourcedomain.Resource) string {

	if value := strings.TrimSpace(resource.PreviewURL); value != "" {
		return value
	}
	return strings.TrimSpace(resource.AssetURL)
}

func (r *Repository) receiptForTaskRewardTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.TaskRewardReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.TaskRewardReceipt{}, err
	}
	var metadata taskRewardMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.TaskRewardReceipt{}, err
	}
	return receiptFromTaskRewardMetadata(transactionID, metadata), nil
}

func receiptFromTaskRewardMetadata(transactionID string, metadata taskRewardMetadata) ledger.TaskRewardReceipt {
	return ledger.TaskRewardReceipt{
		TransactionID: transactionID,
		Balance: ledger.AssetBalance{
			AppCode:         metadata.AppCode,
			UserID:          metadata.TargetUserID,
			AssetType:       metadata.AssetType,
			AvailableAmount: metadata.BalanceAfter,
		},
		Amount:      metadata.Amount,
		GrantedAtMS: metadata.GrantedAtMS,
	}
}

func (r *Repository) receiptForLuckyGiftRewardTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.LuckyGiftRewardReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.LuckyGiftRewardReceipt{}, err
	}
	var metadata luckyGiftRewardMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.LuckyGiftRewardReceipt{}, err
	}
	return receiptFromLuckyGiftRewardMetadata(transactionID, metadata), nil
}

func receiptFromLuckyGiftRewardMetadata(transactionID string, metadata luckyGiftRewardMetadata) ledger.LuckyGiftRewardReceipt {
	return ledger.LuckyGiftRewardReceipt{
		TransactionID: transactionID,
		Balance: ledger.AssetBalance{
			AppCode:         metadata.AppCode,
			UserID:          metadata.TargetUserID,
			AssetType:       metadata.AssetType,
			AvailableAmount: metadata.BalanceAfter,
		},
		Amount:      metadata.Amount,
		GrantedAtMS: metadata.GrantedAtMS,
	}
}

func (r *Repository) receiptForWheelRewardTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.WheelRewardReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.WheelRewardReceipt{}, err
	}
	var metadata wheelRewardMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.WheelRewardReceipt{}, err
	}
	return receiptFromWheelRewardMetadata(transactionID, metadata), nil
}

func receiptFromWheelRewardMetadata(transactionID string, metadata wheelRewardMetadata) ledger.WheelRewardReceipt {
	return ledger.WheelRewardReceipt{
		TransactionID: transactionID,
		Balance: ledger.AssetBalance{
			AppCode:         metadata.AppCode,
			UserID:          metadata.TargetUserID,
			AssetType:       metadata.AssetType,
			AvailableAmount: metadata.BalanceAfter,
		},
		Amount:      metadata.Amount,
		GrantedAtMS: metadata.GrantedAtMS,
	}
}

func (r *Repository) receiptForRoomTurnoverRewardTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.RoomTurnoverRewardReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.RoomTurnoverRewardReceipt{}, err
	}
	var metadata roomTurnoverRewardMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.RoomTurnoverRewardReceipt{}, err
	}
	return receiptFromRoomTurnoverRewardMetadata(transactionID, metadata), nil
}

func receiptFromRoomTurnoverRewardMetadata(transactionID string, metadata roomTurnoverRewardMetadata) ledger.RoomTurnoverRewardReceipt {
	return ledger.RoomTurnoverRewardReceipt{
		TransactionID: transactionID,
		Balance: ledger.AssetBalance{
			AppCode:         metadata.AppCode,
			UserID:          metadata.TargetUserID,
			AssetType:       metadata.AssetType,
			AvailableAmount: metadata.BalanceAfter,
		},
		Amount:      metadata.Amount,
		GrantedAtMS: metadata.GrantedAtMS,
	}
}

func (r *Repository) receiptForInviteActivityRewardTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.InviteActivityRewardReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.InviteActivityRewardReceipt{}, err
	}
	var metadata inviteActivityRewardMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.InviteActivityRewardReceipt{}, err
	}
	return receiptFromInviteActivityRewardMetadata(transactionID, metadata), nil
}

func receiptFromInviteActivityRewardMetadata(transactionID string, metadata inviteActivityRewardMetadata) ledger.InviteActivityRewardReceipt {
	return ledger.InviteActivityRewardReceipt{
		TransactionID: transactionID,
		Balance: ledger.AssetBalance{
			AppCode:         metadata.AppCode,
			UserID:          metadata.TargetUserID,
			AssetType:       metadata.AssetType,
			AvailableAmount: metadata.BalanceAfter,
		},
		Amount:      metadata.Amount,
		GrantedAtMS: metadata.GrantedAtMS,
	}
}

func (r *Repository) receiptForAgencyOpeningRewardTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.AgencyOpeningRewardReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.AgencyOpeningRewardReceipt{}, err
	}
	var metadata agencyOpeningRewardMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.AgencyOpeningRewardReceipt{}, err
	}
	return receiptFromAgencyOpeningRewardMetadata(transactionID, metadata), nil
}

func receiptFromAgencyOpeningRewardMetadata(transactionID string, metadata agencyOpeningRewardMetadata) ledger.AgencyOpeningRewardReceipt {
	return ledger.AgencyOpeningRewardReceipt{
		TransactionID: transactionID,
		Balance: ledger.AssetBalance{
			AppCode:         metadata.AppCode,
			UserID:          metadata.TargetUserID,
			AssetType:       metadata.AssetType,
			AvailableAmount: metadata.BalanceAfter,
		},
		Amount:      metadata.Amount,
		GrantedAtMS: metadata.GrantedAtMS,
	}
}

func (r *Repository) receiptForGameTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.GameCoinChangeReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.GameCoinChangeReceipt{}, err
	}
	var metadata gameCoinMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.GameCoinChangeReceipt{}, err
	}
	return receiptFromGameMetadata(transactionID, metadata, false), nil
}

func receiptFromGameMetadata(transactionID string, metadata gameCoinMetadata, idempotentReplay bool) ledger.GameCoinChangeReceipt {
	return ledger.GameCoinChangeReceipt{
		TransactionID:    transactionID,
		BalanceAfter:     metadata.BalanceAfter,
		IdempotentReplay: idempotentReplay,
	}
}

func (r *Repository) receiptForCoinSellerStockTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.CoinSellerStockCreditReceipt, error) {
	row := tx.QueryRowContext(ctx,
		`SELECT seller_user_id, stock_type, coin_amount, paid_currency_code, paid_amount_micro,
		        counts_as_seller_recharge, balance_after, metadata_json, created_at_ms
		 FROM coin_seller_stock_records
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	)
	var receipt ledger.CoinSellerStockCreditReceipt
	var metadataJSON string
	if err := row.Scan(
		&receipt.SellerUserID,
		&receipt.StockType,
		&receipt.CoinAmount,
		&receipt.PaidCurrencyCode,
		&receipt.PaidAmountMicro,
		&receipt.CountsAsSellerRecharge,
		&receipt.BalanceAfter,
		&metadataJSON,
		&receipt.CreatedAtMS,
	); err != nil {
		return ledger.CoinSellerStockCreditReceipt{}, err
	}
	if metadataJSON != "" {
		var metadata coinSellerStockMetadata
		if err := json.Unmarshal([]byte(metadataJSON), &metadata); err == nil {
			receipt.SellerCountryID = metadata.SellerCountryID
			receipt.SellerRegionID = metadata.SellerRegionID
		}
	}
	receipt.TransactionID = transactionID
	return receipt, nil
}

func receiptFromCoinSellerStockMetadata(transactionID string, metadata coinSellerStockMetadata) ledger.CoinSellerStockCreditReceipt {
	return ledger.CoinSellerStockCreditReceipt{
		TransactionID:          transactionID,
		SellerUserID:           metadata.SellerUserID,
		SellerCountryID:        metadata.SellerCountryID,
		SellerRegionID:         metadata.SellerRegionID,
		StockType:              metadata.StockType,
		CoinAmount:             metadata.CoinAmount,
		PaidCurrencyCode:       metadata.PaidCurrencyCode,
		PaidAmountMicro:        metadata.PaidAmountMicro,
		CountsAsSellerRecharge: metadata.CountsAsSellerRecharge,
		BalanceAfter:           metadata.BalanceAfter,
		CreatedAtMS:            metadata.CreatedAtMS,
	}
}

func (r *Repository) receiptForCoinSellerTransferTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.CoinSellerTransferReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.CoinSellerTransferReceipt{}, err
	}
	var metadata coinSellerTransferMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.CoinSellerTransferReceipt{}, err
	}
	return receiptFromCoinSellerTransferMetadata(transactionID, metadata), nil
}

func receiptFromCoinSellerTransferMetadata(transactionID string, metadata coinSellerTransferMetadata) ledger.CoinSellerTransferReceipt {
	return ledger.CoinSellerTransferReceipt{
		TransactionID:              transactionID,
		SellerBalanceAfter:         metadata.SellerBalanceAfter,
		TargetBalanceAfter:         metadata.TargetBalanceAfter,
		Amount:                     metadata.Amount,
		RechargeSequence:           metadata.RechargeSequence,
		RechargeUSDMinor:           metadata.RechargeUSDMinor,
		RechargeCurrencyCode:       metadata.RechargeCurrencyCode,
		RechargePolicyID:           metadata.RechargePolicyID,
		RechargePolicyVersion:      metadata.RechargePolicyVersion,
		RechargePolicyCoinAmount:   metadata.RechargePolicyCoinAmount,
		RechargePolicyUSDMinorUnit: metadata.RechargePolicyUSDMinorAmount,
	}
}

func (r *Repository) receiptForCoinSellerSubTransferTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.CoinSellerSubTransferReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.CoinSellerSubTransferReceipt{}, err
	}
	var metadata coinSellerSubTransferMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.CoinSellerSubTransferReceipt{}, err
	}
	return receiptFromCoinSellerSubTransferMetadata(transactionID, metadata), nil
}

func receiptFromCoinSellerSubTransferMetadata(transactionID string, metadata coinSellerSubTransferMetadata) ledger.CoinSellerSubTransferReceipt {
	return ledger.CoinSellerSubTransferReceipt{
		TransactionID:      transactionID,
		ParentUserID:       metadata.ParentUserID,
		ChildUserID:        metadata.ChildUserID,
		ParentBalanceAfter: metadata.ParentBalanceAfter,
		ChildBalanceAfter:  metadata.ChildBalanceAfter,
		Amount:             metadata.Amount,
		CreatedAtMS:        metadata.CreatedAtMS,
	}
}

func (r *Repository) receiptForSalaryExchangeTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.SalaryExchangeReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.SalaryExchangeReceipt{}, err
	}
	var metadata salaryExchangeMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.SalaryExchangeReceipt{}, err
	}
	return receiptFromSalaryExchangeMetadata(transactionID, metadata), nil
}

func receiptFromSalaryExchangeMetadata(transactionID string, metadata salaryExchangeMetadata) ledger.SalaryExchangeReceipt {
	return ledger.SalaryExchangeReceipt{
		TransactionID:      transactionID,
		UserID:             metadata.UserID,
		SalaryAssetType:    metadata.SalaryAssetType,
		SalaryBalanceAfter: metadata.SalaryBalanceAfter,
		CoinBalanceAfter:   metadata.CoinBalanceAfter,
		SalaryUSDMinor:     metadata.SalaryUSDMinor,
		CoinAmount:         metadata.CoinAmount,
		CoinPerUSD:         metadata.CoinPerUSD,
		CreatedAtMS:        metadata.CreatedAtMS,
	}
}

func (r *Repository) receiptForSalaryTransferToCoinSellerTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.SalaryTransferToCoinSellerReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.SalaryTransferToCoinSellerReceipt{}, err
	}
	var metadata salaryTransferToCoinSellerMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.SalaryTransferToCoinSellerReceipt{}, err
	}
	return receiptFromSalaryTransferToCoinSellerMetadata(transactionID, metadata), nil
}

func receiptFromSalaryTransferToCoinSellerMetadata(transactionID string, metadata salaryTransferToCoinSellerMetadata) ledger.SalaryTransferToCoinSellerReceipt {
	return ledger.SalaryTransferToCoinSellerReceipt{
		TransactionID:            transactionID,
		SourceUserID:             metadata.SourceUserID,
		SellerUserID:             metadata.SellerUserID,
		SalaryAssetType:          metadata.SalaryAssetType,
		SourceSalaryBalanceAfter: metadata.SourceSalaryBalanceAfter,
		SellerBalanceAfter:       metadata.SellerBalanceAfter,
		SalaryUSDMinor:           metadata.SalaryUSDMinor,
		CoinAmount:               metadata.CoinAmount,
		CoinPerUSD:               metadata.CoinPerUSD,
		RateMinUSDMinor:          metadata.RateMinUSDMinor,
		RateMaxUSDMinor:          metadata.RateMaxUSDMinor,
		CreatedAtMS:              metadata.CreatedAtMS,
	}
}

func (r *Repository) receiptForSalaryWithdrawalTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.SalaryWithdrawalReceipt, error) {
	var metadataJSON string
	if err := tx.QueryRowContext(ctx,
		`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
		 FROM wallet_transactions
		 WHERE app_code = ? AND transaction_id = ?`,
		appcode.FromContext(ctx),
		transactionID,
	).Scan(&metadataJSON); err != nil {
		return ledger.SalaryWithdrawalReceipt{}, err
	}
	var metadata salaryWithdrawalMetadata
	if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
		return ledger.SalaryWithdrawalReceipt{}, err
	}
	return receiptFromSalaryWithdrawalMetadata(transactionID, metadata), nil
}

func receiptFromSalaryWithdrawalMetadata(transactionID string, metadata salaryWithdrawalMetadata) ledger.SalaryWithdrawalReceipt {
	return ledger.SalaryWithdrawalReceipt{
		TransactionID:           transactionID,
		UserID:                  metadata.UserID,
		SalaryAssetType:         metadata.SalaryAssetType,
		SalaryUSDMinor:          metadata.SalaryUSDMinor,
		PointFeeAmount:          metadata.PointFeeAmount,
		PointNetAmount:          metadata.PointNetAmount,
		PointsPerUSD:            metadata.PointsPerUSD,
		PointWithdrawFeeBPS:     metadata.PointWithdrawFeeBPS,
		PointPolicyInstanceCode: metadata.PointPolicyInstanceCode,
		GrossUSDMinor:           metadata.GrossUSDMinor,
		FeeUSDMinor:             metadata.FeeUSDMinor,
		NetUSDMinor:             metadata.NetUSDMinor,
		PointPolicyID:           metadata.PointPolicyID,
		PointPolicyVersion:      metadata.PointPolicyVersion,
		CoinsPerUSD:             metadata.CoinsPerUSD,
		AvailableAfter:          metadata.AvailableAfter,
		FrozenAfter:             metadata.FrozenAfter,
		Version:                 metadata.Version,
		CreatedAtMS:             metadata.CreatedAtMS,
	}
}
