<?php

declare(strict_types=1);

use App\Support\Ui\GovernanceActions\Enums\GovernanceFrictionClass;
use App\Support\Ui\GovernanceActions\Enums\GovernanceReasonPolicy;
use App\Support\Ui\GovernanceActions\GovernanceActionCatalog;

it('keeps the spec 194 governance catalog aligned to the approved action matrix', function (
    string $actionKey,
    GovernanceFrictionClass $expectedFriction,
    GovernanceReasonPolicy $expectedReasonPolicy,
    string $expectedLabel,
): void {
    $rule = GovernanceActionCatalog::rule($actionKey);

    expect($rule->frictionClass)->toBe($expectedFriction)
        ->and($rule->reasonPolicy)->toBe($expectedReasonPolicy)
        ->and($rule->canonicalLabel)->toBe($expectedLabel)
        ->and($rule->requiresConfirmation())->toBeTrue()
        ->and($rule->surfaceKeys)->not->toBeEmpty();
})->with([
    'approve exception' => ['approve_exception', GovernanceFrictionClass::F2, GovernanceReasonPolicy::Required, 'Approve exception'],
    'reject exception' => ['reject_exception', GovernanceFrictionClass::F2, GovernanceReasonPolicy::Required, 'Reject exception'],
    'renew exception' => ['renew_exception', GovernanceFrictionClass::F2, GovernanceReasonPolicy::Required, 'Renew exception'],
    'revoke exception' => ['revoke_exception', GovernanceFrictionClass::F3, GovernanceReasonPolicy::Required, 'Revoke exception'],
    'refresh review' => ['refresh_review', GovernanceFrictionClass::F1, GovernanceReasonPolicy::None, 'Refresh review'],
    'publish review' => ['publish_review', GovernanceFrictionClass::F2, GovernanceReasonPolicy::Required, 'Publish review'],
    'archive review' => ['archive_review', GovernanceFrictionClass::F3, GovernanceReasonPolicy::Required, 'Archive review'],
    'refresh evidence' => ['refresh_evidence', GovernanceFrictionClass::F1, GovernanceReasonPolicy::None, 'Refresh evidence'],
    'expire snapshot' => ['expire_snapshot', GovernanceFrictionClass::F2, GovernanceReasonPolicy::Required, 'Expire snapshot'],
    'retry run' => ['retry_run', GovernanceFrictionClass::F1, GovernanceReasonPolicy::None, 'Retry'],
    'mark investigated' => ['mark_investigated', GovernanceFrictionClass::F2, GovernanceReasonPolicy::Required, 'Mark investigated'],
    'cancel run' => ['cancel_run', GovernanceFrictionClass::F3, GovernanceReasonPolicy::Required, 'Cancel'],
    'close finding' => ['close_finding', GovernanceFrictionClass::F2, GovernanceReasonPolicy::Required, 'Close'],
    'reopen finding' => ['reopen_finding', GovernanceFrictionClass::F2, GovernanceReasonPolicy::Required, 'Reopen'],
    'archive tenant' => ['archive_tenant', GovernanceFrictionClass::F3, GovernanceReasonPolicy::Required, 'Archive'],
    'restore tenant' => ['restore_tenant', GovernanceFrictionClass::F1, GovernanceReasonPolicy::None, 'Restore'],
]);

it('keeps the f1 actions on the current-release no-rationale path', function (): void {
    expect(GovernanceActionCatalog::rule('refresh_review')->reasonPolicy)->toBe(GovernanceReasonPolicy::None)
        ->and(GovernanceActionCatalog::rule('refresh_evidence')->reasonPolicy)->toBe(GovernanceReasonPolicy::None)
        ->and(GovernanceActionCatalog::rule('retry_run')->reasonPolicy)->toBe(GovernanceReasonPolicy::None)
        ->and(GovernanceActionCatalog::rule('restore_tenant')->reasonPolicy)->toBe(GovernanceReasonPolicy::None);
});

it('keeps governed surface bindings on canonical action names', function (): void {
    $bindingsBySurface = collect(GovernanceActionCatalog::surfaceBindings())->groupBy('surfaceKey');

    expect($bindingsBySurface->get('view_evidence_snapshot', collect())->pluck('actionName')->all())
        ->toEqualCanonicalizing(['refresh_evidence', 'expire_snapshot'])
        ->and($bindingsBySurface->get('view_environment_review', collect())->pluck('actionName')->all())
        ->toContain('refresh_review', 'publish_review', 'archive_review');
});

it('documents the current-release deviations instead of relying on silent local overrides', function (): void {
    $deviations = collect(GovernanceActionCatalog::documentedDeviations())
        ->map(fn (array $deviation): string => $deviation['actionKey'].'@'.$deviation['surfaceKey'])
        ->all();

    expect($deviations)->toContain(
        'reject_exception@finding_exceptions_queue',
        'refresh_evidence@view_evidence_snapshot',
        'retry_run@system_view_run',
        'restore_tenant@view_tenant',
    );
});

it('keeps every required-reason binding attached to a concrete ui field', function (): void {
    $rules = collect(GovernanceActionCatalog::rules());
    $bindingsByAction = collect(GovernanceActionCatalog::surfaceBindings())
        ->groupBy('actionName');

    foreach ([
        'approve_selected_exception' => 'approve_exception',
        'reject_selected_exception' => 'reject_exception',
        'renew_exception' => 'renew_exception',
        'revoke_exception' => 'revoke_exception',
        'publish_review' => 'publish_review',
        'archive_review' => 'archive_review',
        'expire_snapshot' => 'expire_snapshot',
        'expire' => 'expire_snapshot',
        'mark_investigated' => 'mark_investigated',
        'cancel' => 'cancel_run',
        'close' => 'close_finding',
        'reopen' => 'reopen_finding',
        'archive' => 'archive_tenant',
    ] as $bindingAction => $ruleKey) {
        $rule = $rules->get($ruleKey);
        $binding = $bindingsByAction->get($bindingAction, collect())->first();

        expect($rule?->requiresReason())->toBeTrue()
            ->and($binding)->not->toBeNull()
            ->and($binding['uiFieldKey'] ?? null)->not->toBeNull();
    }
});
