<?php

namespace App\Services\AgentSettlement;

use App\Models\AdminUser;
use App\Support\AdminAgentSettlementScope;
use App\Support\AgentSettlementPeriodWindow;
use App\Support\PlayerFundingMode;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

/** 账期窗口内信用流水与占成流水笔数（关账前诊断）。 */
final class AgentSettlementPeriodPipelineService
{
    public function __construct(
        private readonly UnsettledTicketPeriodWarning $unsettledWarning,
        private readonly ShareLedgerScopedProfitAggregator $scopedProfitAggregator,
    ) {}
    /**
     * @param  Collection<int, object>  $periods  settlement_periods 行，须含 id、period_start、period_end、admin_site_id
     * @return array<int, array{
     *   credit_ledger_count: int,
     *   share_ledger_count: int,
     *   game_win_loss_total: int,
     *   win_loss_scope: 'platform'|'agent',
     *   basic_rebate_total: int,
     *   unsettled_ticket_count: int,
     * }>
     */
    public function countsForPeriods(Collection $periods, ?AdminUser $admin = null): array
    {
        if ($periods->isEmpty()) {
            return [];
        }

        $siteIds = $periods->pluck('admin_site_id')->map(static fn ($id): int => (int) $id)->unique()->all();
        $siteCodes = DB::table('admin_sites')
            ->whereIn('id', $siteIds)
            ->pluck('code', 'id');

        $out = [];
        $viewer = $this->scopedProfitAggregator->resolveViewer($admin);
        foreach ($periods as $period) {
            $periodId = (int) $period->id;
            $siteCode = (string) ($siteCodes[(int) $period->admin_site_id] ?? '');
            if ($siteCode === '') {
                $out[$periodId] = [
                    'credit_ledger_count' => 0,
                    'share_ledger_count' => 0,
                    'game_win_loss_total' => 0,
                    'win_loss_scope' => $viewer['scope'],
                    'basic_rebate_total' => 0,
                    'unsettled_ticket_count' => 0,
                ];

                continue;
            }

            [$start, $end] = AgentSettlementPeriodWindow::bounds(
                (string) $period->period_start,
                (string) $period->period_end,
            );

            $creditQuery = DB::table('credit_ledger as cl')
                ->join('players as p', function ($join): void {
                    $join->on('p.id', '=', 'cl.owner_id')
                        ->where('cl.owner_type', '=', 'player');
                })
                ->where('p.site_code', $siteCode)
                ->where('p.funding_mode', PlayerFundingMode::CREDIT)
                ->whereBetween('cl.created_at', [$start, $end]);

            if ($admin !== null) {
                AdminAgentSettlementScope::applyDirectPlayersToAlias($creditQuery, $admin, 'p');
            }

            $shareQuery = DB::table('share_ledger as sl')
                ->join('players as p', 'p.id', '=', 'sl.player_id')
                ->where('p.site_code', $siteCode)
                ->whereNull('sl.settlement_period_id')
                ->whereBetween('sl.settled_at', [$start, $end])
                ->whereNull('sl.reversal_of_id');

            if ($admin !== null) {
                AdminAgentSettlementScope::applyDirectPlayersToAlias($shareQuery, $admin, 'p');
            }

            $shareAgg = (clone $shareQuery)
                ->selectRaw('COUNT(*) as share_ledger_count')
                ->selectRaw('COALESCE(SUM(sl.basic_rebate), 0) as basic_rebate_total')
                ->first();

            $scopedWinLoss = $viewer['scope'] === 'platform'
                ? $this->scopedProfitAggregator->sumRawGameWinLoss($shareQuery)
                : $this->scopedProfitAggregator->sumForShareQuery($shareQuery, $viewer['key']);

            $unsettled = $this->unsettledWarning->countForSite(
                (int) $period->admin_site_id,
                (string) $period->period_start,
                (string) $period->period_end,
            );

            $out[$periodId] = [
                'credit_ledger_count' => (int) $creditQuery->count(),
                'share_ledger_count' => (int) ($shareAgg->share_ledger_count ?? 0),
                'game_win_loss_total' => $scopedWinLoss,
                'win_loss_scope' => $viewer['scope'],
                'basic_rebate_total' => (int) ($shareAgg->basic_rebate_total ?? 0),
                'unsettled_ticket_count' => $unsettled['count'],
            ];
        }

        return $out;
    }
}
