package dashboard

import (
	"context"
	"database/sql"
	"fmt"
	"strings"
	"time"
)

// ListCoinSellerRechargeBills 把 dashboard-cdc-worker 的 dealer_recharge 聚合事实暴露给 finance 充值流水。
// Yumi 当前只有按天/国家沉淀的币商充值金额，没有单笔订单号和币商用户 ID；这里生成稳定 synthetic id，
// 让列表、导出和区域筛选至少与总览/Databi 的金额口径完全一致。
func (s *MySQLExternalDashboardSource) ListCoinSellerRechargeBills(ctx context.Context, query CoinSellerRechargeBillQuery) ([]CoinSellerRechargeBill, int64, error) {
	if s == nil || s.db == nil {
		return nil, 0, fmt.Errorf("external dashboard source is not configured")
	}
	countryFilter, err := s.countryFilter(ctx, StatisticsQuery{RegionID: query.RegionID})
	if err != nil {
		return nil, 0, err
	}
	if countryFilter.Applied && len(countryFilter.Codes) == 0 {
		return []CoinSellerRechargeBill{}, 0, nil
	}
	requestTimezone := strings.TrimSpace(query.StatTZ)
	if requestTimezone == "" {
		requestTimezone = s.statTimezone
	}
	requestLocation, err := time.LoadLocation(requestTimezone)
	if err != nil {
		return nil, 0, fmt.Errorf("load external dashboard bill request timezone %s: %w", requestTimezone, err)
	}
	storageTimezone := s.statTimezone
	if _, err := time.LoadLocation(storageTimezone); err != nil {
		return nil, 0, fmt.Errorf("load external dashboard bill storage timezone %s: %w", storageTimezone, err)
	}
	startDate, endDate, _, _ := externalDashboardDateRange(StatisticsQuery{StartMS: query.StartMS, EndMS: query.EndMS}, requestLocation)
	whereSQL, args := s.periodMetricWhere(storageTimezone, startDate, endDate, countryFilter)
	whereSQL, args = s.appendCoinSellerBillKeyword(whereSQL, args, query.Keyword)

	page := query.Page
	if page < 1 {
		page = 1
	}
	pageSize := query.PageSize
	if pageSize < 1 {
		pageSize = 10
	}

	queryCtx, cancel := context.WithTimeout(ctx, s.requestTimeout)
	defer cancel()

	var total int64
	if err := s.db.QueryRowContext(queryCtx, `
SELECT COUNT(*) FROM (
  SELECT t.period_key, t.country_code
  FROM country_dashboard_period_metric t
  WHERE `+whereSQL+`
  GROUP BY t.period_key, t.country_code
  HAVING COALESCE(SUM(t.dealer_recharge), 0) <> 0
) bills`, args...).Scan(&total); err != nil {
		return nil, 0, fmt.Errorf("count external coin seller recharge bills for %s: %w", s.appCode, err)
	}
	if total == 0 {
		return []CoinSellerRechargeBill{}, 0, nil
	}

	rows, err := s.db.QueryContext(queryCtx, `
SELECT t.period_key, UPPER(t.country_code), MAX(t.country_name), CAST(COALESCE(SUM(t.dealer_recharge), 0) AS CHAR)
FROM country_dashboard_period_metric t
WHERE `+whereSQL+`
GROUP BY t.period_key, t.country_code
HAVING COALESCE(SUM(t.dealer_recharge), 0) <> 0
ORDER BY t.period_key DESC, t.country_code
LIMIT ? OFFSET ?`, append(args, pageSize, (page-1)*pageSize)...)
	if err != nil {
		return nil, 0, fmt.Errorf("query external coin seller recharge bills for %s: %w", s.appCode, err)
	}
	defer rows.Close()

	items := make([]CoinSellerRechargeBill, 0, pageSize)
	for rows.Next() {
		var periodKey string
		var countryCode string
		var countryName sql.NullString
		var amountText string
		if err := rows.Scan(&periodKey, &countryCode, &countryName, &amountText); err != nil {
			return nil, 0, fmt.Errorf("scan external coin seller recharge bill for %s: %w", s.appCode, err)
		}
		amount, err := decimalTextToMinor(amountText)
		if err != nil {
			return nil, 0, fmt.Errorf("parse external coin seller recharge amount for %s/%s/%s: %w", s.appCode, periodKey, countryCode, err)
		}
		createdAt, err := time.ParseInLocation("2006-01-02", periodKey, requestLocation)
		if err != nil {
			return nil, 0, fmt.Errorf("parse external coin seller recharge day for %s/%s/%s: %w", s.appCode, periodKey, countryCode, err)
		}
		countryCode = strings.ToUpper(strings.TrimSpace(countryCode))
		items = append(items, CoinSellerRechargeBill{
			TransactionID:  fmt.Sprintf("%s-dealer-recharge-%s-%s", s.appCode, periodKey, countryCode),
			Source:         "dealer_recharge",
			CountryCode:    countryCode,
			USDMinorAmount: amount,
			CreatedAtMS:    createdAt.UnixMilli(),
		})
	}
	if err := rows.Err(); err != nil {
		return nil, 0, fmt.Errorf("iterate external coin seller recharge bills for %s: %w", s.appCode, err)
	}
	return items, total, nil
}

func (s *MySQLExternalDashboardSource) appendCoinSellerBillKeyword(whereSQL string, args []any, rawKeyword string) (string, []any) {
	keyword := strings.TrimSpace(rawKeyword)
	if keyword == "" {
		return whereSQL, args
	}
	upperKeyword := strings.ToUpper(keyword)
	return whereSQL + `
  AND (CONCAT(?, '-dealer-recharge-', t.period_key, '-', UPPER(t.country_code)) = ?
       OR UPPER(t.country_code) = ?
       OR t.country_name LIKE ?)`, append(args, s.appCode, keyword, upperKeyword, "%"+keyword+"%")
}
