<?php

declare(strict_types=1);

use App\Jobs\Supplier\CleanupInactiveSupplierProjectsJob;
use App\Models\Project;
use App\Models\SupplierProject;
use App\Models\SupplierSyncLog;
use App\Models\Tenant;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Tests\Concerns\SharesSupplierPdo;

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

beforeEach(function (): void {
    Cache::store('redis')->put('supplier:session', [
        'phpsessid' => 'sess',
        'csrf' => 'csrf',
        'refreshed_at' => now()->toIso8601String(),
    ], now()->addHours(6));

    config(['services.supplier.portal_url' => 'https://crm.bp-gr.ru']);
});

afterEach(function (): void {
    Cache::store('redis')->forget('supplier:session');
    Carbon::setTestNow();
});

test('phase A re-activates supplier_project when active liderra project still references it', function (): void {
    $tenant = Tenant::factory()->create();
    $sp = SupplierProject::factory()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => 'reactivate.example.com',
        'inactive_since' => now()->subDays(30),
    ]);
    $project = Project::factory()->create([
        'tenant_id' => $tenant->id,
        'is_active' => true,
        'signal_type' => 'site',
        'signal_identifier' => 'reactivate.example.com',
        'supplier_b1_project_id' => $sp->id,
    ]);
    // Phase A смотрит pivot project_supplier_links (Plan 3+), а не legacy FK → нужна привязка.
    linkProjectToSupplier($project, $sp);

    (new CleanupInactiveSupplierProjectsJob)->handle();

    expect($sp->fresh()->inactive_since)->toBeNull();
});

test('phase B marks inactive_since=NOW for newly orphaned supplier_project', function (): void {
    $sp = SupplierProject::factory()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => 'orphan.example.com',
        'inactive_since' => null,
    ]);

    Carbon::setTestNow(Carbon::parse('2026-05-12 02:00:00'));
    (new CleanupInactiveSupplierProjectsJob)->handle();

    expect($sp->fresh()->inactive_since)->not->toBeNull();
});

test('phase C deletes supplier_project after 180 days inactive and writes audit row', function (): void {
    $sp = SupplierProject::factory()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => 'old.example.com',
        'supplier_external_id' => '999',
        'inactive_since' => now()->subDays(181),
    ]);

    Http::fake([
        'crm.bp-gr.ru/admin/visit/rt-project-delete' => Http::response(
            ['status' => 'OK', 'message' => '', 'result' => null],
            200,
        ),
    ]);

    (new CleanupInactiveSupplierProjectsJob)->handle();

    expect(SupplierProject::on('pgsql_supplier')->find($sp->id))->toBeNull();
    // FK ON DELETE SET NULL зануляет supplier_project_id у лога после delete'а
    // supplier_project — трассировка через request_payload (JSONB snapshot).
    expect(
        SupplierSyncLog::on('pgsql_supplier')
            ->where('action', 'delete')
            ->where('http_status', 200)
            ->whereRaw("request_payload->>'supplier_project_id' = ?", [(string) $sp->id])
            ->exists()
    )->toBeTrue();
});

test('phase A runs before phase C (safety ordering): returned-active is reactivated, not deleted', function (): void {
    $tenant = Tenant::factory()->create();
    $sp = SupplierProject::factory()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => 'edge.example.com',
        'supplier_external_id' => '888',
        'inactive_since' => now()->subDays(185),
    ]);
    $project = Project::factory()->create([
        'tenant_id' => $tenant->id,
        'is_active' => true,
        'signal_type' => 'site',
        'signal_identifier' => 'edge.example.com',
        'supplier_b1_project_id' => $sp->id,
    ]);
    // Phase A смотрит pivot project_supplier_links (Plan 3+), а не legacy FK → нужна привязка.
    linkProjectToSupplier($project, $sp);

    Http::fake();
    (new CleanupInactiveSupplierProjectsJob)->handle();

    expect($sp->fresh()?->inactive_since)->toBeNull();
    expect(SupplierProject::on('pgsql_supplier')->find($sp->id))->not->toBeNull();
    Http::assertNothingSent();
});

test('handles 404 from supplier as already-deleted: local delete + audit row with 404 status', function (): void {
    $sp = SupplierProject::factory()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => 'ghost.example.com',
        'supplier_external_id' => '777',
        'inactive_since' => now()->subDays(181),
    ]);

    Http::fake([
        'crm.bp-gr.ru/admin/visit/rt-project-delete' => Http::response('not found', 404),
    ]);

    (new CleanupInactiveSupplierProjectsJob)->handle();

    expect(SupplierProject::on('pgsql_supplier')->find($sp->id))->toBeNull();
    expect(
        SupplierSyncLog::on('pgsql_supplier')
            ->where('action', 'delete')
            ->where('http_status', 404)
            ->whereRaw("request_payload->>'supplier_project_id' = ?", [(string) $sp->id])
            ->exists()
    )->toBeTrue();
});

test('does not delete supplier_project marked inactive less than 180 days ago', function (): void {
    $sp = SupplierProject::factory()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => 'recent.example.com',
        'supplier_external_id' => '555',
        'inactive_since' => now()->subDays(100),
    ]);

    Http::fake();
    (new CleanupInactiveSupplierProjectsJob)->handle();

    expect(SupplierProject::on('pgsql_supplier')->find($sp->id))->not->toBeNull();
    Http::assertNothingSent();
});
