<?php

declare(strict_types=1);

use App\Jobs\GenerateReviewPackJob;
use App\Models\EvidenceSnapshot;
use App\Models\Finding;
use App\Models\OperationRun;
use App\Models\StoredReport;
use App\Services\Evidence\EvidenceSnapshotService;
use App\Services\ReviewPackService;
use App\Support\Evidence\EvidenceSnapshotStatus;
use App\Support\OperationRunType;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Storage;

uses(RefreshDatabase::class);

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

function createRedactionReviewPackSnapshot($tenant): EvidenceSnapshot
{
    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::PolicySync->value,
    ]);

    /** @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;
}

it('redacts protected report fields while preserving safe configuration evidence in review-pack exports', function (): void {
    [$user, $tenant] = createUserWithTenant();

    StoredReport::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'report_type' => StoredReport::REPORT_TYPE_PERMISSION_POSTURE,
        'payload' => [
            'passwordMinimumLength' => 14,
            'clientSecret' => 'super-secret-value',
        ],
    ]);

    createRedactionReviewPackSnapshot($tenant);

    Notification::fake();

    $pack = app(ReviewPackService::class)->generate($tenant, $user, [
        'include_pii' => true,
        'include_operations' => false,
    ]);

    $job = new GenerateReviewPackJob(
        reviewPackId: (int) $pack->getKey(),
        operationRunId: (int) $pack->operation_run_id,
    );

    app()->call([$job, 'handle']);

    $pack->refresh();

    $zipContent = Storage::disk('exports')->get($pack->file_path);
    $tempFile = tempnam(sys_get_temp_dir(), 'spec120-review-pack-');
    file_put_contents($tempFile, $zipContent);

    $zip = new ZipArchive;
    $zip->open($tempFile);

    $report = json_decode((string) $zip->getFromName('reports/permission_posture.json'), true, 512, JSON_THROW_ON_ERROR);
    $metadata = json_decode((string) $zip->getFromName('metadata.json'), true, 512, JSON_THROW_ON_ERROR);

    expect($report['passwordMinimumLength'] ?? null)->toBe(14);
    expect($report['clientSecret'] ?? null)->toBe('[REDACTED]');
    expect(data_get($metadata, 'redaction_integrity.protected_values_hidden'))->toBeTrue();

    $zip->close();
    unlink($tempFile);
});
