<?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 App\Services\Supplier\SupplierPortalClient;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;

uses(DatabaseTransactions::class);

// Creates a stub saas_admin_users row and returns its id.
function stubAdminUser(string $email = 'audit-stub@test.local'): int
{
    $existing = DB::table('saas_admin_users')->where('email', $email)->value('id');
    if ($existing !== null) {
        return (int) $existing;
    }

    return (int) DB::table('saas_admin_users')->insertGetId([
        'email' => $email,
        'full_name' => 'Audit Test Stub',
        'password_hash' => '$2y$04$system-stub-not-loginable',
        'role' => 'super_admin',
        'is_active' => false,
        'sso_provider' => 'local',
        'is_break_glass' => false,
    ]);
}

it('setExportMode writes audit log row', function (): void {
    $adminId = stubAdminUser();
    $this->actingAs(User::factory()->create());

    DB::table('system_settings')->updateOrInsert(
        ['key' => 'supplier_export_mode'],
        ['value' => 'batch', 'type' => 'string', 'updated_at' => now()],
    );

    $countBefore = DB::table('saas_admin_audit_log')->count();

    $this->postJson('/api/admin/supplier-integration/export-mode', [
        'mode' => 'online',
        'admin_user_id' => $adminId,
    ])->assertOk();

    expect(DB::table('saas_admin_audit_log')->count())->toBe($countBefore + 1);

    $row = DB::table('saas_admin_audit_log')
        ->orderByDesc('id')
        ->first();

    expect($row->action)->toBe('supplier_integration.export_mode_set')
        ->and($row->target_type)->toBe('system_setting')
        ->and($row->target_id)->toBeNull()
        ->and($row->admin_user_id)->toBe($adminId);

    $after = json_decode($row->payload_after, true);
    expect($after['mode'])->toBe('online');
});

it('manualQueueResolve writes audit log row', function (): void {
    $adminId = stubAdminUser();
    $admin = User::factory()->create();
    $this->actingAs($admin);

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

    $queueRow = SupplierManualSyncQueue::create([
        'project_id' => $project->id,
        'platform' => 'B1',
        'operation' => 'create',
        'payload_snapshot' => ['signal_type' => 'site', 'unique_key' => 'audit-test.ru'],
        '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' => 77777, 'platform' => 'B1', 'signal_type' => 'site', 'unique_key' => 'audit-test.ru']];
        }
    };
    app()->instance(SupplierProjectChannel::class, $channelMock);

    $countBefore = DB::table('saas_admin_audit_log')->count();

    $this->postJson("/api/admin/supplier-integration/manual-queue/{$queueRow->id}/resolve", [
        'admin_user_id' => $adminId,
    ])->assertOk();

    expect(DB::table('saas_admin_audit_log')->count())->toBe($countBefore + 1);

    $row = DB::table('saas_admin_audit_log')
        ->orderByDesc('id')
        ->first();

    expect($row->action)->toBe('supplier_integration.manual_queue_resolved')
        ->and($row->target_type)->toBe('manual_queue_item')
        ->and((int) $row->target_id)->toBe($queueRow->id)
        ->and($row->admin_user_id)->toBe($adminId);
});

it('projectsDestroy writes audit log row', function (): void {
    $adminId = stubAdminUser();
    $this->actingAs(User::factory()->create());

    $clientMock = new class extends SupplierPortalClient
    {
        public function __construct() {}

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

    $sp = SupplierProject::query()->create([
        'platform' => 'B1',
        'signal_type' => 'site',
        'unique_key' => 'audit-destroy.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' => '12345',
    ]);

    $countBefore = DB::table('saas_admin_audit_log')->count();

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

    expect(DB::table('saas_admin_audit_log')->count())->toBe($countBefore + 1);

    $row = DB::table('saas_admin_audit_log')
        ->orderByDesc('id')
        ->first();

    expect($row->action)->toBe('supplier_integration.projects_destroyed')
        ->and($row->target_type)->toBe('supplier_projects_bulk')
        ->and($row->target_id)->toBeNull()
        ->and($row->admin_user_id)->toBe($adminId);

    $after = json_decode($row->payload_after, true);
    expect($after['deleted'])->toBe(1);
});
