<?php

declare(strict_types=1);

use App\Filament\Widgets\ManagedEnvironment\ManagedEnvironmentReviewPackCard;
use App\Models\EvidenceSnapshot;
use App\Models\Finding;
use App\Models\OperationRun;
use App\Models\ReviewPack;
use App\Models\StoredReport;
use App\Models\ManagedEnvironment;
use App\Services\Evidence\EvidenceSnapshotService;
use App\Support\Evidence\EvidenceSnapshotStatus;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OperationRunType;
use App\Support\Providers\ProviderReasonCodes;
use App\Support\ReasonTranslation\ReasonPresenter;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use Livewire\Livewire;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    Storage::fake('exports');
});

function seedWidgetReviewPackSnapshot(ManagedEnvironment $tenant): EvidenceSnapshot
{
    StoredReport::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'report_type' => StoredReport::REPORT_TYPE_PERMISSION_POSTURE,
        'payload' => ['required_count' => 1, 'granted_count' => 1],
    ]);

    StoredReport::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'report_type' => StoredReport::REPORT_TYPE_ENTRA_ADMIN_ROLES,
        'payload' => ['roles' => [['displayName' => 'Global Administrator']]],
    ]);

    Finding::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

    Finding::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'finding_type' => Finding::FINDING_TYPE_DRIFT,
    ]);

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

    /** @var EvidenceSnapshotService $service */
    $service = app(EvidenceSnapshotService::class);
    $payload = $service->buildSnapshotPayload($tenant);

    $snapshot = EvidenceSnapshot::query()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'status' => EvidenceSnapshotStatus::Active->value,
        'fingerprint' => $payload['fingerprint'],
        'completeness_state' => $payload['completeness'],
        'summary' => $payload['summary'],
        'generated_at' => now(),
    ]);

    foreach ($payload['items'] as $item) {
        $snapshot->items()->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
            'dimension_key' => $item['dimension_key'],
            'state' => $item['state'],
            'required' => $item['required'],
            'source_kind' => $item['source_kind'],
            'source_record_type' => $item['source_record_type'],
            'source_record_id' => $item['source_record_id'],
            'source_fingerprint' => $item['source_fingerprint'],
            'measured_at' => $item['measured_at'],
            'freshness_at' => $item['freshness_at'],
            'summary_payload' => $item['summary_payload'],
            'sort_order' => $item['sort_order'],
        ]);
    }

    return $snapshot;
}

// ─── No Pack State ───────────────────────────────────────────

it('shows the generate CTA when no pack exists', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    setAdminEnvironmentContext($tenant);

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentReviewPackCard::class, ['record' => $tenant])
        ->assertSee('No review pack generated yet')
        ->assertSee('Generate')
        ->assertDontSee('wire:poll.10s', escape: false);
});

// ─── Ready State ─────────────────────────────────────────────

it('shows download and generate buttons when a ready pack exists', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    $filePath = 'review-packs/widget-test.zip';
    Storage::disk('exports')->put($filePath, 'PK-test');

    ReviewPack::factory()->ready()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
        'file_path' => $filePath,
        'file_disk' => 'exports',
    ]);

    setAdminEnvironmentContext($tenant);

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentReviewPackCard::class, ['record' => $tenant])
        ->assertSee('Download')
        ->assertSee('Generate new')
        ->assertDontSee('wire:poll.10s', escape: false);
});

// ─── Generating State ────────────────────────────────────────

it('shows in-progress message for a generating pack', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    ReviewPack::factory()->generating()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
    ]);

    setAdminEnvironmentContext($tenant);

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentReviewPackCard::class, ['record' => $tenant])
        ->assertSee('Generation in progress')
        ->assertSee('wire:poll.10s', escape: false);
});

// ─── Queued State ────────────────────────────────────────────

it('shows in-progress message for a queued pack', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    ReviewPack::factory()->queued()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
    ]);

    setAdminEnvironmentContext($tenant);

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentReviewPackCard::class, ['record' => $tenant])
        ->assertSee('Generation in progress')
        ->assertSee('wire:poll.10s', escape: false);
});

// ─── Failed State ────────────────────────────────────────────

it('shows retry button for a failed pack', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    ReviewPack::factory()->failed()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
    ]);

    setAdminEnvironmentContext($tenant);

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentReviewPackCard::class, ['record' => $tenant])
        ->assertSee('Retry')
        ->assertDontSee('wire:poll.10s', escape: false);
});

it('renders translated reason semantics for failed review-pack runs when available', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    $run = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => 'environment.review_pack.generate',
        'status' => 'completed',
        'outcome' => 'failed',
        'context' => [
            'reason_code' => ProviderReasonCodes::ProviderPermissionMissing,
        ],
        'failure_summary' => [[
            'code' => 'operation.failed',
            'reason_code' => ProviderReasonCodes::ProviderPermissionMissing,
            'message' => 'The provider app is missing a required permission.',
        ]],
    ]);

    ReviewPack::factory()->failed()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
        'operation_run_id' => (int) $run->getKey(),
    ]);

    $reasonSemantics = app(ReasonPresenter::class)->semantics(
        app(ReasonPresenter::class)->forOperationRun($run, 'review_pack_widget'),
    );
    $reasonEnvelope = app(ReasonPresenter::class)->forOperationRun($run, 'review_pack_widget');

    expect($reasonEnvelope)->not->toBeNull()
        ->and($reasonSemantics)->not->toBeNull();

    setAdminEnvironmentContext($tenant);

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentReviewPackCard::class, ['record' => $tenant])
        ->assertSee($reasonEnvelope->operatorLabel)
        ->assertSee($reasonEnvelope->shortExplanation)
        ->assertSee($reasonSemantics['owner_label'])
        ->assertSee($reasonSemantics['family_label']);
});

// ─── Expired State ───────────────────────────────────────────

it('shows generate action for an expired pack', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    ReviewPack::factory()->expired()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
    ]);

    setAdminEnvironmentContext($tenant);

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentReviewPackCard::class, ['record' => $tenant])
        ->assertSee('Generate new')
        ->assertDontSee('wire:poll.10s', escape: false);
});

// ─── Generate Pack Livewire Action ──────────────────────────

it('can trigger generatePack Livewire action', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');
    seedWidgetReviewPackSnapshot($tenant);

    setAdminEnvironmentContext($tenant);

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentReviewPackCard::class, ['record' => $tenant])
        ->call('generatePack', true, true)
        ->assertHasNoErrors();

    expect(ReviewPack::query()->where('managed_environment_id', (int) $tenant->getKey())->count())->toBe(1);
});
