<?php

declare(strict_types=1);

namespace App\Jobs;

use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * Daily 18:02 МСК snapshot — фиксирует состояние всех eligible Лидерра-проектов
 * на завтрашний день (slepok №NЛ по канону спека §0).
 * Spec: docs/superpowers/specs/2026-05-26-slepok-routing-protection-design.md §4.2.2.
 */
final class SnapshotProjectRoutingJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public const DB_CONNECTION = 'pgsql_supplier'; // BYPASSRLS

    public function handle(): void
    {
        $snapshotDate = Carbon::tomorrow('Europe/Moscow')->toDateString();
        $weekdayBit = 1 << (Carbon::tomorrow('Europe/Moscow')->isoWeekday() - 1);

        // NB: Без внешнего transaction() — атомарность гарантирует INSERT ... ON CONFLICT
        // на уровне PG. Внешний transaction() ломается при тестах под DatabaseTransactions
        // + SharesSupplierPdo (общий PDO pgsql/pgsql_supplier → PG ругается «active transaction»).
        $exists = DB::connection(self::DB_CONNECTION)
            ->table('project_routing_snapshots')
            ->where('snapshot_date', $snapshotDate)
            ->exists();
        if ($exists) {
            Log::info('snapshot.already_exists', ['date' => $snapshotDate]);

            return;
        }

        $count = DB::connection(self::DB_CONNECTION)->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
            ON CONFLICT (snapshot_date, project_id) DO NOTHING
        SQL, [$snapshotDate, $weekdayBit]);

        Log::info('snapshot.created', ['date' => $snapshotDate, 'rows' => $count]);
    }
}
