<?php

declare(strict_types=1);

use App\Jobs\Billing\BalanceFrozenReminderJob;
use App\Mail\BalanceFrozenFinalMail;
use App\Mail\BalanceFrozenReminderMail;
use App\Models\PricingTier;
use App\Models\Project;
use App\Models\Tenant;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Tests\Concerns\SharesSupplierPdo;

// Изоляция: liderra_testing persistent — DatabaseTransactions откатывает default-pgsql,
// SharesSupplierPdo делает pgsql_supplier общим PDO (паттерн Спека B / Task 1.4).
// Per-tenant Mail-фильтры обязательны — DemoSeeder тенанты могут попасть в sweep
// (прецедент idempotent-fixup 55a1bc05).
uses(DatabaseTransactions::class);
uses(SharesSupplierPdo::class);

beforeEach(function () {
    // RLS-контекст (системный tenant 0).
    DB::statement("SELECT set_config('app.current_tenant_id', '0', true)");
    PricingTier::query()->create([
        'tier_no' => 1,
        'leads_in_tier' => null,
        'price_per_lead_kopecks' => 5000,
        'is_active' => true,
        'effective_from' => now(),
    ]);
});

it('sends reminder ~1 day after freeze', function () {
    Mail::fake();
    // frozen 25h назад — попадает в окно reminder (24-48h).
    Carbon::setTestNow('2026-05-25 12:00:00');
    $tenant = Tenant::factory()->create([
        'balance_rub' => '0.00',
        'frozen_by_balance_at' => Carbon::now()->subHours(25),
    ]);
    Project::factory()->for($tenant)->create(['is_active' => true, 'daily_limit_target' => 25]);

    (new BalanceFrozenReminderJob)->handle();

    Mail::assertQueued(BalanceFrozenReminderMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);
    Mail::assertNotQueued(BalanceFrozenFinalMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);
});

it('sends final ~3 days after freeze', function () {
    Mail::fake();
    // frozen 73h назад — попадает в окно final (72-96h).
    Carbon::setTestNow('2026-05-25 12:00:00');
    $tenant = Tenant::factory()->create([
        'balance_rub' => '0.00',
        'frozen_by_balance_at' => Carbon::now()->subHours(73),
    ]);
    Project::factory()->for($tenant)->create(['is_active' => true, 'daily_limit_target' => 25]);

    (new BalanceFrozenReminderJob)->handle();

    Mail::assertQueued(BalanceFrozenFinalMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);
    Mail::assertNotQueued(BalanceFrozenReminderMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);
});

it('sends nothing for freshly frozen tenant', function () {
    Mail::fake();
    // frozen 2h назад — окно ещё не открылось.
    Carbon::setTestNow('2026-05-25 12:00:00');
    $tenant = Tenant::factory()->create([
        'balance_rub' => '0.00',
        'frozen_by_balance_at' => Carbon::now()->subHours(2),
    ]);
    Project::factory()->for($tenant)->create(['is_active' => true, 'daily_limit_target' => 25]);

    (new BalanceFrozenReminderJob)->handle();

    Mail::assertNotQueued(BalanceFrozenReminderMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);
    Mail::assertNotQueued(BalanceFrozenFinalMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);
});

it('sends nothing in dead-zone between reminder and final windows (48-72h)', function () {
    Mail::fake();
    // frozen 60h назад — после reminder-окна (24-48h), до final-окна (72-96h).
    // matchWindow(60) → null. Пиннит разрыв: расширение reminder-окна до 72h
    // ошибочно выстрелит reminder здесь — тест это поймает.
    Carbon::setTestNow('2026-05-25 12:00:00');
    $tenant = Tenant::factory()->create([
        'balance_rub' => '0.00',
        'frozen_by_balance_at' => Carbon::now()->subHours(60),
    ]);
    Project::factory()->for($tenant)->create(['is_active' => true, 'daily_limit_target' => 25]);

    (new BalanceFrozenReminderJob)->handle();

    Mail::assertNotQueued(BalanceFrozenReminderMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);
    Mail::assertNotQueued(BalanceFrozenFinalMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);
});

it('sends nothing after final window closes (>96h)', function () {
    Mail::fake();
    // frozen 100h назад — за пределами final-окна (72-96h). matchWindow(100) → null.
    Carbon::setTestNow('2026-05-25 12:00:00');
    $tenant = Tenant::factory()->create([
        'balance_rub' => '0.00',
        'frozen_by_balance_at' => Carbon::now()->subHours(100),
    ]);
    Project::factory()->for($tenant)->create(['is_active' => true, 'daily_limit_target' => 25]);

    (new BalanceFrozenReminderJob)->handle();

    Mail::assertNotQueued(BalanceFrozenReminderMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);
    Mail::assertNotQueued(BalanceFrozenFinalMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);
});

it('is throttled — does not re-send reminder for same tenant in window', function () {
    Mail::fake();
    Carbon::setTestNow('2026-05-25 12:00:00');
    $tenant = Tenant::factory()->create([
        'balance_rub' => '0.00',
        'frozen_by_balance_at' => Carbon::now()->subHours(25),
    ]);
    Project::factory()->for($tenant)->create(['is_active' => true, 'daily_limit_target' => 25]);

    // Первый прогон — отправляет reminder.
    (new BalanceFrozenReminderJob)->handle();
    Mail::assertQueued(BalanceFrozenReminderMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);

    // Сброс fake и второй прогон в том же окне — повторного письма быть не должно.
    Mail::fake();
    (new BalanceFrozenReminderJob)->handle();
    Mail::assertNotQueued(BalanceFrozenReminderMail::class, fn ($mail) => $mail->tenant->id === $tenant->id);
});
