<?php

declare(strict_types=1);

use App\Models\Deal;
use App\Models\Project;
use App\Models\SystemSetting;
use App\Models\Tenant;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Tests\Concerns\SharesSupplierPdo;

// Команда читает/пишет через pgsql_supplier (BYPASSRLS). SharesSupplierPdo делит
// PDO, чтобы это соединение видело незакоммиченные данные транзакции теста.
uses(DatabaseTransactions::class, SharesSupplierPdo::class);

/**
 * F-P1: команда-ретеншен анонимизирует ПДн soft-deleted сделок по истечении
 * настраиваемого срока. Контракт — спека 2026-06-17-fp1-deal-pii-retention-spec.
 */
function makeRetentionDeal(
    Tenant $tenant,
    Project $project,
    ?Carbon\Carbon $deletedAt,
    string $phone = '+79991112233',
): Deal {
    return Deal::factory()->create([
        'tenant_id' => $tenant->id,
        'project_id' => $project->id,
        'phone' => $phone,
        'phones' => ['+79995556677'],
        'contact_name' => 'Иван',
        'received_at' => now(),
        'deleted_at' => $deletedAt,
    ]);
}

/** Сырое чтение сделки без soft-delete scope (PDO делится через SharesSupplierPdo). */
function rawDeal(int $id): ?object
{
    return DB::connection('pgsql_supplier')->table('deals')->where('id', $id)->first();
}

it('анонимизирует ПДн soft-deleted сделок старше окна, не трогая свежие и живые', function () {
    SystemSetting::create(['key' => 'pd_scrub_soft_deleted_deals_days', 'value' => '30', 'type' => 'int']);
    $tenant = Tenant::factory()->create();
    DB::statement('SET app.current_tenant_id = '.$tenant->id);
    $project = Project::factory()->create(['tenant_id' => $tenant->id]);

    $old = makeRetentionDeal($tenant, $project, now()->subDays(40));   // старше окна → чистим
    $fresh = makeRetentionDeal($tenant, $project, now()->subDays(5));  // в окне → не трогаем
    $live = makeRetentionDeal($tenant, $project, null);                // живой → не трогаем

    $this->artisan('pd:scrub-soft-deleted-deals')->assertExitCode(0);

    $oldRow = rawDeal($old->id);
    expect($oldRow->phone)->toBe('+7000XXXXXXX');
    expect($oldRow->contact_name)->toBe('Удалено');
    expect($oldRow->phones)->toBeNull();

    expect(rawDeal($fresh->id)->phone)->toBe('+79991112233');
    expect(rawDeal($live->id)->phone)->toBe('+79991112233');
});

it('no-op если retention не настроен (ключ отсутствует)', function () {
    $tenant = Tenant::factory()->create();
    DB::statement('SET app.current_tenant_id = '.$tenant->id);
    $project = Project::factory()->create(['tenant_id' => $tenant->id]);
    $old = makeRetentionDeal($tenant, $project, now()->subDays(40));

    $this->artisan('pd:scrub-soft-deleted-deals')->assertExitCode(0);

    expect(rawDeal($old->id)->phone)->toBe('+79991112233');
});

it('идемпотентна: повторный прогон ничего не меняет', function () {
    SystemSetting::create(['key' => 'pd_scrub_soft_deleted_deals_days', 'value' => '30', 'type' => 'int']);
    $tenant = Tenant::factory()->create();
    DB::statement('SET app.current_tenant_id = '.$tenant->id);
    $project = Project::factory()->create(['tenant_id' => $tenant->id]);
    $old = makeRetentionDeal($tenant, $project, now()->subDays(40));

    $this->artisan('pd:scrub-soft-deleted-deals')->assertExitCode(0);
    $this->artisan('pd:scrub-soft-deleted-deals')->assertExitCode(0);

    expect(rawDeal($old->id)->phone)->toBe('+7000XXXXXXX');
});

it('пишет запись в pd_processing_log при анонимизации (системный актор)', function () {
    SystemSetting::create(['key' => 'pd_scrub_soft_deleted_deals_days', 'value' => '30', 'type' => 'int']);
    $tenant = Tenant::factory()->create();
    DB::statement('SET app.current_tenant_id = '.$tenant->id);
    $project = Project::factory()->create(['tenant_id' => $tenant->id]);
    makeRetentionDeal($tenant, $project, now()->subDays(40));

    $this->artisan('pd:scrub-soft-deleted-deals')->assertExitCode(0);

    $log = DB::connection('pgsql_supplier')->table('pd_processing_log')
        ->where('action', 'deleted')
        ->where('purpose', '152-FZ retention scrub')
        ->first();

    expect($log)->not->toBeNull();
    expect($log->actor_admin_user_id)->toBeNull();
    expect($log->actor_tenant_user_id)->toBeNull();
});
