package mysql

import (
	"context"
	"fmt"
	"strings"
	"time"

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

// GetAgencyHostGiftStats 用固定数量的 GROUP BY 查询同时返回 Agency 汇总和每个 Host 的统计。
// POINT_DIAMOND 投影明确保留 host_base_amount 与 agency_amount：Host 列表只取前者，Agency
// owner 再走 agency/time 索引汇总后者，因此自营主播的一笔 100+20 会稳定呈现为 Host 100、Agency 20。
func (r *Repository) GetAgencyHostGiftStats(ctx context.Context, query ledger.AgencyHostGiftStatsQuery) (ledger.AgencyHostGiftStats, error) {
	if r == nil || r.db == nil {
		return ledger.AgencyHostGiftStats{}, xerr.New(xerr.Unavailable, "mysql repository is not configured")
	}
	if len(query.HostUserIDs) == 0 && query.AgencyUserID == 0 {
		return ledger.AgencyHostGiftStats{}, nil
	}
	stats := ledger.AgencyHostGiftStats{HostStats: make([]ledger.AgencyHostRevenueStats, 0, len(query.HostUserIDs))}
	hostIndexes := make(map[int64]int, len(query.HostUserIDs))
	for _, hostUserID := range query.HostUserIDs {
		if _, exists := hostIndexes[hostUserID]; exists {
			continue
		}
		hostIndexes[hostUserID] = len(stats.HostStats)
		stats.HostStats = append(stats.HostStats, ledger.AgencyHostRevenueStats{HostUserID: hostUserID})
	}
	if len(stats.HostStats) > 0 {
		startCycle := time.UnixMilli(query.StartAtMS).UTC().Format("2006-01")
		endCycle := time.UnixMilli(query.EndAtMS - 1).UTC().Format("2006-01")
		placeholders := make([]string, len(stats.HostStats))
		args := make([]any, 0, len(stats.HostStats)*2+10)
		args = append(args, appcode.FromContext(ctx))
		for index, host := range stats.HostStats {
			placeholders[index] = "?"
			args = append(args, host.HostUserID)
		}
		args = append(args, startCycle, endCycle, query.StartAtMS, query.EndAtMS)
		args = append(args, appcode.FromContext(ctx))
		for _, host := range stats.HostStats {
			args = append(args, host.HostUserID)
		}
		args = append(args, query.StartAtMS, query.EndAtMS)
		querySQL := fmt.Sprintf(`
		SELECT
		  host_user_id,
		  COALESCE(SUM(CASE WHEN income_type = 'SALARY_DIAMOND' THEN host_base_amount ELSE 0 END), 0),
		  COALESCE(SUM(CASE WHEN income_type = 'POINT_DIAMOND' THEN host_base_amount ELSE 0 END), 0),
		  COUNT(DISTINCT CASE WHEN sender_user_id > 0 THEN sender_user_id END),
		  MAX(CASE WHEN host_base_amount > 0 THEN 1 ELSE 0 END)
		FROM (
		  SELECT diamond_delta AS host_base_amount, user_id AS host_user_id, sender_user_id, 'SALARY_DIAMOND' AS income_type
		  FROM host_period_diamond_entries FORCE INDEX (idx_host_period_diamond_entries_user_cycle)
		  WHERE app_code = ? AND user_id IN (%s)
		    AND cycle_key BETWEEN ? AND ?
		    AND created_at_ms >= ? AND created_at_ms < ?
		  UNION ALL
		  SELECT host_base_amount, host_user_id, sender_user_id, 'POINT_DIAMOND' AS income_type
		  FROM point_diamond_gift_income_entries FORCE INDEX (idx_point_diamond_gift_host_time)
		  WHERE app_code = ? AND host_user_id IN (%s)
		    AND created_at_ms >= ? AND created_at_ms < ?
		) AS gift_income
		GROUP BY host_user_id`, strings.Join(placeholders, ","), strings.Join(placeholders, ","))
		rows, err := r.db.QueryContext(ctx, querySQL, args...)
		if err != nil {
			return ledger.AgencyHostGiftStats{}, err
		}
		for rows.Next() {
			var hostUserID int64
			var hostStats ledger.HostRevenueStats
			var gifted int64
			if err := rows.Scan(&hostUserID, &hostStats.DiamondEarnings, &hostStats.PointDiamondEarnings, &hostStats.GiftSenders, &gifted); err != nil {
				rows.Close()
				return ledger.AgencyHostGiftStats{}, err
			}
			index, exists := hostIndexes[hostUserID]
			if !exists {
				continue
			}
			stats.HostStats[index].Stats = hostStats
			stats.GiftIncome += hostStats.DiamondEarnings
			stats.PointDiamondHostIncome += hostStats.PointDiamondEarnings
			stats.GiftedHostCount += gifted
		}
		if err := rows.Close(); err != nil {
			return ledger.AgencyHostGiftStats{}, err
		}
		if err := rows.Err(); err != nil {
			return ledger.AgencyHostGiftStats{}, err
		}

		transferArgs := make([]any, 0, len(stats.HostStats)+11)
		transferArgs = append(transferArgs, ledger.AssetPoint, ledger.AssetPointDiamond, appcode.FromContext(ctx))
		for _, host := range stats.HostStats {
			transferArgs = append(transferArgs, host.HostUserID)
		}
		transferArgs = append(transferArgs,
			ledger.AssetPoint, ledger.AssetPointDiamond, query.StartAtMS, query.EndAtMS,
			bizTypePointExchangeToCoin, bizTypePointTransferToCoinSeller, bizTypeSalaryWithdrawalFreeze,
		)
		transferSQL := fmt.Sprintf(`
		SELECT
		  e.user_id,
		  COALESCE(SUM(CASE WHEN e.asset_type = ? THEN -e.available_delta ELSE 0 END), 0),
		  COALESCE(SUM(CASE WHEN e.asset_type = ? THEN -e.available_delta ELSE 0 END), 0)
		FROM wallet_entries e FORCE INDEX (idx_wallet_entries_asset_user_time)
		INNER JOIN wallet_transactions t
		  ON t.app_code = e.app_code AND t.transaction_id = e.transaction_id
		WHERE e.app_code = ? AND e.user_id IN (%s) AND e.asset_type IN (?, ?)
		  AND e.created_at_ms >= ? AND e.created_at_ms < ?
		  AND e.available_delta < 0
		  AND t.biz_type IN (?, ?, ?)
		GROUP BY e.user_id`, strings.Join(placeholders, ","))
		transferRows, err := r.db.QueryContext(ctx, transferSQL, transferArgs...)
		if err != nil {
			return ledger.AgencyHostGiftStats{}, err
		}
		for transferRows.Next() {
			var hostUserID int64
			var pointExchanged int64
			var pointDiamondExchanged int64
			if err := transferRows.Scan(&hostUserID, &pointExchanged, &pointDiamondExchanged); err != nil {
				transferRows.Close()
				return ledger.AgencyHostGiftStats{}, err
			}
			if index, exists := hostIndexes[hostUserID]; exists {
				stats.HostStats[index].Stats.DiamondExchanged = pointExchanged
				stats.HostStats[index].Stats.PointDiamondExchanged = pointDiamondExchanged
			}
		}
		if err := transferRows.Close(); err != nil {
			return ledger.AgencyHostGiftStats{}, err
		}
		if err := transferRows.Err(); err != nil {
			return ledger.AgencyHostGiftStats{}, err
		}
	}
	if query.AgencyUserID > 0 {
		// 该索引把 app/agency/time 放在最左侧；不扫描 wallet_entries JSON，也不受 Host 与 Agency
		// 同一用户时合并为一条 POINT_DIAMOND 分录的影响。
		err := r.db.QueryRowContext(ctx, `
			SELECT COALESCE(SUM(agency_amount), 0)
			FROM point_diamond_gift_income_entries FORCE INDEX (idx_point_diamond_gift_agency_time)
			WHERE app_code = ? AND agency_user_id = ?
			  AND created_at_ms >= ? AND created_at_ms < ?`,
			appcode.FromContext(ctx), query.AgencyUserID, query.StartAtMS, query.EndAtMS,
		).Scan(&stats.PointDiamondAgencyShareIncome)
		if err != nil {
			return ledger.AgencyHostGiftStats{}, err
		}
	}
	return stats, nil
}
