<?php

declare(strict_types=1);

use App\Filament\Pages\Operations\TenantlessOperationRunViewer;
use App\Filament\Pages\EnvironmentDashboard;
use App\Models\AuditLog;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\StoredReport;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Support\Audit\AuditActionId;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OperationRunType;
use App\Support\Providers\ProviderReasonCodes;
use App\Support\Providers\ProviderVerificationStatus;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;

function supportDiagnosticsTenantAuditComponent(User $user, ManagedEnvironment $tenant): \Livewire\Features\SupportTesting\Testable
{
    test()->actingAs($user);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
    setAdminEnvironmentContext($tenant);

    return Livewire::actingAs($user)->test(EnvironmentDashboard::class);
}

function supportDiagnosticsOperationAuditComponent(User $user, OperationRun $run): \Livewire\Features\SupportTesting\Testable
{
    test()->actingAs($user);
    Filament::setTenant(null, true);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $run->workspace_id);

    return Livewire::actingAs($user)->test(TenantlessOperationRunViewer::class, ['run' => $run]);
}

function seedSupportDiagnosticsAuditFixture(string $role = 'owner'): array
{
    $tenant = ManagedEnvironment::factory()->create(['name' => 'Audit ManagedEnvironment']);
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: $role);

    $connection = ProviderConnection::factory()
        ->withCredential()
        ->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
            'display_name' => 'Audit connection',
            'verification_status' => ProviderVerificationStatus::Blocked->value,
            'last_error_reason_code' => ProviderReasonCodes::ProviderPermissionMissing,
            'last_error_message' => 'raw-provider-secret-message',
            'last_health_check_at' => now()->subMinutes(15),
        ]);

    $run = OperationRun::factory()
        ->forTenant($tenant)
        ->create([
            'type' => OperationRunType::BaselineCompare->value,
            'status' => OperationRunStatus::Completed->value,
            'outcome' => OperationRunOutcome::Failed->value,
            'summary_counts' => [
                'total' => 0,
                'processed' => 0,
            ],
            'context' => [
                'provider_connection_id' => (int) $connection->getKey(),
                'raw_response_body' => 'secret-provider-body',
            ],
            'completed_at' => now()->subMinutes(10),
        ]);

    StoredReport::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'report_type' => StoredReport::REPORT_TYPE_PERMISSION_POSTURE,
        'payload' => [
            'raw_response_body' => 'stored-report-secret-body',
        ],
    ]);

    AuditLog::query()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'operation_run_id' => (int) $run->getKey(),
        'action' => 'operation.failed',
        'resource_type' => 'operation_run',
        'resource_id' => (string) $run->getKey(),
        'target_label' => 'Operation #'.$run->getKey(),
        'metadata' => [
            'raw_response_body' => 'audit-secret-body',
        ],
        'outcome' => 'success',
        'recorded_at' => now()->subMinutes(5),
    ]);

    return [$user, $tenant, $run];
}

it('audits tenant support diagnostics opens with redacted metadata and no side effects', function (): void {
    [$user, $tenant] = seedSupportDiagnosticsAuditFixture();

    bindFailHardGraphClient();
    Bus::fake();
    Queue::fake();

    $operationRunCount = OperationRun::query()->count();

    assertNoOutboundHttp(function () use ($user, $tenant): void {
        supportDiagnosticsTenantAuditComponent($user, $tenant)
            ->mountAction('openSupportDiagnostics')
            ->assertMountedActionModalSee('Support diagnostics');
    });

    Bus::assertNothingDispatched();
    Queue::assertNothingPushed();

    $audit = AuditLog::query()
        ->where('action', AuditActionId::SupportDiagnosticsOpened->value)
        ->latest('id')
        ->firstOrFail();

    $metadataJson = json_encode($audit->metadata, JSON_THROW_ON_ERROR);

    expect(OperationRun::query()->count())->toBe($operationRunCount)
        ->and(AuditLog::query()->where('action', AuditActionId::SupportDiagnosticsOpened->value)->count())->toBe(1)
        ->and(AuditLog::query()->where('action', AuditActionId::BaselineCompareStarted->value)->count())->toBe(0)
        ->and($audit->resource_type)->toBe('support_diagnostic_bundle')
        ->and($audit->resource_id)->toBe('tenant:'.$tenant->getKey())
        ->and($audit->operation_run_id)->toBeNull()
        ->and($audit->metadata['context_type'] ?? null)->toBe('tenant')
        ->and($audit->metadata['redaction_mode'] ?? null)->toBe('default_redacted')
        ->and($audit->metadata['section_count'] ?? null)->toBe(8)
        ->and($audit->metadata['reference_count'] ?? null)->toBeGreaterThan(0)
        ->and($audit->metadata['primary_context_id'] ?? null)->toBe((string) $tenant->getKey())
        ->and($metadataJson)->not->toContain('raw-provider-secret-message')
        ->and($metadataJson)->not->toContain('secret-provider-body')
        ->and($metadataJson)->not->toContain('stored-report-secret-body')
        ->and($metadataJson)->not->toContain('audit-secret-body');
});

it('audits operation support diagnostics opens with redacted metadata and no side effects', function (): void {
    [$user, $tenant, $run] = seedSupportDiagnosticsAuditFixture();

    bindFailHardGraphClient();
    Bus::fake();
    Queue::fake();

    $operationRunCount = OperationRun::query()->count();

    assertNoOutboundHttp(function () use ($user, $run): void {
        supportDiagnosticsOperationAuditComponent($user, $run)
            ->mountAction('openSupportDiagnostics')
            ->assertMountedActionModalSee('Support diagnostics');
    });

    Bus::assertNothingDispatched();
    Queue::assertNothingPushed();

    $audit = AuditLog::query()
        ->where('action', AuditActionId::SupportDiagnosticsOpened->value)
        ->latest('id')
        ->firstOrFail();

    $metadataJson = json_encode($audit->metadata, JSON_THROW_ON_ERROR);

    expect(OperationRun::query()->count())->toBe($operationRunCount)
        ->and(AuditLog::query()->where('action', AuditActionId::SupportDiagnosticsOpened->value)->count())->toBe(1)
        ->and(AuditLog::query()->where('action', AuditActionId::BaselineCompareStarted->value)->count())->toBe(0)
        ->and($audit->resource_type)->toBe('support_diagnostic_bundle')
        ->and($audit->resource_id)->toBe('operation_run:'.$run->getKey())
        ->and($audit->operation_run_id)->toBe((int) $run->getKey())
        ->and($audit->metadata['context_type'] ?? null)->toBe('operation_run')
        ->and($audit->metadata['redaction_mode'] ?? null)->toBe('default_redacted')
        ->and($audit->metadata['section_count'] ?? null)->toBe(8)
        ->and($audit->metadata['reference_count'] ?? null)->toBeGreaterThan(0)
        ->and($audit->metadata['primary_context_id'] ?? null)->toBe((string) $run->getKey())
        ->and($metadataJson)->not->toContain('raw-provider-secret-message')
        ->and($metadataJson)->not->toContain('secret-provider-body')
        ->and($metadataJson)->not->toContain('stored-report-secret-body')
        ->and($metadataJson)->not->toContain('audit-secret-body');
});