<?php

declare(strict_types=1);

use App\Models\OperationRun;
use App\Services\Audit\AuditRecorder;
use App\Support\Audit\AuditActorSnapshot;
use App\Support\Audit\AuditActorType;
use App\Support\Audit\AuditOutcome;
use App\Support\Audit\AuditTargetSnapshot;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('records workspace and tenant audit rows through the shared recorder', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $run = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'backup_create',
    ]);

    $audit = app(AuditRecorder::class)->record(
        action: 'backup.created',
        context: [
            'item_count' => 3,
            'client_secret' => 'super-secret',
        ],
        workspace: $tenant->workspace,
        tenant: $tenant,
        actor: AuditActorSnapshot::human($user),
        target: new AuditTargetSnapshot(
            type: 'backup_set',
            id: '42',
            label: 'Nightly backup',
        ),
        outcome: 'completed',
        summary: null,
        operationRunId: (int) $run->getKey(),
    )->refresh();

    expect((int) $audit->workspace_id)->toBe((int) $tenant->workspace_id)
        ->and((int) $audit->managed_environment_id)->toBe((int) $tenant->getKey())
        ->and($audit->actorSnapshot()->type)->toBe(AuditActorType::Human)
        ->and($audit->actorDisplayLabel())->toBe($user->name)
        ->and($audit->resource_type)->toBe('backup_set')
        ->and((string) $audit->resource_id)->toBe('42')
        ->and($audit->targetDisplayLabel())->toBe('Nightly backup')
        ->and($audit->summaryText())->toBe('Backup set created for Nightly backup')
        ->and($audit->normalizedOutcome())->toBe(AuditOutcome::Success)
        ->and((int) $audit->operation_run_id)->toBe((int) $run->getKey())
        ->and(data_get($audit->metadata, 'client_secret'))->toBe('[REDACTED]')
        ->and(data_get($audit->metadata, 'item_count'))->toBe(3);
});

it('infers actor kind, target identity, and normalized outcome when snapshots are omitted', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $audit = app(AuditRecorder::class)->record(
        action: 'backup_schedule.run_failed',
        context: [
            '_actor_type' => 'scheduled',
            'backup_schedule_id' => 123,
            'status' => 'failed',
            'token' => 'top-secret',
        ],
        workspace: $tenant->workspace,
        tenant: $tenant,
    )->refresh();

    expect($audit->actorSnapshot()->type)->toBe(AuditActorType::Scheduled)
        ->and($audit->resource_type)->toBe('backup_schedule')
        ->and((string) $audit->resource_id)->toBe('123')
        ->and($audit->targetDisplayLabel())->toBe('Backup schedule #123')
        ->and($audit->normalizedOutcome())->toBe(AuditOutcome::Failed)
        ->and(data_get($audit->metadata, 'token'))->toBe('[REDACTED]');
});
