<?php

declare(strict_types=1);

use App\Models\Project;
use App\Models\SupplierManualSyncQueue;
use App\Models\SupplierProject;
use App\Models\Tenant;
use App\Models\User;
use App\Services\Supplier\Channel\SupplierProjectChannel;
use App\Services\Supplier\Dto\SupplierProjectDto;
use Illuminate\Foundation\Testing\DatabaseTransactions;

uses(DatabaseTransactions::class);

// EnsureSaasAdmin — стаб (Sprint 3F): в testing пропускает всех без проверки
// роли. actingAs нужен только чтобы $request->user() в manualQueueResolve дал
// id для resolved_by_user_id.

it('GET /api/admin/supplier-integration/manual-queue returns pending rows', function (): void {
    $this->actingAs(User::factory()->create());
    $tenant = Tenant::factory()->create();
    $project = Project::factory()->for($tenant)->create();

    SupplierManualSyncQueue::create([
        'project_id' => $project->id,
        'platform' => 'B1',
        'operation' => 'create',
        'payload_snapshot' => ['limit' => 10],
        'failure_reason' => 'contract_break',
        'status' => 'pending',
    ]);

    $r = $this->getJson('/api/admin/supplier-integration/manual-queue');

    $r->assertOk()
        ->assertJsonStructure(['queue' => [['id', 'project_id', 'platform', 'operation', 'payload_snapshot', 'failure_reason', 'created_at']]])
        ->assertJsonCount(1, 'queue');
});

it('GET excludes resolved rows', function (): void {
    $this->actingAs(User::factory()->create());
    $tenant = Tenant::factory()->create();
    $project = Project::factory()->for($tenant)->create();
    SupplierManualSyncQueue::create([
        'project_id' => $project->id, 'platform' => 'B1', 'operation' => 'create',
        'payload_snapshot' => [], 'failure_reason' => 'contract_break',
        'status' => 'resolved', 'resolved_at' => now(),
    ]);

    $this->getJson('/api/admin/supplier-integration/manual-queue')
        ->assertOk()->assertJsonCount(0, 'queue');
});

it('POST /resolve marks row resolved when listProjects matches', function (): void {
    $admin = User::factory()->create();
    $this->actingAs($admin);
    $tenant = Tenant::factory()->create();
    $project = Project::factory()->for($tenant)->create();
    $row = SupplierManualSyncQueue::create([
        'project_id' => $project->id, 'platform' => 'B1', 'operation' => 'create',
        'payload_snapshot' => ['signal_type' => 'site', 'unique_key' => 'foo.com'],
        'failure_reason' => 'contract_break', 'status' => 'pending',
    ]);

    $channelMock = new class implements SupplierProjectChannel
    {
        public function createProject(SupplierProjectDto $dto): int
        {
            return 0;
        }

        public function updateProject(int $externalId, SupplierProjectDto $dto): void {}

        public function listProjects(): array
        {
            return [['id' => 99999, 'platform' => 'B1', 'signal_type' => 'site', 'unique_key' => 'foo.com']];
        }
    };
    app()->instance(SupplierProjectChannel::class, $channelMock);

    $this->postJson("/api/admin/supplier-integration/manual-queue/{$row->id}/resolve")
        ->assertOk();

    expect($row->fresh()->status)->toBe('resolved');
    expect($row->fresh()->resolved_by_user_id)->toBe($admin->id);
    // FK ведёт на local supplier_projects.id; portal external_id (99999) хранится
    // в supplier_external_id созданной строки + в queue-row.external_id.
    expect($project->fresh()->supplier_b1_project_id)->not->toBeNull();
    expect(SupplierProject::find($project->fresh()->supplier_b1_project_id)->supplier_external_id)->toBe('99999');
    expect($row->fresh()->external_id)->toBe('99999');
});

it('POST /resolve returns 409 when listProjects does not match', function (): void {
    $this->actingAs(User::factory()->create());
    $tenant = Tenant::factory()->create();
    $project = Project::factory()->for($tenant)->create();
    $row = SupplierManualSyncQueue::create([
        'project_id' => $project->id, 'platform' => 'B1', 'operation' => 'create',
        'payload_snapshot' => ['signal_type' => 'site', 'unique_key' => 'foo.com'],
        'failure_reason' => 'contract_break', 'status' => 'pending',
    ]);

    $channelMock = new class implements SupplierProjectChannel
    {
        public function createProject(SupplierProjectDto $dto): int
        {
            return 0;
        }

        public function updateProject(int $externalId, SupplierProjectDto $dto): void {}

        public function listProjects(): array
        {
            return [];
        }
    };
    app()->instance(SupplierProjectChannel::class, $channelMock);

    $this->postJson("/api/admin/supplier-integration/manual-queue/{$row->id}/resolve")
        ->assertStatus(409);

    expect($row->fresh()->status)->toBe('pending');
});
