<?php

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

use App\Http\Controllers\Controller;
use App\Services\AgentSettlement\SettlementPartyEnrichment;
use App\Support\AdminAgentSettlementScope;
use App\Support\ApiResponse;
use App\Support\PaginationTrait;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

final class AgentSettlementBillIndexController extends Controller
{
    use PaginationTrait;

    public function __construct(
        private readonly SettlementPartyEnrichment $partyEnrichment,
    ) {}

    public function __invoke(Request $request): JsonResponse
    {
        $admin = $request->lotteryAdmin();
        abort_if($admin === null, 401);

        $periodId = (int) $request->query('settlement_period_id', 0);
        $adminSiteId = (int) $request->query('admin_site_id', 0);

        $query = DB::table('settlement_bills as sb')
            ->leftJoin('settlement_periods as sp', 'sp.id', '=', 'sb.settlement_period_id')
            ->select([
                'sb.*',
                'sp.period_start',
                'sp.period_end',
                'sp.admin_site_id',
            ])
            ->orderByDesc('sb.id');

        if ($periodId > 0) {
            $query->where('sb.settlement_period_id', $periodId);
        }

        if ($adminSiteId > 0) {
            $query->where('sp.admin_site_id', $adminSiteId);
        }

        $billId = (int) $request->query('bill_id', 0);
        if ($billId > 0) {
            $query->where('sb.id', $billId);
        }

        $billType = (string) $request->query('bill_type', '');
        if ($billType !== '') {
            $query->where('sb.bill_type', $billType);
        }

        $scope = (string) $request->query('scope', '');
        match ($scope) {
            'pending_confirm' => $query->where('sb.status', 'pending_confirm'),
            'awaiting_payment' => $query
                ->whereIn('sb.status', ['confirmed', 'partial_paid', 'overdue'])
                ->where('sb.unpaid_amount', '>', 0),
            'settled' => $query->where('sb.status', 'settled'),
            'adjustment' => $query->whereIn('sb.bill_type', ['adjustment', 'reversal']),
            default => null,
        };

        $keyword = trim((string) $request->query('keyword', ''));
        if ($keyword !== '') {
            $this->applyKeywordFilter($query, $keyword);
        }

        AdminAgentSettlementScope::applyToBillsQuery($query, $admin, 'sb');

        $meta = $this->paginationMeta($request, defaultPerPage: 20, maxPerPage: 100);
        $paginator = $query->paginate($meta['per_page'], ['sb.*', 'sp.period_start', 'sp.period_end', 'sp.admin_site_id'], 'page', $meta['page']);

        /** @var Collection<int, object> $items */
        $items = collect($paginator->items());

        return ApiResponse::success([
            'items' => $this->partyEnrichment->enrichBillRows($items),
            'total' => $paginator->total(),
            'page' => $paginator->currentPage(),
            'per_page' => $paginator->perPage(),
        ]);
    }

    private function applyKeywordFilter(\Illuminate\Database\Query\Builder $query, string $keyword): void
    {
        $like = '%'.addcslashes($keyword, '%_\\').'%';

        $query->where(function (\Illuminate\Database\Query\Builder $outer) use ($keyword, $like): void {
            if (ctype_digit($keyword)) {
                $outer->orWhere('sb.id', (int) $keyword)
                    ->orWhere('sb.owner_id', (int) $keyword);
            }

            $outer->orWhere(function (\Illuminate\Database\Query\Builder $player) use ($like): void {
                $player->where('sb.owner_type', 'player')
                    ->whereExists(function (\Illuminate\Database\Query\Builder $exists) use ($like): void {
                        $exists->selectRaw('1')
                            ->from('players as p')
                            ->whereColumn('p.id', 'sb.owner_id')
                            ->where(function (\Illuminate\Database\Query\Builder $match) use ($like): void {
                                $match->where('p.username', 'like', $like)
                                    ->orWhere('p.site_player_id', 'like', $like);
                            });
                    });
            });

            $outer->orWhere(function (\Illuminate\Database\Query\Builder $agent) use ($like): void {
                $agent->where('sb.owner_type', 'agent')
                    ->whereExists(function (\Illuminate\Database\Query\Builder $exists) use ($like): void {
                        $exists->selectRaw('1')
                            ->from('agent_nodes as a')
                            ->whereColumn('a.id', 'sb.owner_id')
                            ->where(function (\Illuminate\Database\Query\Builder $match) use ($like): void {
                                $match->where('a.name', 'like', $like)
                                    ->orWhere('a.code', 'like', $like);
                            });
                    });
            });

            $outer->orWhere(function (\Illuminate\Database\Query\Builder $counter) use ($like): void {
                $counter->where('sb.counterparty_type', 'agent')
                    ->whereExists(function (\Illuminate\Database\Query\Builder $exists) use ($like): void {
                        $exists->selectRaw('1')
                            ->from('agent_nodes as a')
                            ->whereColumn('a.id', 'sb.counterparty_id')
                            ->where(function (\Illuminate\Database\Query\Builder $match) use ($like): void {
                                $match->where('a.name', 'like', $like)
                                    ->orWhere('a.code', 'like', $like);
                            });
                    });
            });
        });
    }
}
