<?php

namespace App\Http\Controllers\Api\V1\Admin\Draw;

use App\Models\AdminUser;
use App\Models\Draw;
use App\Models\TicketItem;
use App\Models\TicketOrder;
use Illuminate\Http\Request;
use App\Support\AdminApiList;
use App\Support\AdminScopeContext;
use App\Support\AdminDrawApiPresenter;
use App\Support\AdminDrawResponsePolicy;
use App\Support\AdminScopePolicy;
use App\Services\LotterySettings;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;

/**
 * GET /api/v1/admin/draws — 期号列表。
 */
final class AdminDrawIndexController extends Controller
{
    public function __invoke(Request $request): JsonResponse
    {
        $admin = $request->lotteryAdmin();
        abort_if($admin === null, 401);

        $p = AdminApiList::readPaging($request);
        $drawNo = trim((string) $request->query('draw_no', ''));
        $status = trim((string) $request->query('status', ''));
        $scope = AdminScopePolicy::resolveContext($request, $admin);

        $q = Draw::query()->orderByDesc('draw_time')->orderByDesc('id');

        if ($drawNo !== '') {
            $q->where('draw_no', 'like', '%'.$drawNo.'%');
        }

        if ($status !== '') {
            $q->where('status', $status);
        }

        /** @var LengthAwarePaginator $paginator */
        $paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']);

        $statsByDrawId = AdminDrawResponsePolicy::canViewDrawFinance($admin)
            ? $this->aggregateListStats(
                $paginator->getCollection()->pluck('id')->map(fn ($id) => (int) $id)->all(),
                $scope,
            )
            : [];

        return AdminApiList::jsonWith(
            $paginator,
            fn (Draw $row): array => AdminDrawApiPresenter::listRow(
                $row,
                $statsByDrawId[(int) $row->id] ?? null,
                $admin,
            ),
            [
                'schedule' => [
                    'timezone' => LotterySettings::drawTimezone(),
                    'interval_minutes' => LotterySettings::drawIntervalMinutes(),
                    'betting_window_seconds' => LotterySettings::drawBettingWindowSeconds(),
                    'close_before_draw_seconds' => LotterySettings::drawCloseBeforeDrawSeconds(),
                ],
                'capabilities' => AdminDrawResponsePolicy::capabilities($admin),
            ],
        );
    }

    /**
     * @param  list<int>  $drawIds
     * @return array<int, array{total_bet_minor: int, total_payout_minor: int, profit_loss_minor: int}>
     */
    private function aggregateListStats(array $drawIds, AdminScopeContext $scope): array
    {
        if ($drawIds === []) {
            return [];
        }

        $betQuery = TicketOrder::query()->whereIn('draw_id', $drawIds);
        $this->scopeOrdersToVisiblePlayers($betQuery, $scope);
        $betByDraw = $betQuery
            ->groupBy('draw_id')
            ->selectRaw('draw_id, COALESCE(SUM(total_actual_deduct), 0) AS total_bet')
            ->pluck('total_bet', 'draw_id');

        $payoutQuery = TicketItem::query()->whereIn('draw_id', $drawIds);
        $this->scopeTicketItemsToVisiblePlayers($payoutQuery, $scope);
        $payoutRows = $payoutQuery
            ->groupBy('draw_id')
            ->selectRaw(
                'draw_id, COALESCE(SUM(win_amount), 0) AS win, COALESCE(SUM(jackpot_win_amount), 0) AS jackpot',
            )
            ->get()
            ->keyBy('draw_id');

        $stats = [];
        foreach ($drawIds as $drawId) {
            $bet = (int) ($betByDraw[$drawId] ?? $betByDraw[(string) $drawId] ?? 0);
            $payoutRow = $payoutRows->get($drawId) ?? $payoutRows->get((string) $drawId);
            $payout = (int) ($payoutRow->win ?? 0) + (int) ($payoutRow->jackpot ?? 0);
            $stats[$drawId] = [
                'total_bet_minor' => $bet,
                'total_payout_minor' => $payout,
                'profit_loss_minor' => $bet - $payout,
            ];
        }

        return $stats;
    }

    /**
     * @param  \Illuminate\Database\Eloquent\Builder<TicketOrder>  $query
     */
    private function scopeOrdersToVisiblePlayers($query, AdminScopeContext $scope): void
    {
        if ($scope->isSuperAdmin() && $scope->effectiveRequestedAgentNodeId() === null) {
            return;
        }

        $query->whereHas('player', function ($playerQuery) use ($scope): void {
            AdminScopePolicy::applyPlayerFilters($playerQuery, $scope);
        });
    }

    /**
     * @param  \Illuminate\Database\Eloquent\Builder<TicketItem>  $query
     */
    private function scopeTicketItemsToVisiblePlayers($query, AdminScopeContext $scope): void
    {
        if ($scope->isSuperAdmin() && $scope->effectiveRequestedAgentNodeId() === null) {
            return;
        }

        $query->whereHas('player', function ($playerQuery) use ($scope): void {
            AdminScopePolicy::applyPlayerFilters($playerQuery, $scope);
        });
    }

}
