<?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\SupportRequest;
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 Livewire\Livewire;

uses(\Illuminate\Foundation\Testing\RefreshDatabase::class);

function supportRequestAuditTenantComponent(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 supportRequestAuditOperationComponent(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]);
}

it('records a redacted audit entry for tenant-scoped support requests', function (): void {
    $tenant = ManagedEnvironment::factory()->create(['name' => 'Audit Support ManagedEnvironment']);
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

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

    supportRequestAuditTenantComponent($user, $tenant)
        ->mountAction('requestSupport')
        ->setActionData([
            'severity' => SupportRequest::SEVERITY_HIGH,
            'summary' => 'Need tenant support audit proof.',
        ])
        ->callMountedAction()
        ->assertHasNoActionErrors();

    $supportRequest = SupportRequest::query()->sole();

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

    expect($audit)->not->toBeNull()
        ->and($audit?->workspace_id)->toBe((int) $tenant->workspace_id)
        ->and($audit?->managed_environment_id)->toBe((int) $tenant->getKey())
        ->and($audit?->resource_type)->toBe('support_request')
        ->and($audit?->resource_id)->toBe((string) $supportRequest->getKey())
        ->and($audit?->target_label)->toBe($supportRequest->internal_reference)
        ->and($audit?->operation_run_id)->toBeNull()
        ->and(data_get($audit?->metadata, 'internal_reference'))->toBe($supportRequest->internal_reference)
        ->and(data_get($audit?->metadata, 'primary_context_type'))->toBe(SupportRequest::PRIMARY_CONTEXT_TENANT)
        ->and(data_get($audit?->metadata, 'primary_context_id'))->toBe((string) $tenant->getKey())
        ->and(data_get($audit?->metadata, 'attachment_mode'))->toBe(SupportRequest::ATTACHMENT_MODE_DIAGNOSTIC_SNAPSHOT_ATTACHED)
        ->and(data_get($audit?->metadata, 'redaction_mode'))->toBe('default_redacted')
        ->and((string) json_encode($audit?->metadata))->not->toContain('tenant-provider-secret');
});

it('records a redacted audit entry for run-scoped support requests', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'operator');

    $run = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => OperationRunType::BaselineCompare->value,
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
        'summary_counts' => [
            'total' => 0,
            'processed' => 0,
        ],
        'context' => [
            'raw_response_body' => 'run-provider-secret',
        ],
        'failure_summary' => [[
            'message' => 'Run failed after provider validation.',
        ]],
        'completed_at' => now(),
    ]);

    supportRequestAuditOperationComponent($user, $run)
        ->mountAction('requestSupport')
        ->setActionData([
            'severity' => SupportRequest::SEVERITY_BLOCKING,
            'summary' => 'Need run support audit proof.',
        ])
        ->callMountedAction()
        ->assertHasNoActionErrors();

    $supportRequest = SupportRequest::query()->sole();

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

    expect($audit)->not->toBeNull()
        ->and($audit?->workspace_id)->toBe((int) $tenant->workspace_id)
        ->and($audit?->managed_environment_id)->toBe((int) $tenant->getKey())
        ->and($audit?->resource_type)->toBe('support_request')
        ->and($audit?->resource_id)->toBe((string) $supportRequest->getKey())
        ->and($audit?->target_label)->toBe($supportRequest->internal_reference)
        ->and($audit?->operation_run_id)->toBe((int) $run->getKey())
        ->and(data_get($audit?->metadata, 'internal_reference'))->toBe($supportRequest->internal_reference)
        ->and(data_get($audit?->metadata, 'primary_context_type'))->toBe(SupportRequest::PRIMARY_CONTEXT_OPERATION_RUN)
        ->and(data_get($audit?->metadata, 'primary_context_id'))->toBe((string) $run->getKey())
        ->and(data_get($audit?->metadata, 'attachment_mode'))->toBe(SupportRequest::ATTACHMENT_MODE_DIAGNOSTIC_SNAPSHOT_ATTACHED)
        ->and(data_get($audit?->metadata, 'redaction_mode'))->toBe('default_redacted')
        ->and((string) json_encode($audit?->metadata))->not->toContain('run-provider-secret');
});

it('creates distinct support references for duplicate submissions without outbound http or operation-run side effects', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'operator');

    $run = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => OperationRunType::BaselineCompare->value,
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
        'summary_counts' => [
            'total' => 0,
            'processed' => 0,
        ],
        'failure_summary' => [[
            'message' => 'Run failed after provider validation.',
        ]],
        'completed_at' => now(),
    ]);

    $component = supportRequestAuditOperationComponent($user, $run);
    $existingRunCount = OperationRun::query()->count();

    assertNoOutboundHttp(function () use ($component): void {
        $component
            ->mountAction('requestSupport')
            ->setActionData([
                'severity' => SupportRequest::SEVERITY_HIGH,
                'summary' => 'Duplicate run support request.',
            ])
            ->callMountedAction()
            ->assertHasNoActionErrors()
            ->mountAction('requestSupport')
            ->setActionData([
                'severity' => SupportRequest::SEVERITY_HIGH,
                'summary' => 'Duplicate run support request.',
            ])
            ->callMountedAction()
            ->assertHasNoActionErrors();
    });

    $supportRequests = SupportRequest::query()
        ->orderBy('id')
        ->get();

    $auditReferences = AuditLog::query()
        ->where('action', AuditActionId::SupportRequestCreated->value)
        ->orderBy('id')
        ->pluck('target_label');

    expect($supportRequests)->toHaveCount(2)
        ->and($supportRequests->pluck('summary')->all())->toBe([
            'Duplicate run support request.',
            'Duplicate run support request.',
        ])
        ->and($supportRequests->pluck('internal_reference')->unique())->toHaveCount(2)
        ->and($supportRequests->pluck('operation_run_id')->unique()->all())->toBe([(int) $run->getKey()])
        ->and($auditReferences->all())->toBe($supportRequests->pluck('internal_reference')->all())
        ->and(OperationRun::query()->count())->toBe($existingRunCount)
        ->and($run->fresh()?->status)->toBe(OperationRunStatus::Completed->value)
        ->and($run->fresh()?->outcome)->toBe(OperationRunOutcome::Failed->value);
});
