<?php

declare(strict_types=1);

use App\Jobs\SnapshotProjectRoutingJob;
use App\Models\Project;
use App\Models\Tenant;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\Concerns\SharesSupplierPdo;

// NB: Job не оборачивает свою INSERT в DB::transaction() — иначе под
// DatabaseTransactions+SharesSupplierPdo (общий PDO между pgsql и pgsql_supplier)
// PostgreSQL возвращает «There is already an active transaction». Атомарность
// гарантирует INSERT ... ON CONFLICT DO NOTHING на уровне PG (идемпотентность).
uses(DatabaseTransactions::class);
uses(SharesSupplierPdo::class);

beforeEach(function () {
    Carbon::setTestNow('2026-05-27 15:02:00', 'UTC'); // 18:02 MSK = 15:02 UTC
});

afterEach(function () {
    Carbon::setTestNow();
});

it('creates snapshot for tomorrow with active projects only', function () {
    $tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]);
    $active = Project::factory()->for($tenant)->create([
        'is_active' => true,
        'delivery_days_mask' => 127,
        'daily_limit_target' => 10,
        'preflight_blocked_at' => null,
        'signal_type' => 'call',
        'signal_identifier' => '79161234567',
    ]);
    $inactive = Project::factory()->for($tenant)->create([
        'is_active' => false,
        'delivery_days_mask' => 127,
        'signal_type' => 'call',
        'signal_identifier' => '79169999999',
    ]);
    (new SnapshotProjectRoutingJob)->handle();
    $rows = DB::table('project_routing_snapshots')
        ->where('snapshot_date', '2026-05-28')->get();
    expect($rows)->toHaveCount(1);
    expect($rows->first()->project_id)->toBe($active->id);
});

it('excludes frozen tenants', function () {
    $tenant = Tenant::factory()->create(['frozen_by_balance_at' => now()]);
    Project::factory()->for($tenant)->create([
        'is_active' => true, 'delivery_days_mask' => 127, 'daily_limit_target' => 10, 'signal_type' => 'call', 'signal_identifier' => '79161234567',
    ]);
    (new SnapshotProjectRoutingJob)->handle();
    expect(DB::table('project_routing_snapshots')->count())->toBe(0);
});

it('excludes preflight_blocked projects', function () {
    $tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]);
    Project::factory()->for($tenant)->create([
        'is_active' => true, 'delivery_days_mask' => 127, 'daily_limit_target' => 10, 'signal_type' => 'call', 'signal_identifier' => '79161234567',
        'preflight_blocked_at' => now(),
    ]);
    (new SnapshotProjectRoutingJob)->handle();
    expect(DB::table('project_routing_snapshots')->count())->toBe(0);
});

it('excludes projects whose days_mask does not match tomorrow', function () {
    // 2026-05-28 — четверг (isoWeekday=4 → bit 1<<3 = 8). Тест: mask=4 (только среда).
    $tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]);
    Project::factory()->for($tenant)->create([
        'is_active' => true,
        'delivery_days_mask' => 4, // только среда
        'daily_limit_target' => 10,
        'signal_type' => 'call',
        'signal_identifier' => '79161234567',
    ]);
    (new SnapshotProjectRoutingJob)->handle();
    expect(DB::table('project_routing_snapshots')->count())->toBe(0);
});

it('uses effective_daily_limit_today as daily_limit when set (R-11/OPEN-5 variant A)', function () {
    $tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]);
    Project::factory()->for($tenant)->create([
        'is_active' => true, 'delivery_days_mask' => 127,
        'daily_limit_target' => 10,
        'effective_daily_limit_today' => 3, // override
        'signal_type' => 'call',
        'signal_identifier' => '79161234567',
    ]);
    (new SnapshotProjectRoutingJob)->handle();
    $row = DB::table('project_routing_snapshots')->first();
    expect($row->daily_limit)->toBe(3);
});

it('is idempotent — second run does not duplicate', function () {
    $tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]);
    Project::factory()->for($tenant)->create([
        'is_active' => true, 'delivery_days_mask' => 127, 'daily_limit_target' => 10, 'signal_type' => 'call', 'signal_identifier' => '79161234567',
    ]);
    (new SnapshotProjectRoutingJob)->handle();
    (new SnapshotProjectRoutingJob)->handle();
    expect(DB::table('project_routing_snapshots')->count())->toBe(1);
});
