<?php

declare(strict_types=1);

use Tests\Support\TestLaneManifest;
use Tests\Support\TestLaneReport;

function heavyGovernanceSyntheticHotspots(): array
{
    return [
        ['file' => 'tests/Feature/Filament/BaselineProfileCaptureStartSurfaceTest.php', 'seconds' => 22.4],
        ['file' => 'tests/Feature/Filament/BaselineProfileCompareStartSurfaceTest.php', 'seconds' => 21.1],
        ['file' => 'tests/Feature/Filament/BaselineActionAuthorizationTest.php', 'seconds' => 19.5],
        ['file' => 'tests/Feature/Findings/FindingBulkActionsTest.php', 'seconds' => 18.2],
        ['file' => 'tests/Feature/Findings/FindingWorkflowRowActionsTest.php', 'seconds' => 14.8],
        ['file' => 'tests/Feature/Findings/FindingWorkflowViewActionsTest.php', 'seconds' => 13.6],
        ['file' => 'tests/Feature/SettingsFoundation/WorkspaceSettingsManageTest.php', 'seconds' => 12.7],
        ['file' => 'tests/Feature/Guards/ActionSurfaceContractTest.php', 'seconds' => 11.9],
        ['file' => 'tests/Feature/Guards/OperationLifecycleOpsUxGuardTest.php', 'seconds' => 10.4],
        ['file' => 'tests/Feature/Filament/PolicyResourceAdminSearchParityTest.php', 'seconds' => 4.2],
    ];
}

it('keeps lane artifact paths app-root relative under storage/logs/test-lanes', function (): void {
    $artifacts = TestLaneReport::artifactPaths('fast-feedback');
    $artifactContract = TestLaneManifest::artifactPublicationContract('fast-feedback');

    expect($artifacts)->toHaveKeys(['junit', 'summary', 'budget', 'report', 'profile', 'trendHistory']);

    expect($artifactContract['requiredFiles'])->toEqualCanonicalizing(['summary.md', 'budget.json', 'report.json', 'junit.xml', 'trend-history.json'])
        ->and($artifactContract['stagedNamePattern'])->toBe('{laneId}.{artifactFile}');

    foreach (array_values($artifacts) as $relativePath) {
        expect($relativePath)->toStartWith('storage/logs/test-lanes/');
    }
});

it('keeps only the skeleton file checked into the lane artifact directory', function (): void {
    $gitignore = base_path('storage/logs/test-lanes/.gitignore');

    expect(file_exists($gitignore))->toBeTrue()
        ->and((string) file_get_contents($gitignore))->toContain('*')
        ->and((string) file_get_contents($gitignore))->toContain('!.gitignore');
});

it('publishes heavy attribution, contract, and coverage payloads under the canonical artifact root', function (): void {
    $durationsByFile = collect(heavyGovernanceSyntheticHotspots())
        ->mapWithKeys(static fn (array $entry): array => [$entry['file'] => $entry['seconds']])
        ->all();

    $slowestEntries = collect(heavyGovernanceSyntheticHotspots())
        ->map(static fn (array $entry): array => [
            'label' => $entry['file'].'::synthetic',
            'subject' => $entry['file'].'::synthetic',
            'filePath' => $entry['file'],
            'durationSeconds' => $entry['seconds'],
            'wallClockSeconds' => $entry['seconds'],
            'laneId' => 'heavy-governance',
        ])
        ->values()
        ->all();

    $report = TestLaneReport::buildReport(
        laneId: 'heavy-governance',
        wallClockSeconds: 118.4,
        slowestEntries: $slowestEntries,
        durationsByFile: $durationsByFile,
    );

    expect($report['artifactDirectory'])->toBe('storage/logs/test-lanes')
        ->and($report['slowestEntries'])->toHaveCount(10)
        ->and($report)->toHaveKeys([
            'artifactPublicationContract',
            'knownWorkflowProfiles',
            'failureClasses',
            'trendHistoryArtifact',
            'trendCurrentAssessment',
            'trendHotspotSnapshot',
            'trendRecalibrationDecisions',
            'trendWarnings',
            'budgetContract',
            'hotspotInventory',
            'decompositionRecords',
            'slimmingDecisions',
            'authorGuidance',
            'inventoryCoverage',
            'budgetSnapshots',
            'budgetOutcome',
            'remainingOpenFamilies',
            'stabilizedFamilies',
        ])
        ->and(collect($report['classificationAttribution'])->pluck('classificationId')->all())
        ->toContain('ui-workflow', 'surface-guard', 'discovery-heavy')
        ->and(collect($report['familyAttribution'])->pluck('familyId')->all())
        ->toContain(
            'baseline-profile-start-surfaces',
            'findings-workflow-surfaces',
            'finding-bulk-actions-workflow',
            'workspace-settings-slice-management',
            'action-surface-contract',
            'ops-ux-governance',
        )
        ->and(collect($report['budgetEvaluations'])->pluck('targetType')->unique()->values()->all())
        ->toEqualCanonicalizing(['lane', 'classification', 'family'])
        ->and($report['familyBudgetEvaluations'])->not->toBeEmpty()
        ->and($report['inventoryCoverage']['meetsInclusionRule'])->toBeTrue()
        ->and($report['inventoryCoverage']['inventoryFamilyCount'])->toBe(6)
        ->and($report['budgetSnapshots'])->toHaveCount(2)
        ->and($report['budgetOutcome'])->toHaveKeys([
            'decisionStatus',
            'finalThresholdSeconds',
            'remainingOpenFamilies',
            'followUpDebt',
        ])
        ->and($report['knownWorkflowProfiles'])->toContain('heavy-governance-manual', 'heavy-governance-scheduled');
});

it('stages deterministic CI artifact bundles from the canonical lane outputs', function (): void {
    $artifactDirectory = 'storage/logs/test-lanes/contract-stage-test';
    $stagingDirectory = base_path('storage/logs/test-lanes/contract-stage-test/staged');
    $report = TestLaneReport::buildReport(
        laneId: 'fast-feedback',
        wallClockSeconds: 182.4,
        slowestEntries: [],
        durationsByFile: [],
        artifactDirectory: $artifactDirectory,
        ciContext: [
            'workflowId' => 'pr-fast-feedback',
            'triggerClass' => 'pull-request',
            'entryPointResolved' => true,
            'workflowLaneMatched' => true,
        ],
    );

    TestLaneReport::writeArtifacts(
        laneId: 'fast-feedback',
        report: $report,
        profileOutput: null,
        artifactDirectory: $artifactDirectory,
        exitCode: 0,
    );

        $artifactPaths = TestLaneReport::artifactPaths('fast-feedback', $artifactDirectory);

        file_put_contents(
                TestLaneManifest::absolutePath($artifactPaths['junit']),
                <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
    <testsuite name="fast-feedback" tests="1" assertions="1" errors="0" failures="0" skipped="0" time="0.1">
        <testcase name="synthetic" file="tests/Feature/Guards/TestLaneArtifactsContractTest.php" time="0.1" />
    </testsuite>
</testsuites>
XML,
        );

    $stagingResult = TestLaneReport::stageArtifacts(
        laneId: 'fast-feedback',
        stagingDirectory: $stagingDirectory,
        artifactDirectory: $artifactDirectory,
    );

    expect($stagingResult['complete'])->toBeTrue()
        ->and(collect($stagingResult['stagedArtifacts'])->pluck('artifactType')->all())
        ->toEqualCanonicalizing(['summary.md', 'budget.json', 'report.json', 'junit.xml', 'trend-history.json'])
        ->and(collect($stagingResult['stagedArtifacts'])->pluck('relativePath')->all())
        ->toContain(
            $stagingDirectory.'/fast-feedback.summary.md',
            $stagingDirectory.'/fast-feedback.budget.json',
            $stagingDirectory.'/fast-feedback.report.json',
            $stagingDirectory.'/fast-feedback.junit.xml',
            $stagingDirectory.'/fast-feedback.trend-history.json',
        );
});


it('publishes the shared fixture slimming comparison only for the governed standard lanes', function (): void {
    $fastFeedback = TestLaneReport::buildReport(
        laneId: 'fast-feedback',
        wallClockSeconds: 176.73623,
        slowestEntries: [],
        durationsByFile: [],
        comparisonProfile: 'shared-test-fixture-slimming',
    );

    $heavyGovernance = TestLaneReport::buildReport(
        laneId: 'heavy-governance',
        wallClockSeconds: 83.66,
        slowestEntries: [],
        durationsByFile: [],
        comparisonProfile: 'shared-test-fixture-slimming',
    );

    expect($fastFeedback)->toHaveKey('sharedFixtureSlimmingComparison')
        ->and($heavyGovernance)->not->toHaveKey('sharedFixtureSlimmingComparison');
});
