<?php

declare(strict_types=1);

use App\Models\ReviewPack;
use App\Models\AuditLog;
use App\Models\OperationRun;
use App\Models\PlatformUser;
use App\Services\Entitlements\WorkspaceCommercialLifecycleResolver;
use App\Services\ReviewPackService;
use App\Services\Settings\SettingsWriter;
use App\Support\Audit\AuditActionId;
use App\Support\Auth\PlatformCapabilities;
use App\Support\ReviewPackStatus;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;

uses(RefreshDatabase::class);

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

// ─── Helper ──────────────────────────────────────────────────

function createReadyPackWithFile(?array $packOverrides = []): array
{
    [$user, $tenant] = createUserWithTenant();

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

    $pack = ReviewPack::factory()->ready()->create(array_merge([
        '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',
        'sha256' => hash('sha256', 'PK-fake-zip-content'),
    ], $packOverrides));

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

function suspendReadyPackWorkspaceForDownloadTest(ReviewPack $pack): void
{
    app(SettingsWriter::class)->updateWorkspaceCommercialLifecycle(
        actor: PlatformUser::factory()->create([
            'capabilities' => [
                PlatformCapabilities::ACCESS_SYSTEM_PANEL,
                PlatformCapabilities::DIRECTORY_VIEW,
                PlatformCapabilities::COMMERCIAL_LIFECYCLE_MANAGE,
            ],
            'is_active' => true,
        ]),
        workspace: $pack->workspace,
        state: WorkspaceCommercialLifecycleResolver::STATE_SUSPENDED_READ_ONLY,
        reason: 'Download preservation test',
    );
}

// ─── Happy Path: Signed URL → 200 ───────────────────────────

it('downloads a ready pack via signed URL with correct headers', function (): void {
    [$user, $tenant, $pack] = createReadyPackWithFile();

    $signedUrl = app(ReviewPackService::class)->generateDownloadUrl($pack, [
        'source_surface' => 'customer_review_workspace',
        'review_id' => '789',
        'tenant_filter_id' => (string) $tenant->getKey(),
        'interpretation_version' => 'compliance_evidence_mapping.v1',
    ]);
    $packCount = ReviewPack::query()->count();
    $operationRunCount = OperationRun::query()->count();

    $response = $this->actingAs($user)->get($signedUrl);

    $response->assertOk();
    $response->assertHeader('X-Review-Pack-SHA256', $pack->sha256);
    $response->assertDownload();

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

    expect($audit)->not->toBeNull()
        ->and($audit?->resource_type)->toBe('review_pack')
        ->and(data_get($audit?->metadata, 'review_pack_id'))->toBe((int) $pack->getKey())
        ->and(data_get($audit?->metadata, 'source_surface'))->toBe('customer_review_workspace')
        ->and(data_get($audit?->metadata, 'review_id'))->toBe('789')
        ->and(data_get($audit?->metadata, 'tenant_filter_id'))->toBe((string) $tenant->getKey())
        ->and(data_get($audit?->metadata, 'interpretation_version'))->toBe('compliance_evidence_mapping.v1')
        ->and(ReviewPack::query()->count())->toBe($packCount)
        ->and(OperationRun::query()->count())->toBe($operationRunCount);
});

it('keeps ready pack downloads available while the workspace is suspended read-only', function (): void {
    [$user, $tenant, $pack] = createReadyPackWithFile();
    suspendReadyPackWorkspaceForDownloadTest($pack);

    $signedUrl = app(ReviewPackService::class)->generateDownloadUrl($pack, [
        'source_surface' => 'suspended_read_only_check',
    ]);

    $response = $this->actingAs($user)->get($signedUrl);

    $response->assertOk();
    $response->assertHeader('X-Review-Pack-SHA256', $pack->sha256);
    $response->assertDownload();
});

// ─── Expired Signature → 403 ────────────────────────────────

it('rejects requests with an expired signature', function (): void {
    [$user, $tenant, $pack] = createReadyPackWithFile();

    // Generate a signed URL that expires immediately
    $signedUrl = URL::signedRoute(
        'admin.review-packs.download',
        ['reviewPack' => $pack->getKey()],
        now()->subMinute(),
    );

    $response = $this->actingAs($user)->get($signedUrl);

    $response->assertForbidden();
});

// ─── Expired Pack → 404 ─────────────────────────────────────

it('returns 404 for an expired pack', function (): void {
    [$user, $tenant, $pack] = createReadyPackWithFile([
        'status' => ReviewPackStatus::Expired->value,
    ]);

    $signedUrl = app(ReviewPackService::class)->generateDownloadUrl($pack);

    $response = $this->actingAs($user)->get($signedUrl);

    $response->assertNotFound();
});

// ─── Non-Ready Pack → 404 ───────────────────────────────────

it('returns 404 for a queued pack', function (): void {
    [$user, $tenant] = createUserWithTenant();

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

    $signedUrl = URL::signedRoute(
        'admin.review-packs.download',
        ['reviewPack' => $pack->getKey()],
        now()->addHour(),
    );

    $response = $this->actingAs($user)->get($signedUrl);

    $response->assertNotFound();
});

// ─── Non-Existent Pack → 404 ────────────────────────────────

it('returns 404 for a non-existent pack', function (): void {
    [$user, $tenant] = createUserWithTenant();

    $signedUrl = URL::signedRoute(
        'admin.review-packs.download',
        ['reviewPack' => 99999],
        now()->addHour(),
    );

    $response = $this->actingAs($user)->get($signedUrl);

    $response->assertNotFound();
});

// ─── Past Expiry Date → 404 ─────────────────────────────────

it('returns 404 when pack status is ready but expires_at is in the past', function (): void {
    [$user, $tenant, $pack] = createReadyPackWithFile([
        'expires_at' => now()->subDay(),
    ]);

    $signedUrl = URL::signedRoute(
        'admin.review-packs.download',
        ['reviewPack' => $pack->getKey()],
        now()->addHour(),
    );

    $response = $this->actingAs($user)->get($signedUrl);

    $response->assertNotFound();
});

// ─── Missing File on Disk → 404 ─────────────────────────────

it('returns 404 when file does not exist on disk', function (): void {
    [$user, $tenant] = createUserWithTenant();

    $pack = 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' => 'review-packs/does-not-exist.zip',
        'file_disk' => 'exports',
    ]);

    $signedUrl = URL::signedRoute(
        'admin.review-packs.download',
        ['reviewPack' => $pack->getKey()],
        now()->addHour(),
    );

    $response = $this->actingAs($user)->get($signedUrl);

    $response->assertNotFound();
});

// ─── Unsigned URL → 403 ─────────────────────────────────────

it('returns 403 for an unsigned URL', function (): void {
    [$user, $tenant, $pack] = createReadyPackWithFile();

    $response = $this->actingAs($user)->get(
        route('admin.review-packs.download', ['reviewPack' => $pack->getKey()]),
    );

    $response->assertForbidden();
});
