package mysql

import (
	"context"
	"sort"
	"strings"

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

// GetBalances 读取用户多资产余额；指定资产不存在时返回 0 投影，便于客户端稳定渲染。
func (r *Repository) GetBalances(ctx context.Context, userID int64, assetTypes []string) ([]ledger.AssetBalance, error) {
	if r == nil || r.db == nil {
		return nil, xerr.New(xerr.Unavailable, "mysql repository is not configured")
	}
	assetTypes = normalizeAssetTypes(assetTypes)
	appCode := appcode.FromContext(ctx)

	query := `SELECT app_code, user_id, asset_type, available_amount, frozen_amount, version, updated_at_ms
		FROM wallet_accounts WHERE app_code = ? AND user_id = ?`
	args := []any{appCode, userID}
	if len(assetTypes) > 0 {
		placeholders := strings.TrimRight(strings.Repeat("?,", len(assetTypes)), ",")
		query += " AND asset_type IN (" + placeholders + ")"
		for _, assetType := range assetTypes {
			args = append(args, assetType)
		}
	}
	query += " ORDER BY asset_type"

	rows, err := r.db.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	byAsset := make(map[string]ledger.AssetBalance)
	for rows.Next() {
		var balance ledger.AssetBalance
		if err := rows.Scan(&balance.AppCode, &balance.UserID, &balance.AssetType, &balance.AvailableAmount, &balance.FrozenAmount, &balance.Version, &balance.UpdatedAtMs); err != nil {
			return nil, err
		}
		byAsset[balance.AssetType] = balance
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}

	if len(assetTypes) == 0 {
		balances := make([]ledger.AssetBalance, 0, len(byAsset))
		for _, balance := range byAsset {
			balances = append(balances, balance)
		}
		sort.Slice(balances, func(i, j int) bool { return balances[i].AssetType < balances[j].AssetType })
		return balances, nil
	}

	balances := make([]ledger.AssetBalance, 0, len(assetTypes))
	for _, assetType := range assetTypes {
		if balance, ok := byAsset[assetType]; ok {
			balances = append(balances, balance)
			continue
		}
		balances = append(balances, ledger.AssetBalance{AppCode: appCode, UserID: userID, AssetType: assetType})
	}
	return balances, nil
}

func normalizeAssetTypes(assetTypes []string) []string {
	seen := make(map[string]bool, len(assetTypes))
	result := make([]string, 0, len(assetTypes))
	for _, assetType := range assetTypes {
		assetType = strings.ToUpper(strings.TrimSpace(assetType))
		if assetType == "" || seen[assetType] {
			continue
		}
		seen[assetType] = true
		result = append(result, assetType)
	}
	return result
}
