<?php

declare(strict_types=1);

use App\Filament\Resources\PolicyResource\Pages\ViewPolicy;
use App\Jobs\CapturePolicySnapshotJob;
use App\Models\AuditLog;
use App\Models\Policy;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;
use Tests\TestCase;

final class AuditLoggingTest extends TestCase
{
    use RefreshDatabase;

    public function test_spec090_writes_an_audit_log_when_capture_snapshot_dispatch_succeeds(): void
    {
        Queue::fake();

        [$user, $tenant] = createUserWithTenant(role: 'owner');
        $this->actingAs($user);

        $tenant->makeCurrent();
        Filament::setTenant($tenant, true);

        $policy = Policy::factory()->create([
            'managed_environment_id' => (int) $tenant->getKey(),
        ]);

        Livewire::test(ViewPolicy::class, ['record' => $policy->getRouteKey()])
            ->callAction('capture_snapshot', data: [
                'include_assignments' => true,
                'include_scope_tags' => true,
            ])
            ->assertHasNoActionErrors();

        Queue::assertPushed(CapturePolicySnapshotJob::class);

        $audit = AuditLog::query()
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->where('action', 'policy.capture_snapshot_dispatched')
            ->latest('id')
            ->first();

        $this->assertNotNull($audit);
        $this->assertSame('success', $audit?->status);
        $this->assertSame('operation_run', $audit?->resource_type);
        $this->assertSame((int) $policy->getKey(), (int) ($audit?->metadata['policy_id'] ?? 0));
    }

    public function test_spec090_does_not_require_audit_logs_for_denied_capture_snapshot_attempts(): void
    {
        Queue::fake();

        [$user, $tenant] = createUserWithTenant(role: 'readonly');
        $this->actingAs($user);

        $tenant->makeCurrent();
        Filament::setTenant($tenant, true);

        $policy = Policy::factory()->create([
            'managed_environment_id' => (int) $tenant->getKey(),
        ]);

        Livewire::test(ViewPolicy::class, ['record' => $policy->getRouteKey()])
            ->callAction('capture_snapshot', data: [
                'include_assignments' => true,
                'include_scope_tags' => true,
            ])
            ->assertSuccessful();

        Queue::assertNothingPushed();

        $this->assertSame(
            0,
            AuditLog::query()
                ->where('managed_environment_id', (int) $tenant->getKey())
                ->where('action', 'policy.capture_snapshot_dispatched')
                ->count(),
        );
    }

    public function test_spec090_does_not_require_audit_logs_for_cancelled_capture_snapshot_modals(): void
    {
        Queue::fake();

        [$user, $tenant] = createUserWithTenant(role: 'owner');
        $this->actingAs($user);

        $tenant->makeCurrent();
        Filament::setTenant($tenant, true);

        $policy = Policy::factory()->create([
            'managed_environment_id' => (int) $tenant->getKey(),
        ]);

        Livewire::test(ViewPolicy::class, ['record' => $policy->getRouteKey()])
            ->mountAction('capture_snapshot')
            ->assertSuccessful();

        Queue::assertNothingPushed();

        $this->assertSame(
            0,
            AuditLog::query()
                ->where('managed_environment_id', (int) $tenant->getKey())
                ->where('action', 'policy.capture_snapshot_dispatched')
                ->count(),
        );
    }
}
