<?php

declare(strict_types=1);

use App\Models\Finding;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\ManagedEnvironment;
use App\Models\Workspace;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OperationRunType;
use App\Support\SupportDiagnostics\SupportDiagnosticBundleBuilder;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('builds tenant bundles with stable section order and stable reference order', function (): void {
    $tenant = ManagedEnvironment::factory()->create(['name' => 'Deterministic ManagedEnvironment']);

    ProviderConnection::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'display_name' => 'Deterministic connection',
    ]);

    OperationRun::factory()
        ->forTenant($tenant)
        ->create([
            'type' => OperationRunType::BaselineCompare->value,
            'status' => OperationRunStatus::Completed->value,
            'outcome' => OperationRunOutcome::Succeeded->value,
            'completed_at' => now()->subMinute(),
        ]);

    $firstFinding = Finding::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'severity' => Finding::SEVERITY_LOW,
        'last_seen_at' => now()->subMinutes(4),
    ]);

    $secondFinding = Finding::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'severity' => Finding::SEVERITY_CRITICAL,
        'last_seen_at' => now()->subMinutes(2),
    ]);

    $builder = app(SupportDiagnosticBundleBuilder::class);

    $firstBundle = $builder->forTenant($tenant);
    $secondBundle = $builder->forTenant($tenant->fresh());

    expect(array_column($firstBundle['sections'], 'key'))
        ->toBe([
            'overview',
            'provider_connection',
            'operation_context',
            'findings',
            'stored_reports',
            'environment_review',
            'review_pack',
            'audit_history',
        ])
        ->and(array_column($firstBundle['sections'], 'key'))->toBe(array_column($secondBundle['sections'], 'key'));

    $firstFindingsSection = collect($firstBundle['sections'])->firstWhere('key', 'findings');
    $secondFindingsSection = collect($secondBundle['sections'])->firstWhere('key', 'findings');

    expect(array_column($firstFindingsSection['references'], 'record_id'))
        ->toBe([(string) $firstFinding->getKey(), (string) $secondFinding->getKey()])
        ->and($firstFindingsSection['references'])->toBe($secondFindingsSection['references']);
});

it('degrades missing operation-run support context without failing bundle generation', function (): void {
    $workspace = Workspace::factory()->create();

    $tenantlessRun = OperationRun::factory()->create([
        'managed_environment_id' => null,
        'workspace_id' => (int) $workspace->getKey(),
        'type' => OperationRunType::BaselineCompare->value,
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
        'summary_counts' => [
            'total' => 0,
            'processed' => 0,
        ],
        'completed_at' => now(),
    ]);

    $bundle = app(SupportDiagnosticBundleBuilder::class)->forOperationRun($tenantlessRun);
    $sections = collect($bundle['sections'])->keyBy('key');

    expect($bundle['context']['managed_environment_id'])->toBeNull()
        ->and($bundle['summary']['completeness_note'])->toContain('Provider connection')
        ->and($bundle['summary']['completeness_note'])->toContain('Review pack')
        ->and($sections['operation_context']['availability'])->toBe('available')
        ->and($sections['provider_connection']['availability'])->toBe('missing')
        ->and($sections['findings']['availability'])->toBe('missing')
        ->and($sections['stored_reports']['availability'])->toBe('missing')
        ->and($sections['environment_review']['availability'])->toBe('missing')
        ->and($sections['review_pack']['availability'])->toBe('missing');
});

it('marks references without canonical destinations as inaccessible', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    $connection = ProviderConnection::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

    $method = new \ReflectionMethod(SupportDiagnosticBundleBuilder::class, 'modelReference');
    $reference = $method->invoke(
        app(SupportDiagnosticBundleBuilder::class),
        'provider_connection',
        $connection,
        'Detached provider connection',
        'Open provider connection',
        null,
        null,
    );

    expect($reference)
        ->toBeArray()
        ->and($reference['availability'])->toBe('inaccessible')
        ->and($reference['access_reason'])->toBe('Canonical destination is not available from this context.');
});