<?php

declare(strict_types=1);

use App\Exceptions\Supplier\SupplierClientException;
use App\Exceptions\Supplier\SupplierTransientException;
use App\Mail\SupplierCriticalAlertMail;
use App\Models\Project;
use App\Models\SupplierManualSyncQueue;
use App\Models\Tenant;
use App\Services\Supplier\Channel\Exceptions\TierEscalatedException;
use App\Services\Supplier\Channel\FailoverProjectChannel;
use App\Services\Supplier\Channel\SupplierProjectChannel;
use App\Services\Supplier\Dto\SupplierProjectDto;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Mail;

uses(RefreshDatabase::class);

test('Tier-1 fail + Tier-2 fail → Tier-3 escalation creates manual queue row + queues alert mail', function (): void {
    Mail::fake();
    config(['services.supplier.alert_email' => 'ops@liderra.local']);

    $tenant = Tenant::factory()->create();
    $project = Project::factory()->for($tenant)->create();

    $tier1 = mock(SupplierProjectChannel::class);
    $tier1->shouldReceive('listProjects')->andReturn([]);  // dedup-сверка: нет совпадений
    $tier1->shouldReceive('createProject')->andThrow(new SupplierClientException('Tier-1 mock fail'));

    $tier2 = mock(SupplierProjectChannel::class);
    $tier2->shouldReceive('createProject')->andThrow(new RuntimeException('Tier-2 manage-project.js selector break'));

    $channel = new FailoverProjectChannel($tier1, $tier2, app(Mailer::class));

    $dto = new SupplierProjectDto(
        platform: 'B1', signalType: 'site', uniqueKey: 'failover-smoke.example',
        limit: 1, workdays: [1, 2, 3, 4, 5], regions: [], regionsReverse: false, status: 'active',
    );

    expect(fn () => $channel->createProjectForLiderra($project, $dto))
        ->toThrow(TierEscalatedException::class);

    expect(SupplierManualSyncQueue::where('project_id', $project->id)->count())->toBe(1);

    Mail::assertQueued(SupplierCriticalAlertMail::class, fn ($m) => $m->alertType === 'manual_required');
});

test('Tier-1 transient fail (portal unreachable) bypasses Tier-2 and goes straight to Tier-3', function (): void {
    Mail::fake();
    config(['services.supplier.alert_email' => 'ops@liderra.local']);

    $tenant = Tenant::factory()->create();
    $project = Project::factory()->for($tenant)->create();

    $tier1 = mock(SupplierProjectChannel::class);
    $tier1->shouldReceive('listProjects')->andReturn([]);
    $tier1->shouldReceive('createProject')->andThrow(new SupplierTransientException('Connection refused'));

    $tier2 = mock(SupplierProjectChannel::class);
    $tier2->shouldNotReceive('createProject');  // КЛЮЧЕВОЕ — transient НЕ должен попасть в tier-2

    $channel = new FailoverProjectChannel($tier1, $tier2, app(Mailer::class));

    $dto = new SupplierProjectDto(
        platform: 'B1', signalType: 'site', uniqueKey: 'transient-smoke.example',
        limit: 1, workdays: [1, 2, 3, 4, 5], regions: [], regionsReverse: false, status: 'active',
    );

    expect(fn () => $channel->createProjectForLiderra($project, $dto))
        ->toThrow(TierEscalatedException::class);

    $row = SupplierManualSyncQueue::where('project_id', $project->id)->first();
    expect($row->failure_reason)->toBe('portal_unreachable');
});
