<?php

namespace App\Services\Admin;

use App\Models\Draw;
use App\Models\RiskPoolLockLog;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

/**
 * 风险占用流水查询：按号码明细或按注单聚合。
 */
final class AdminRiskPoolLockLogQueryService
{
    /**
     * @return LengthAwarePaginator<int, object>
     */
    public function paginateEntries(Draw $draw, Request $request, int $page, int $perPage): LengthAwarePaginator
    {
        $action = trim((string) $request->query('action_type', ''));
        $number = trim((string) $request->query('normalized_number', ''));
        $ticketItemId = (int) $request->integer('ticket_item_id', 0);

        $q = RiskPoolLockLog::query()
            ->where('draw_id', $draw->id)
            ->with(['ticketItem:id,ticket_no,play_code,player_id'])
            ->orderByDesc('created_at')
            ->orderByDesc('id');

        if ($action !== '' && in_array($action, ['lock', 'release'], true)) {
            $q->where('action_type', $action);
        }

        if ($number !== '' && preg_match('/^[0-9]{4}$/', $number) === 1) {
            $q->where('normalized_number', $number);
        }

        if ($ticketItemId > 0) {
            $q->where('ticket_item_id', $ticketItemId);
        }

        return $q->paginate($perPage, ['*'], 'page', $page);
    }

    /**
     * @return LengthAwarePaginator<int, object>
     */
    public function paginateByTicket(Draw $draw, Request $request, int $page, int $perPage): LengthAwarePaginator
    {
        $action = trim((string) $request->query('action_type', ''));
        $number = trim((string) $request->query('normalized_number', ''));
        $ticketItemId = (int) $request->integer('ticket_item_id', 0);

        $bindings = ['draw_id' => $draw->id];
        $filters = 'l.draw_id = :draw_id AND l.ticket_item_id IS NOT NULL';

        if ($action !== '' && in_array($action, ['lock', 'release'], true)) {
            $filters .= ' AND l.action_type = :action_type';
            $bindings['action_type'] = $action;
        }

        if ($number !== '' && preg_match('/^[0-9]{4}$/', $number) === 1) {
            $filters .= ' AND l.normalized_number = :normalized_number';
            $bindings['normalized_number'] = $number;
        }

        if ($ticketItemId > 0) {
            $filters .= ' AND l.ticket_item_id = :ticket_item_id';
            $bindings['ticket_item_id'] = $ticketItemId;
        }

        $driver = DB::connection()->getDriverName();
        $lockCountExpr = $driver === 'sqlite'
            ? "SUM(CASE WHEN l.action_type = 'lock' THEN 1 ELSE 0 END)"
            : "COUNT(*) FILTER (WHERE l.action_type = 'lock')";
        $releaseCountExpr = $driver === 'sqlite'
            ? "SUM(CASE WHEN l.action_type = 'release' THEN 1 ELSE 0 END)"
            : "COUNT(*) FILTER (WHERE l.action_type = 'release')";
        $lockAmountExpr = $driver === 'sqlite'
            ? "COALESCE(SUM(CASE WHEN l.action_type = 'lock' THEN l.amount ELSE 0 END), 0)"
            : "COALESCE(SUM(l.amount) FILTER (WHERE l.action_type = 'lock'), 0)";
        $releaseAmountExpr = $driver === 'sqlite'
            ? "COALESCE(SUM(CASE WHEN l.action_type = 'release' THEN l.amount ELSE 0 END), 0)"
            : "COALESCE(SUM(l.amount) FILTER (WHERE l.action_type = 'release'), 0)";

        $aggregateSql = <<<SQL
SELECT
    l.ticket_item_id AS ticket_item_id,
    ti.ticket_no AS ticket_no,
    ti.play_code AS play_code,
    ti.original_number AS original_number,
    ti.combination_count AS combination_count,
    ti.player_id AS player_id,
    {$lockCountExpr} AS lock_entry_count,
    {$releaseCountExpr} AS release_entry_count,
    {$lockAmountExpr} AS total_lock_amount,
    {$releaseAmountExpr} AS total_release_amount,
    COUNT(DISTINCT l.normalized_number) AS number_count,
    MAX(l.created_at) AS last_at
FROM risk_pool_lock_logs l
INNER JOIN ticket_items ti ON ti.id = l.ticket_item_id
WHERE {$filters}
GROUP BY l.ticket_item_id, ti.ticket_no, ti.play_code, ti.original_number, ti.combination_count, ti.player_id
SQL;

        $countSql = "SELECT COUNT(*) AS aggregate_count FROM ({$aggregateSql}) AS grouped";
        $total = (int) (DB::selectOne($countSql, $bindings)->aggregate_count ?? 0);
        $lastPage = max(1, (int) ceil($total / $perPage));
        $page = min(max($page, 1), $lastPage);
        $offset = ($page - 1) * $perPage;

        $items = DB::select(
            "{$aggregateSql} ORDER BY last_at DESC, ticket_item_id DESC LIMIT {$perPage} OFFSET {$offset}",
            $bindings,
        );

        return new LengthAwarePaginator(
            $items,
            $total,
            $perPage,
            $page,
            ['path' => $request->url(), 'query' => $request->query()],
        );
    }
}
