<?php

declare(strict_types=1);

use App\Models\Project;
use App\Models\SupplierProject;
use App\Models\Tenant;
use App\Models\User;
use App\Services\Supplier\SupplierPortalClient;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;

uses(DatabaseTransactions::class);

// EnsureSaasAdmin — стаб в testing (см. SupplierManualQueueTest::16): обычный
// User::factory + actingAs без guard'а.

it('GET /admin/supplier-integration/projects returns rows with orderers + last delivery', function (): void {
    $this->actingAs(User::factory()->create());
    $tenant = Tenant::factory()->create(['organization_name' => 'ООО Ромашка']);

    $sp = SupplierProject::query()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => 'okna.ru',
        'subject_code' => 82, // Москва (по конституционному порядку, ст. 65)
        'current_limit' => 5,
        'current_workdays' => [1, 2, 3, 4, 5, 6, 7],
        'current_regions' => null,
        'sync_status' => 'ok',
        'supplier_external_id' => '777',
    ]);

    $project = Project::factory()->for($tenant)->create();
    DB::table('project_supplier_links')->insert([
        'project_id' => $project->id,
        'supplier_project_id' => $sp->id,
        'platform' => 'B1',
        'subject_code' => 82,
    ]);

    DB::table('supplier_leads')->insert([
        'supplier_project_id' => $sp->id,
        'platform' => 'B1',
        'raw_payload' => json_encode([]),
        'phone' => '+79991234567',
        'received_at' => '2026-05-19 10:00:00',
    ]);

    $resp = $this->getJson('/api/admin/supplier-integration/projects')
        ->assertOk()
        ->json();

    $row = collect($resp['projects'])->firstWhere('id', $sp->id);
    expect($row)->not->toBeNull()
        ->and($row['unique_key'])->toBe('okna.ru')
        ->and($row['subject_code'])->toBe(82)
        ->and($row['subject_name'])->toBe('Москва')
        ->and($row['platform'])->toBe('B1')
        ->and($row['current_limit'])->toBe(5)
        ->and($row['orderers'])->toContain('ООО Ромашка')
        ->and($row['last_delivery_at'])->not->toBeNull();
});

it('GET /projects returns subject_name «РФ» for NULL subject_code', function (): void {
    $this->actingAs(User::factory()->create());

    $sp = SupplierProject::query()->create([
        'platform' => 'B2',
        'signal_type' => 'site',
        'unique_key' => 'all-russia.example',
        'subject_code' => null,
        'current_limit' => 0,
        'current_workdays' => [1, 2, 3, 4, 5, 6, 7],
        'current_regions' => null,
        'sync_status' => 'ok',
        'supplier_external_id' => '888',
    ]);

    $resp = $this->getJson('/api/admin/supplier-integration/projects')->assertOk()->json();
    $row = collect($resp['projects'])->firstWhere('id', $sp->id);
    expect($row['subject_code'])->toBeNull()
        ->and($row['subject_name'])->toBe('РФ');
});

it('POST /projects/delete deletes on portal + locally (pivot cascades)', function (): void {
    $this->actingAs(User::factory()->create());

    // Мокаем portal-клиент, чтобы не лезть в Redis-сессию (SupplierPortalClient::loadSession()).
    $deletedExternalIds = [];
    $clientMock = new class($deletedExternalIds) extends SupplierPortalClient
    {
        /** @var array<int, int> */
        public array $calls;

        public function __construct(array &$calls)
        {
            $this->calls = &$calls;
        }

        public function deleteProject(int $externalId): void
        {
            $this->calls[] = $externalId;
        }
    };
    app()->instance(SupplierPortalClient::class, $clientMock);

    $tenant = Tenant::factory()->create();
    $sp = SupplierProject::query()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => 'delete-me.ru',
        'subject_code' => 77,
        'current_limit' => 0,
        'current_workdays' => [1, 2, 3, 4, 5, 6, 7],
        'current_regions' => null,
        'sync_status' => 'ok',
        'supplier_external_id' => '999',
    ]);
    $project = Project::factory()->for($tenant)->create();
    DB::table('project_supplier_links')->insert([
        'project_id' => $project->id,
        'supplier_project_id' => $sp->id,
        'platform' => 'B1',
        'subject_code' => 77,
    ]);

    $this->postJson('/api/admin/supplier-integration/projects/delete', ['ids' => [$sp->id]])
        ->assertOk()
        ->assertJson(['deleted' => 1, 'failures' => []]);

    expect(SupplierProject::find($sp->id))->toBeNull();
    expect($clientMock->calls)->toBe([999]);
    expect(DB::table('project_supplier_links')->where('supplier_project_id', $sp->id)->count())->toBe(0);
});

it('POST /projects/delete validates ids array', function (): void {
    $this->actingAs(User::factory()->create());

    $this->postJson('/api/admin/supplier-integration/projects/delete', ['ids' => []])
        ->assertStatus(422);

    $this->postJson('/api/admin/supplier-integration/projects/delete', [])
        ->assertStatus(422);
});

it('POST /projects/delete collects failures without aborting batch', function (): void {
    $this->actingAs(User::factory()->create());

    $clientMock = new class extends SupplierPortalClient
    {
        public int $callsCount = 0;

        public function __construct() {}

        public function deleteProject(int $externalId): void
        {
            $this->callsCount++;
            if ($externalId === 555) {
                throw new RuntimeException('portal said no');
            }
        }
    };
    app()->instance(SupplierPortalClient::class, $clientMock);

    $spOk = SupplierProject::query()->create([
        'platform' => 'B1', 'signal_type' => 'site', 'unique_key' => 'ok.ru',
        'subject_code' => 77, 'current_limit' => 0,
        'current_workdays' => [1, 2, 3, 4, 5, 6, 7], 'current_regions' => null,
        'sync_status' => 'ok', 'supplier_external_id' => '111',
    ]);
    $spBad = SupplierProject::query()->create([
        'platform' => 'B1', 'signal_type' => 'site', 'unique_key' => 'bad.ru',
        'subject_code' => 77, 'current_limit' => 0,
        'current_workdays' => [1, 2, 3, 4, 5, 6, 7], 'current_regions' => null,
        'sync_status' => 'ok', 'supplier_external_id' => '555',
    ]);

    $resp = $this->postJson('/api/admin/supplier-integration/projects/delete', [
        'ids' => [$spOk->id, $spBad->id],
    ])->assertOk()->json();

    expect($resp['deleted'])->toBe(1)
        ->and(count($resp['failures']))->toBe(1)
        ->and($resp['failures'][0]['id'])->toBe($spBad->id)
        ->and($resp['failures'][0]['error'])->toContain('portal said no');

    expect(SupplierProject::find($spOk->id))->toBeNull();
    expect(SupplierProject::find($spBad->id))->not->toBeNull(); // bad — не удалён локально
});
