<?php

use App\Filament\Resources\RestoreRunResource;
use App\Models\AuditLog;
use App\Models\BackupSet;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Validation\ValidationException;

uses(RefreshDatabase::class);

beforeEach(function () {
    config()->set('tenantpilot.hardening.intune_write_gate.enabled', true);
    config()->set('tenantpilot.hardening.intune_write_gate.freshness_threshold_hours', 24);
});

test('blocked restore start creates audit log entry', function () {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $tenant->update([
        'rbac_status' => null,
        'rbac_last_checked_at' => null,
    ]);

    $backupSet = BackupSet::factory()->create(['managed_environment_id' => $tenant->id]);

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

    try {
        RestoreRunResource::createRestoreRun([
            'backup_set_id' => $backupSet->id,
            'is_dry_run' => false,
            'selected_items' => null,
        ]);

        $this->fail('Expected ValidationException to be thrown');
    } catch (ValidationException) {
        // Expected
    }

    $auditLog = AuditLog::query()
        ->where('managed_environment_id', $tenant->id)
        ->where('action', 'intune_rbac.write_blocked')
        ->first();

    expect($auditLog)->not->toBeNull()
        ->and($auditLog->status)->toBe('blocked')
        ->and($auditLog->actor_email)->toBe($user->email)
        ->and($auditLog->resource_type)->toBe('restore_run')
        ->and($auditLog->metadata)->toBeArray()
        ->and($auditLog->metadata['operation_type'])->toBe('restore.execute')
        ->and($auditLog->metadata['reason_code'])->toBe('intune_rbac.not_configured')
        ->and($auditLog->metadata['backup_set_id'])->toBe($backupSet->id);
});

test('audit log does not contain token or credential fields', function () {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $tenant->update([
        'rbac_status' => 'degraded',
        'rbac_last_checked_at' => now(),
    ]);

    $backupSet = BackupSet::factory()->create(['managed_environment_id' => $tenant->id]);

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

    try {
        RestoreRunResource::createRestoreRun([
            'backup_set_id' => $backupSet->id,
            'is_dry_run' => false,
            'selected_items' => null,
        ]);

        $this->fail('Expected ValidationException to be thrown');
    } catch (ValidationException) {
        // Expected
    }

    $auditLog = AuditLog::query()
        ->where('managed_environment_id', $tenant->id)
        ->where('action', 'intune_rbac.write_blocked')
        ->first();

    expect($auditLog)->not->toBeNull();

    $metadataJson = json_encode($auditLog->metadata);
    $sensitivePatterns = ['token', 'secret', 'password', 'credential', 'bearer', 'client_secret'];

    foreach ($sensitivePatterns as $pattern) {
        expect(str_contains(strtolower($metadataJson), $pattern))->toBeFalse(
            "Audit log metadata should not contain '{$pattern}'"
        );
    }
});

test('audit log records correct reason code for unhealthy status', function () {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $tenant->update([
        'rbac_status' => 'failed',
        'rbac_last_checked_at' => now(),
    ]);

    $backupSet = BackupSet::factory()->create(['managed_environment_id' => $tenant->id]);

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

    try {
        RestoreRunResource::createRestoreRun([
            'backup_set_id' => $backupSet->id,
            'is_dry_run' => false,
            'selected_items' => null,
        ]);

        $this->fail('Expected ValidationException to be thrown');
    } catch (ValidationException) {
        // Expected
    }

    $auditLog = AuditLog::query()
        ->where('managed_environment_id', $tenant->id)
        ->where('action', 'intune_rbac.write_blocked')
        ->first();

    expect($auditLog)->not->toBeNull()
        ->and($auditLog->metadata['reason_code'])->toBe('intune_rbac.unhealthy');
});
