<?php

declare(strict_types=1);

use App\Jobs\Supplier\SyncSupplierProjectsJob;
use App\Models\Project;
use App\Models\Tenant;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Tests\Concerns\SharesSupplierPdo;

uses(DatabaseTransactions::class);
uses(SharesSupplierPdo::class);

/**
 * Task 2.6 — офлайн-батч обязан заказывать у поставщика по источнику ИЗ СЛЕПКА,
 * а не по live projects.* . Закрывает рассинхрон окна 18:02 (snapshot) → 18:05 (sync):
 * клиент мог сменить источник между двумя cron'ами, но завтрашний заказ уже зафиксирован
 * слепком (slepok-инвариант) — иначе поставщик заберёт лиды по НОВОМУ источнику,
 * а раздача доводит хвост по СТАРОМУ → рассинхрон денег.
 */
function insertTomorrowSmsSnapshot(
    Project $project,
    array $smsSenders,
    ?string $smsKeyword = null,
): void {
    $tomorrow = Carbon::tomorrow('Europe/Moscow')->toDateString();
    DB::table('project_routing_snapshots')->insert([
        'snapshot_date' => $tomorrow,
        'project_id' => $project->id,
        'tenant_id' => $project->tenant_id,
        'daily_limit' => 10,
        'delivery_days_mask' => 127,
        'regions' => '{}',
        'signal_type' => 'sms',
        'signal_identifier' => null,
        'sms_senders' => json_encode($smsSenders),
        'sms_keyword' => $smsKeyword,
        'expected_volume' => 10,
        'delivered_count' => 0,
        'created_at' => now(),
    ]);
}

it('батч заказывает по источнику из слепка, даже если live-источник сменили после слепка', function (): void {
    Carbon::setTestNow(Carbon::parse('2026-05-27 18:04:00', 'Europe/Moscow'));

    $tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]);
    $project = Project::factory()->for($tenant)->create([
        'is_active' => true,
        'signal_type' => 'sms',
        'signal_identifier' => null,
        'sms_senders' => ['Caranga'],
        'sms_keyword' => null,
    ]);
    // Снимок снят с источника Caranga.
    insertTomorrowSmsSnapshot($project, smsSenders: ['Caranga']);

    // ↓ Клиент сменил live-источник в окне 18:02→18:05 (после слепка).
    DB::table('projects')->where('id', $project->id)->update([
        'sms_senders' => json_encode(['NewSender']),
    ]);

    $projects = (new SyncSupplierProjectsJob)->collectEligibleProjects();

    $ours = $projects->where('id', $project->id);
    expect($ours)->toHaveCount(1);
    // Источник ИЗ СЛЕПКА (Caranga), не live (NewSender).
    expect((array) $ours->first()->sms_senders)->toBe(['Caranga']);

    Carbon::setTestNow();
});

it('батч переопределяет signal_identifier (site) значением слепка', function (): void {
    Carbon::setTestNow(Carbon::parse('2026-05-27 18:04:00', 'Europe/Moscow'));

    $tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]);
    $project = Project::factory()->for($tenant)->create([
        'is_active' => true,
        'signal_type' => 'site',
        'signal_identifier' => 'old-site.ru',
        'sms_senders' => null,
        'sms_keyword' => null,
    ]);
    $tomorrow = Carbon::tomorrow('Europe/Moscow')->toDateString();
    DB::table('project_routing_snapshots')->insert([
        'snapshot_date' => $tomorrow,
        'project_id' => $project->id,
        'tenant_id' => $project->tenant_id,
        'daily_limit' => 10,
        'delivery_days_mask' => 127,
        'regions' => '{}',
        'signal_type' => 'site',
        'signal_identifier' => 'old-site.ru',
        'sms_senders' => null,
        'sms_keyword' => null,
        'expected_volume' => 10,
        'delivered_count' => 0,
        'created_at' => now(),
    ]);

    DB::table('projects')->where('id', $project->id)->update([
        'signal_identifier' => 'new-site.ru',
    ]);

    $projects = (new SyncSupplierProjectsJob)->collectEligibleProjects();

    $ours = $projects->where('id', $project->id);
    expect($ours)->toHaveCount(1);
    expect($ours->first()->signal_identifier)->toBe('old-site.ru');

    Carbon::setTestNow();
});
