<?php

namespace App\Console\Commands;

use App\Models\Draw;
use Carbon\Carbon;
use Illuminate\Console\Command;
use App\Services\LotterySettings;
use App\Services\Draw\DrawPlannerService;

/**
 * PRD §17.2：校验期号计划相邻开奖时刻间隔是否符合 interval_minutes（默认 5 分钟）。
 */
final class LotteryPerfDrawScheduleAuditCommand extends Command
{
    protected $signature = 'lottery:perf-draw-schedule-audit
                            {--samples=48 : 抽检相邻期数}
                            {--tolerance-seconds=60 : 允许偏差（秒）}';

    protected $description = 'Audit draw_time spacing for schedule punctuality (§17.2)';

    public function handle(DrawPlannerService $planner): int
    {
        $samples = max(2, (int) $this->option('samples'));
        $tolerance = max(0, (int) $this->option('tolerance-seconds'));
        $intervalMinutes = LotterySettings::drawIntervalMinutes();
        $expectedSeconds = $intervalMinutes * 60;

        $planner->ensureBuffer(Carbon::now('UTC'));

        $nowUtc = Carbon::now('UTC');
        $horizon = $nowUtc->copy()->addDays(14);

        $businessDate = Draw::query()
            ->whereNotNull('draw_time')
            ->where('draw_time', '>', $nowUtc)
            ->where('draw_time', '<=', $horizon)
            ->where('business_date', '<', '2090-01-01')
            ->orderByDesc('business_date')
            ->value('business_date');

        if ($businessDate === null) {
            $this->error('No upcoming draws found.');

            return self::FAILURE;
        }

        $times = Draw::query()
            ->where('business_date', $businessDate)
            ->whereNotNull('draw_time')
            ->orderBy('sequence_no')
            ->limit($samples + 1)
            ->pluck('draw_time')
            ->map(fn ($t) => Carbon::parse($t)->utc())
            ->values()
            ->all();

        $this->line('business_date='.$businessDate);

        if (count($times) < 2) {
            $this->error('Not enough draws to audit.');

            return self::FAILURE;
        }

        $violations = [];
        for ($i = 1; $i < count($times); $i++) {
            $delta = $times[$i]->diffInSeconds($times[$i - 1], absolute: true);
            if (abs($delta - $expectedSeconds) > $tolerance) {
                $violations[] = [
                    'pair' => ($i - 1).'→'.$i,
                    'delta_seconds' => $delta,
                    'expected_seconds' => $expectedSeconds,
                ];
            }
        }

        $this->info(sprintf(
            'interval_minutes=%d expected_gap=%ds tolerance=±%ds pairs_checked=%d',
            $intervalMinutes,
            $expectedSeconds,
            $tolerance,
            count($times) - 1,
        ));

        if ($violations === []) {
            $this->info('PASS — all checked gaps within tolerance.');

            return self::SUCCESS;
        }

        $this->error('FAIL — spacing violations:');
        $this->table(['pair', 'delta_seconds', 'expected_seconds'], $violations);

        return self::FAILURE;
    }
}
