package mysql

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

// GetWalletOverview 返回钱包首页摘要；开关放在 wallet-service 内，避免 gateway 硬编码账务能力。
func (r *Repository) GetWalletOverview(ctx context.Context, userID int64) (ledger.WalletOverview, error) {

	balances, err := r.GetBalances(ctx, userID, []string{
		ledger.AssetCoin,
		ledger.AssetHostSalaryUSD,
		ledger.AssetAgencySalaryUSD,
		ledger.AssetBDSalaryUSD,
		ledger.AssetAdminSalaryUSD,
	})
	if err != nil {
		return ledger.WalletOverview{}, err
	}
	return ledger.WalletOverview{
		Balances: balances,
		FeatureFlags: ledger.WalletFeatureFlags{
			RechargeEnabled:        true,
			DiamondExchangeEnabled: false,
		},
	}, nil
}

// GetWalletValueSummary 返回我的页钱包卡片需要的最小金币余额。
func (r *Repository) GetWalletValueSummary(ctx context.Context, userID int64) (ledger.WalletValueSummary, error) {
	balances, err := r.GetBalances(ctx, userID, []string{ledger.AssetCoin})
	if err != nil {
		return ledger.WalletValueSummary{}, err
	}
	if len(balances) == 0 {
		return ledger.WalletValueSummary{}, nil
	}
	return ledger.WalletValueSummary{
		CoinAmount:  balances[0].AvailableAmount,
		UpdatedAtMS: balances[0].UpdatedAtMs,
	}, nil
}

// GetUserGiftWall 读取送礼事务维护的收礼聚合表；它只表达已扣费成功的礼物事实。
func (r *Repository) GetUserGiftWall(ctx context.Context, userID int64) (ledger.UserGiftWall, error) {
	if r == nil || r.db == nil {
		return ledger.UserGiftWall{}, xerr.New(xerr.Unavailable, "mysql repository is not configured")
	}
	appCode := appcode.FromContext(ctx)
	rows, err := r.db.QueryContext(ctx, `
		SELECT gift_id, gift_name, resource_id, COALESCE(CAST(resource_snapshot_json AS CHAR), '{}'),
		       gift_type_code, COALESCE(CAST(presentation_json AS CHAR), '{}'), gift_count,
		       total_value, total_coin_value, total_diamond_value, total_gift_point, total_heat_value,
		       charge_asset_type, last_price_version, first_received_at_ms, last_received_at_ms, sort_order
		FROM user_gift_wall
		WHERE app_code = ? AND user_id = ?
		ORDER BY sort_order ASC, total_value DESC, last_received_at_ms DESC, gift_id ASC`,
		appCode, userID,
	)
	if err != nil {
		return ledger.UserGiftWall{}, err
	}
	defer rows.Close()

	wall := ledger.UserGiftWall{Items: make([]ledger.GiftWallItem, 0)}
	for rows.Next() {
		var item ledger.GiftWallItem
		if err := rows.Scan(
			&item.GiftID,
			&item.GiftName,
			&item.ResourceID,
			&item.ResourceSnapshotJSON,
			&item.GiftTypeCode,
			&item.PresentationJSON,
			&item.GiftCount,
			&item.TotalValue,
			&item.TotalCoinValue,
			&item.TotalDiamondValue,
			&item.TotalGiftPoint,
			&item.TotalHeatValue,
			&item.ChargeAssetType,
			&item.LastPriceVersion,
			&item.FirstReceivedAtMS,
			&item.LastReceivedAtMS,
			&item.SortOrder,
		); err != nil {
			return ledger.UserGiftWall{}, err
		}
		item.Resource = giftWallResourceFromJSON(item.ResourceSnapshotJSON)
		wall.Items = append(wall.Items, item)
		wall.GiftKindCount++
		wall.GiftTotalCount += item.GiftCount
		wall.TotalValue += item.TotalValue
		wall.TotalCoinValue += item.TotalCoinValue
		wall.TotalDiamondValue += item.TotalDiamondValue
		wall.TotalGiftPoint += item.TotalGiftPoint
		wall.TotalHeatValue += item.TotalHeatValue
	}
	if err := rows.Err(); err != nil {
		return ledger.UserGiftWall{}, err
	}
	return wall, nil
}

func giftWallResourceFromJSON(raw string) ledger.GiftWallResource {
	var resource ledger.GiftWallResource
	if strings.TrimSpace(raw) == "" {
		return resource
	}

	_ = json.Unmarshal([]byte(raw), &resource)
	return resource
}

// GetDiamondExchangeConfig 返回后台配置的钻石兑换规则，未配置时返回空列表而不是 gateway 默认值。
func (r *Repository) GetDiamondExchangeConfig(ctx context.Context, _ int64) ([]ledger.DiamondExchangeRule, error) {
	if r == nil || r.db == nil {
		return nil, xerr.New(xerr.Unavailable, "mysql repository is not configured")
	}
	return []ledger.DiamondExchangeRule{}, nil
}

// ListWalletTransactions 分页读取当前用户钱包分录，并带出交易业务类型。
func (r *Repository) ListWalletTransactions(ctx context.Context, query ledger.ListWalletTransactionsQuery) ([]ledger.WalletTransaction, int64, error) {
	if r == nil || r.db == nil {
		return nil, 0, xerr.New(xerr.Unavailable, "mysql repository is not configured")
	}
	ctx = contextWithCommandApp(ctx, query.AppCode)
	query.AppCode = appcode.FromContext(ctx)
	query.Page, query.PageSize = normalizePage(query.Page, query.PageSize)
	where := `WHERE e.app_code = ? AND e.user_id = ?`
	args := []any{query.AppCode, query.UserID}
	if strings.TrimSpace(query.AssetType) != "" {
		where += ` AND e.asset_type = ?`
		args = append(args, query.AssetType)
	}

	var total int64
	if err := r.db.QueryRowContext(ctx, `
		SELECT COUNT(*)
		FROM wallet_entries e
		`+where,
		args...,
	).Scan(&total); err != nil {
		return nil, 0, err
	}

	rows, err := r.db.QueryContext(ctx, `
		SELECT e.entry_id, e.transaction_id, wt.biz_type, e.asset_type,
		       e.available_delta, e.frozen_delta, e.available_after, e.frozen_after,
		       e.counterparty_user_id, e.room_id, e.created_at_ms
		FROM wallet_entries e
		JOIN wallet_transactions wt ON wt.app_code = e.app_code AND wt.transaction_id = e.transaction_id
		`+where+`
		ORDER BY e.created_at_ms DESC, e.entry_id DESC
		LIMIT ? OFFSET ?`,
		append(args, query.PageSize, resourceOffset(query.Page, query.PageSize))...,
	)
	if err != nil {
		return nil, 0, err
	}
	defer rows.Close()

	items := make([]ledger.WalletTransaction, 0, query.PageSize)
	for rows.Next() {
		var item ledger.WalletTransaction
		if err := rows.Scan(
			&item.EntryID,
			&item.TransactionID,
			&item.BizType,
			&item.AssetType,
			&item.AvailableDelta,
			&item.FrozenDelta,
			&item.AvailableAfter,
			&item.FrozenAfter,
			&item.CounterpartyUserID,
			&item.RoomID,
			&item.CreatedAtMS,
		); err != nil {
			return nil, 0, err
		}
		items = append(items, item)
	}
	return items, total, rows.Err()
}
