<?php

declare(strict_types=1);

namespace App\Console\Commands;

use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * Перестраивает project_routing_snapshots за указанную дату из текущего
 * live-состояния, ПЕРЕЗАПИСЫВАЯ существующий snapshot.
 *
 * В отличие от `snapshot:backfill` (идемпотентный — ON CONFLICT DO NOTHING),
 * `snapshot:rebuild` всегда сначала DELETE'ит существующий snapshot за дату,
 * затем создаёт новый. Используется для manual recovery после падения
 * `SnapshotProjectRoutingJob` cron'а с уже частично записанным snapshot'ом
 * (см. Task 2.10, Spec §4.2.6 fail-loud strategy).
 *
 * Fail-loud strategy:
 *   1. Heartbeat alarm via SchedulerHeartbeatTracker (Task 2.4).
 *   2. LeadRouter Log::error on missing snapshot (Task 2.5).
 *   3. Manual recovery: `php artisan snapshot:rebuild --date=YYYY-MM-DD`.
 *
 * NO fallback to live projects — explicit downtime + alert is safer
 * than silent regression.
 */
final class SnapshotRebuildCommand extends Command
{
    protected $signature = 'snapshot:rebuild {--date= : YYYY-MM-DD, по умолчанию сегодня}';

    protected $description = 'Перестроить project_routing_snapshots за указанную дату (DELETE+INSERT, для recovery)';

    public function handle(): int
    {
        $dateStr = (string) ($this->option('date') ?? Carbon::today('Europe/Moscow')->toDateString());
        $date = Carbon::parse($dateStr, 'Europe/Moscow');
        $weekdayBit = 1 << ($date->isoWeekday() - 1);

        // NB: НЕ оборачиваем в ->transaction() — это recovery-команда, half-done state
        // допустим (retry восстанавливает; на проде admin контроль). Wrapper конфликтует
        // с tests SharesSupplierPdo (shared PDO + nested transaction levels).
        $deleted = DB::connection('pgsql_supplier')
            ->table('project_routing_snapshots')
            ->where('snapshot_date', $dateStr)
            ->delete();

        $inserted = DB::connection('pgsql_supplier')->insert(<<<'SQL'
            INSERT INTO project_routing_snapshots (
                snapshot_date, project_id, tenant_id,
                daily_limit, delivery_days_mask, regions,
                signal_type, signal_identifier, sms_senders, sms_keyword,
                expected_volume
            )
            SELECT
                ?::date,
                p.id, p.tenant_id,
                COALESCE(p.effective_daily_limit_today, p.daily_limit_target),
                p.delivery_days_mask, p.regions,
                p.signal_type, p.signal_identifier, p.sms_senders, p.sms_keyword,
                COALESCE(p.effective_daily_limit_today, p.daily_limit_target)
            FROM projects p
            INNER JOIN tenants t ON t.id = p.tenant_id
            WHERE p.is_active = true
              AND (p.delivery_days_mask & ?::int) <> 0
              AND p.preflight_blocked_at IS NULL
              AND t.frozen_by_balance_at IS NULL
              AND t.deleted_at IS NULL
        SQL, [$dateStr, $weekdayBit]);

        $this->info("Snapshot rebuilt for {$dateStr}: deleted={$deleted}, inserted={$inserted}.");
        Log::warning('snapshot.rebuild', [
            'date' => $dateStr,
            'deleted' => $deleted,
            'inserted' => $inserted,
        ]);

        return self::SUCCESS;
    }
}
