<?php

declare(strict_types=1);

namespace App\Support\Ui\GovernanceActions;

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

final class GovernanceActionCatalog
{
    /**
     * @return array<string, array{
     *     familyKey: string,
     *     canonicalObject: string,
     *     panels: array<int, string>,
     *     surfaceKeys: array<int, string>,
     *     defaultActionOrder: array<int, string>,
     *     supportsDocumentedDeviation: bool,
     *     defaultMutationScopeSource: string
     * }>
     */
    public static function families(): array
    {
        return [
            'exception_decision' => [
                'familyKey' => 'exception_decision',
                'canonicalObject' => 'exception',
                'panels' => ['admin', 'tenant'],
                'surfaceKeys' => ['finding_exceptions_queue', 'view_finding_exception', 'view_finding'],
                'defaultActionOrder' => [
                    'approve_exception',
                    'reject_exception',
                    'renew_exception',
                    'revoke_exception',
                ],
                'supportsDocumentedDeviation' => true,
                'defaultMutationScopeSource' => 'exception governance',
            ],
            'review_lifecycle' => [
                'familyKey' => 'review_lifecycle',
                'canonicalObject' => 'review',
                'panels' => ['tenant'],
                'surfaceKeys' => ['view_environment_review'],
                'defaultActionOrder' => ['refresh_review', 'publish_review', 'archive_review'],
                'supportsDocumentedDeviation' => true,
                'defaultMutationScopeSource' => 'environment review lifecycle',
            ],
            'evidence_lifecycle' => [
                'familyKey' => 'evidence_lifecycle',
                'canonicalObject' => 'snapshot',
                'panels' => ['tenant'],
                'surfaceKeys' => ['list_evidence_snapshots', 'view_evidence_snapshot'],
                'defaultActionOrder' => ['refresh_evidence', 'expire_snapshot'],
                'supportsDocumentedDeviation' => true,
                'defaultMutationScopeSource' => 'evidence lifecycle',
            ],
            'run_triage' => [
                'familyKey' => 'run_triage',
                'canonicalObject' => 'run',
                'panels' => ['system'],
                'surfaceKeys' => ['system_view_run'],
                'defaultActionOrder' => ['retry_run', 'mark_investigated', 'cancel_run'],
                'supportsDocumentedDeviation' => true,
                'defaultMutationScopeSource' => 'run triage',
            ],
            'finding_lifecycle' => [
                'familyKey' => 'finding_lifecycle',
                'canonicalObject' => 'finding',
                'panels' => ['tenant'],
                'surfaceKeys' => ['view_finding', 'finding_list_row', 'finding_bulk'],
                'defaultActionOrder' => ['resolve_finding', 'close_finding', 'reopen_finding'],
                'supportsDocumentedDeviation' => false,
                'defaultMutationScopeSource' => 'finding lifecycle',
            ],
            'tenant_lifecycle' => [
                'familyKey' => 'tenant_lifecycle',
                'canonicalObject' => 'tenant',
                'panels' => ['admin'],
                'surfaceKeys' => ['tenant_index_row', 'view_tenant', 'edit_tenant'],
                'defaultActionOrder' => ['archive_tenant', 'restore_tenant'],
                'supportsDocumentedDeviation' => true,
                'defaultMutationScopeSource' => 'tenant lifecycle',
            ],
        ];
    }

    /**
     * @return array<string, GovernanceActionRule>
     */
    public static function rules(): array
    {
        return [
            'approve_exception' => new GovernanceActionRule(
                actionKey: 'approve_exception',
                familyKey: 'exception_decision',
                frictionClass: GovernanceFrictionClass::F2,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'none',
                canonicalLabel: 'Approve exception',
                modalHeading: 'Approve exception',
                modalDescription: 'Approve this exception request for the selected tenant and linked finding. TenantPilot updates the governed exception decision and risk-acceptance continuity only.',
                successTitle: 'Exception approved',
                auditVerb: 'approve exception',
                serviceOwner: 'FindingExceptionService',
                surfaceKeys: ['finding_exceptions_queue'],
            ),
            'reject_exception' => new GovernanceActionRule(
                actionKey: 'reject_exception',
                familyKey: 'exception_decision',
                frictionClass: GovernanceFrictionClass::F2,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'contextual',
                canonicalLabel: 'Reject exception',
                modalHeading: 'Reject exception',
                modalDescription: 'Reject this exception request for the selected tenant and linked finding. TenantPilot records the governance decision and leaves the finding out of governed risk acceptance.',
                successTitle: 'Exception rejected',
                auditVerb: 'reject exception',
                serviceOwner: 'FindingExceptionService',
                surfaceKeys: ['finding_exceptions_queue'],
            ),
            'renew_exception' => new GovernanceActionRule(
                actionKey: 'renew_exception',
                familyKey: 'exception_decision',
                frictionClass: GovernanceFrictionClass::F2,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'none',
                canonicalLabel: 'Renew exception',
                modalHeading: 'Renew exception',
                modalDescription: 'Submit a renewal request for this governed exception. TenantPilot records the request and keeps the formal decision pending until it is reviewed.',
                successTitle: 'Renewal request submitted',
                auditVerb: 'renew exception',
                serviceOwner: 'FindingExceptionService',
                surfaceKeys: ['view_finding_exception', 'view_finding'],
            ),
            'revoke_exception' => new GovernanceActionRule(
                actionKey: 'revoke_exception',
                familyKey: 'exception_decision',
                frictionClass: GovernanceFrictionClass::F3,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'required',
                canonicalLabel: 'Revoke exception',
                modalHeading: 'Revoke exception',
                modalDescription: 'Revoke this active exception for the tenant and linked finding. TenantPilot records the revocation and removes the governed exception support.',
                successTitle: 'Exception revoked',
                auditVerb: 'revoke exception',
                serviceOwner: 'FindingExceptionService',
                surfaceKeys: ['view_finding_exception', 'view_finding'],
            ),
            'refresh_review' => new GovernanceActionRule(
                actionKey: 'refresh_review',
                familyKey: 'review_lifecycle',
                frictionClass: GovernanceFrictionClass::F1,
                reasonPolicy: GovernanceReasonPolicy::None,
                dangerPolicy: 'none',
                canonicalLabel: 'Refresh review',
                modalHeading: 'Refresh review',
                modalDescription: 'Refresh this environment review from the latest eligible evidence basis. TenantPilot queues a recomputation for this review and keeps existing publication history untouched.',
                successTitle: 'Refresh review queued',
                auditVerb: 'refresh review',
                serviceOwner: 'EnvironmentReviewService',
                surfaceKeys: ['view_environment_review'],
            ),
            'publish_review' => new GovernanceActionRule(
                actionKey: 'publish_review',
                familyKey: 'review_lifecycle',
                frictionClass: GovernanceFrictionClass::F2,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'none',
                canonicalLabel: 'Publish review',
                modalHeading: 'Publish review',
                modalDescription: 'Publish this environment review as the current governed review outcome for this tenant. TenantPilot records the publication decision only.',
                successTitle: 'Review published',
                auditVerb: 'publish review',
                serviceOwner: 'EnvironmentReviewLifecycleService',
                surfaceKeys: ['view_environment_review'],
            ),
            'archive_review' => new GovernanceActionRule(
                actionKey: 'archive_review',
                familyKey: 'review_lifecycle',
                frictionClass: GovernanceFrictionClass::F3,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'required',
                canonicalLabel: 'Archive review',
                modalHeading: 'Archive review',
                modalDescription: 'Archive this environment review so it stays historical only. TenantPilot preserves the evidence history but removes the review from active lifecycle work.',
                successTitle: 'Review archived',
                auditVerb: 'archive review',
                serviceOwner: 'EnvironmentReviewLifecycleService',
                surfaceKeys: ['view_environment_review'],
            ),
            'refresh_evidence' => new GovernanceActionRule(
                actionKey: 'refresh_evidence',
                familyKey: 'evidence_lifecycle',
                frictionClass: GovernanceFrictionClass::F1,
                reasonPolicy: GovernanceReasonPolicy::None,
                dangerPolicy: 'none',
                canonicalLabel: 'Refresh evidence',
                modalHeading: 'Refresh evidence',
                modalDescription: 'Refresh content evidence for this tenant. TenantPilot queues a new snapshot and leaves existing governed snapshots intact.',
                successTitle: 'Refresh evidence queued',
                auditVerb: 'refresh evidence',
                serviceOwner: 'EvidenceSnapshotService',
                surfaceKeys: ['view_evidence_snapshot'],
            ),
            'expire_snapshot' => new GovernanceActionRule(
                actionKey: 'expire_snapshot',
                familyKey: 'evidence_lifecycle',
                frictionClass: GovernanceFrictionClass::F2,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'required',
                canonicalLabel: 'Expire snapshot',
                modalHeading: 'Expire snapshot',
                modalDescription: 'Expire this evidence snapshot for the current tenant. TenantPilot records that the snapshot is no longer valid for governance use.',
                successTitle: 'Snapshot expired',
                auditVerb: 'expire snapshot',
                serviceOwner: 'EvidenceSnapshotService',
                surfaceKeys: ['list_evidence_snapshots', 'view_evidence_snapshot'],
            ),
            'retry_run' => new GovernanceActionRule(
                actionKey: 'retry_run',
                familyKey: 'run_triage',
                frictionClass: GovernanceFrictionClass::F1,
                reasonPolicy: GovernanceReasonPolicy::None,
                dangerPolicy: 'none',
                canonicalLabel: 'Retry',
                modalHeading: 'Retry run',
                modalDescription: 'Retry this failed run. TenantPilot queues a new run and preserves the original run history.',
                successTitle: 'Retry queued',
                auditVerb: 'retry run',
                serviceOwner: 'OperationRunTriageService',
                surfaceKeys: ['system_view_run'],
            ),
            'mark_investigated' => new GovernanceActionRule(
                actionKey: 'mark_investigated',
                familyKey: 'run_triage',
                frictionClass: GovernanceFrictionClass::F2,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'none',
                canonicalLabel: 'Mark investigated',
                modalHeading: 'Mark investigated',
                modalDescription: 'Mark this run as investigated. TenantPilot records the triage rationale on this run only.',
                successTitle: 'Run marked as investigated',
                auditVerb: 'mark investigated',
                serviceOwner: 'OperationRunTriageService',
                surfaceKeys: ['system_view_run'],
            ),
            'cancel_run' => new GovernanceActionRule(
                actionKey: 'cancel_run',
                familyKey: 'run_triage',
                frictionClass: GovernanceFrictionClass::F3,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'required',
                canonicalLabel: 'Cancel',
                modalHeading: 'Cancel run',
                modalDescription: 'Cancel this in-flight run. TenantPilot records the cancellation reason and marks the run as failed.',
                successTitle: 'Run cancelled',
                auditVerb: 'cancel run',
                serviceOwner: 'OperationRunTriageService',
                surfaceKeys: ['system_view_run'],
            ),
            'resolve_finding' => new GovernanceActionRule(
                actionKey: 'resolve_finding',
                familyKey: 'finding_lifecycle',
                frictionClass: GovernanceFrictionClass::F2,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'none',
                canonicalLabel: 'Resolve',
                modalHeading: 'Resolve finding',
                modalDescription: 'Resolve this finding for the current tenant. TenantPilot records a canonical remediation outcome and keeps the finding in a pending-verification state until trusted evidence later confirms it is actually clear.',
                successTitle: 'Finding resolved pending verification',
                auditVerb: 'resolve finding',
                serviceOwner: 'FindingWorkflowService',
                surfaceKeys: ['view_finding', 'finding_list_row', 'finding_bulk'],
            ),
            'close_finding' => new GovernanceActionRule(
                actionKey: 'close_finding',
                familyKey: 'finding_lifecycle',
                frictionClass: GovernanceFrictionClass::F2,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'none',
                canonicalLabel: 'Close',
                modalHeading: 'Close finding',
                modalDescription: 'Close this finding for the current tenant. TenantPilot records a canonical administrative closure reason such as false positive, duplicate, or no longer applicable.',
                successTitle: 'Finding closed',
                auditVerb: 'close finding',
                serviceOwner: 'FindingWorkflowService',
                surfaceKeys: ['view_finding', 'finding_list_row', 'finding_bulk'],
            ),
            'reopen_finding' => new GovernanceActionRule(
                actionKey: 'reopen_finding',
                familyKey: 'finding_lifecycle',
                frictionClass: GovernanceFrictionClass::F2,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'none',
                canonicalLabel: 'Reopen',
                modalHeading: 'Reopen finding',
                modalDescription: 'Reopen this terminal finding for the current tenant. TenantPilot records a canonical reopen reason and recalculates due attention.',
                successTitle: 'Finding reopened',
                auditVerb: 'reopen finding',
                serviceOwner: 'FindingWorkflowService',
                surfaceKeys: ['view_finding', 'finding_list_row', 'finding_bulk'],
            ),
            'archive_tenant' => new GovernanceActionRule(
                actionKey: 'archive_tenant',
                familyKey: 'tenant_lifecycle',
                frictionClass: GovernanceFrictionClass::F3,
                reasonPolicy: GovernanceReasonPolicy::Required,
                dangerPolicy: 'required',
                canonicalLabel: 'Archive',
                modalHeading: 'Archive environment',
                modalDescription: 'Archive this environment. TenantPilot keeps it available for inspection and audit history but removes it from active management flows.',
                successTitle: 'Environment archived',
                auditVerb: 'archive environment',
                serviceOwner: 'ManagedEnvironmentResource',
                surfaceKeys: ['tenant_index_row', 'view_tenant', 'edit_tenant'],
            ),
            'restore_tenant' => new GovernanceActionRule(
                actionKey: 'restore_tenant',
                familyKey: 'tenant_lifecycle',
                frictionClass: GovernanceFrictionClass::F1,
                reasonPolicy: GovernanceReasonPolicy::None,
                dangerPolicy: 'none',
                canonicalLabel: 'Restore',
                modalHeading: 'Restore environment',
                modalDescription: 'Restore this environment so it becomes available again in normal management flows.',
                successTitle: 'Environment restored',
                auditVerb: 'restore environment',
                serviceOwner: 'ManagedEnvironmentResource',
                surfaceKeys: ['tenant_index_row', 'view_tenant', 'edit_tenant'],
            ),
        ];
    }

    public static function rule(string $actionKey): GovernanceActionRule
    {
        $rule = static::rules()[$actionKey] ?? null;

        if (! $rule instanceof GovernanceActionRule) {
            throw new InvalidArgumentException(sprintf('Unknown governance action "%s".', $actionKey));
        }

        return $rule;
    }

    /**
     * @return array<int, array{
     *     surfaceKey: string,
     *     pageClass: string,
     *     actionName: string,
     *     familyKey: string,
     *     statePredicate: string,
     *     primaryOrSecondary: string,
     *     capabilityKey: string|null,
     *     uiFieldKey: string|null,
     *     auditChannel: string
     * }>
     */
    public static function surfaceBindings(): array
    {
        return [
            [
                'surfaceKey' => 'finding_exceptions_queue',
                'pageClass' => 'App\\Filament\\Pages\\Monitoring\\FindingExceptionsQueue',
                'actionName' => 'approve_selected_exception',
                'familyKey' => 'exception_decision',
                'statePredicate' => 'selected exception is pending',
                'primaryOrSecondary' => 'primary',
                'capabilityKey' => 'finding_exception.approve',
                'uiFieldKey' => 'approval_reason',
                'auditChannel' => 'tenant_audit',
            ],
            [
                'surfaceKey' => 'finding_exceptions_queue',
                'pageClass' => 'App\\Filament\\Pages\\Monitoring\\FindingExceptionsQueue',
                'actionName' => 'reject_selected_exception',
                'familyKey' => 'exception_decision',
                'statePredicate' => 'selected exception is pending',
                'primaryOrSecondary' => 'primary',
                'capabilityKey' => 'finding_exception.approve',
                'uiFieldKey' => 'rejection_reason',
                'auditChannel' => 'tenant_audit',
            ],
            [
                'surfaceKey' => 'view_finding_exception',
                'pageClass' => 'App\\Filament\\Resources\\FindingExceptionResource\\Pages\\ViewFindingException',
                'actionName' => 'renew_exception',
                'familyKey' => 'exception_decision',
                'statePredicate' => 'exception can be renewed',
                'primaryOrSecondary' => 'primary',
                'capabilityKey' => 'finding_exception.manage',
                'uiFieldKey' => 'request_reason',
                'auditChannel' => 'tenant_audit',
            ],
            [
                'surfaceKey' => 'view_finding_exception',
                'pageClass' => 'App\\Filament\\Resources\\FindingExceptionResource\\Pages\\ViewFindingException',
                'actionName' => 'revoke_exception',
                'familyKey' => 'exception_decision',
                'statePredicate' => 'exception can be revoked',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'finding_exception.manage',
                'uiFieldKey' => 'revocation_reason',
                'auditChannel' => 'tenant_audit',
            ],
            [
                'surfaceKey' => 'view_evidence_snapshot',
                'pageClass' => 'App\\Filament\\Resources\\EvidenceSnapshotResource\\Pages\\ViewEvidenceSnapshot',
                'actionName' => 'refresh_evidence',
                'familyKey' => 'evidence_lifecycle',
                'statePredicate' => 'snapshot is visible to tenant operator',
                'primaryOrSecondary' => 'primary',
                'capabilityKey' => 'evidence.manage',
                'uiFieldKey' => null,
                'auditChannel' => 'workspace_audit',
            ],
            [
                'surfaceKey' => 'view_evidence_snapshot',
                'pageClass' => 'App\\Filament\\Resources\\EvidenceSnapshotResource\\Pages\\ViewEvidenceSnapshot',
                'actionName' => 'expire_snapshot',
                'familyKey' => 'evidence_lifecycle',
                'statePredicate' => 'snapshot can expire',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'evidence.manage',
                'uiFieldKey' => 'expiration_reason',
                'auditChannel' => 'workspace_audit',
            ],
            [
                'surfaceKey' => 'list_evidence_snapshots',
                'pageClass' => 'App\\Filament\\Resources\\EvidenceSnapshotResource',
                'actionName' => 'expire',
                'familyKey' => 'evidence_lifecycle',
                'statePredicate' => 'snapshot can expire',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'evidence.manage',
                'uiFieldKey' => 'expiration_reason',
                'auditChannel' => 'workspace_audit',
            ],
            [
                'surfaceKey' => 'view_environment_review',
                'pageClass' => 'App\\Filament\\Resources\\EnvironmentReviewResource\\Pages\\ViewEnvironmentReview',
                'actionName' => 'refresh_review',
                'familyKey' => 'review_lifecycle',
                'statePredicate' => 'review is mutable',
                'primaryOrSecondary' => 'primary',
                'capabilityKey' => 'environment_review.manage',
                'uiFieldKey' => null,
                'auditChannel' => 'workspace_audit',
            ],
            [
                'surfaceKey' => 'view_environment_review',
                'pageClass' => 'App\\Filament\\Resources\\EnvironmentReviewResource\\Pages\\ViewEnvironmentReview',
                'actionName' => 'publish_review',
                'familyKey' => 'review_lifecycle',
                'statePredicate' => 'review is mutable and ready to publish',
                'primaryOrSecondary' => 'primary',
                'capabilityKey' => 'environment_review.manage',
                'uiFieldKey' => 'publish_reason',
                'auditChannel' => 'workspace_audit',
            ],
            [
                'surfaceKey' => 'view_environment_review',
                'pageClass' => 'App\\Filament\\Resources\\EnvironmentReviewResource\\Pages\\ViewEnvironmentReview',
                'actionName' => 'archive_review',
                'familyKey' => 'review_lifecycle',
                'statePredicate' => 'review is not terminal',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'environment_review.manage',
                'uiFieldKey' => 'archive_reason',
                'auditChannel' => 'workspace_audit',
            ],
            [
                'surfaceKey' => 'system_view_run',
                'pageClass' => 'App\\Filament\\System\\Pages\\Ops\\ViewRun',
                'actionName' => 'retry',
                'familyKey' => 'run_triage',
                'statePredicate' => 'run is retryable',
                'primaryOrSecondary' => 'primary',
                'capabilityKey' => 'platform.operations.manage',
                'uiFieldKey' => null,
                'auditChannel' => 'system_audit',
            ],
            [
                'surfaceKey' => 'system_view_run',
                'pageClass' => 'App\\Filament\\System\\Pages\\Ops\\ViewRun',
                'actionName' => 'mark_investigated',
                'familyKey' => 'run_triage',
                'statePredicate' => 'run is triage-owned',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'platform.operations.manage',
                'uiFieldKey' => 'reason',
                'auditChannel' => 'system_audit',
            ],
            [
                'surfaceKey' => 'system_view_run',
                'pageClass' => 'App\\Filament\\System\\Pages\\Ops\\ViewRun',
                'actionName' => 'cancel',
                'familyKey' => 'run_triage',
                'statePredicate' => 'run is cancellable',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'platform.operations.manage',
                'uiFieldKey' => 'reason',
                'auditChannel' => 'system_audit',
            ],
            [
                'surfaceKey' => 'view_finding',
                'pageClass' => 'App\\Filament\\Resources\\FindingResource\\Pages\\ViewFinding',
                'actionName' => 'resolve',
                'familyKey' => 'finding_lifecycle',
                'statePredicate' => 'finding has open status',
                'primaryOrSecondary' => 'primary',
                'capabilityKey' => 'tenant_findings.resolve',
                'uiFieldKey' => 'resolved_reason',
                'auditChannel' => 'tenant_audit',
            ],
            [
                'surfaceKey' => 'view_finding',
                'pageClass' => 'App\\Filament\\Resources\\FindingResource\\Pages\\ViewFinding',
                'actionName' => 'close',
                'familyKey' => 'finding_lifecycle',
                'statePredicate' => 'finding has open status',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'tenant_findings.close',
                'uiFieldKey' => 'closed_reason',
                'auditChannel' => 'tenant_audit',
            ],
            [
                'surfaceKey' => 'view_finding',
                'pageClass' => 'App\\Filament\\Resources\\FindingResource\\Pages\\ViewFinding',
                'actionName' => 'reopen',
                'familyKey' => 'finding_lifecycle',
                'statePredicate' => 'finding has terminal status',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'tenant_findings.triage',
                'uiFieldKey' => 'reopen_reason',
                'auditChannel' => 'tenant_audit',
            ],
            [
                'surfaceKey' => 'view_tenant',
                'pageClass' => 'App\\Filament\\Resources\\ManagedEnvironmentResource\\Pages\\ViewManagedEnvironment',
                'actionName' => 'archive',
                'familyKey' => 'tenant_lifecycle',
                'statePredicate' => 'tenant is active',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'tenant.delete',
                'uiFieldKey' => 'archive_reason',
                'auditChannel' => 'workspace_audit',
            ],
            [
                'surfaceKey' => 'view_tenant',
                'pageClass' => 'App\\Filament\\Resources\\ManagedEnvironmentResource\\Pages\\ViewManagedEnvironment',
                'actionName' => 'restore',
                'familyKey' => 'tenant_lifecycle',
                'statePredicate' => 'tenant is archived',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'tenant.delete',
                'uiFieldKey' => null,
                'auditChannel' => 'workspace_audit',
            ],
            [
                'surfaceKey' => 'edit_tenant',
                'pageClass' => 'App\\Filament\\Resources\\ManagedEnvironmentResource\\Pages\\EditManagedEnvironment',
                'actionName' => 'archive',
                'familyKey' => 'tenant_lifecycle',
                'statePredicate' => 'tenant is active',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'tenant.delete',
                'uiFieldKey' => 'archive_reason',
                'auditChannel' => 'workspace_audit',
            ],
            [
                'surfaceKey' => 'edit_tenant',
                'pageClass' => 'App\\Filament\\Resources\\ManagedEnvironmentResource\\Pages\\EditManagedEnvironment',
                'actionName' => 'restore',
                'familyKey' => 'tenant_lifecycle',
                'statePredicate' => 'tenant is archived',
                'primaryOrSecondary' => 'secondary',
                'capabilityKey' => 'tenant.delete',
                'uiFieldKey' => null,
                'auditChannel' => 'workspace_audit',
            ],
        ];
    }

    /**
     * @return array<int, array{
     *     actionKey: string,
     *     surfaceKey: string,
     *     deviationType: string,
     *     rationale: string,
     *     reviewGate: string,
     *     allowedUntil: string|null
     * }>
     */
    public static function documentedDeviations(): array
    {
        return [
            [
                'actionKey' => 'reject_exception',
                'surfaceKey' => 'finding_exceptions_queue',
                'deviationType' => 'danger_override',
                'rationale' => 'Reject stays visually distinct from approval without escalating into the F3 destructive family.',
                'reviewGate' => 'Spec194GovernanceActionSemanticsGuardTest',
                'allowedUntil' => null,
            ],
            [
                'actionKey' => 'refresh_evidence',
                'surfaceKey' => 'view_evidence_snapshot',
                'deviationType' => 'reason_override',
                'rationale' => 'Refresh evidence remains an F1 action with no operator-entered rationale in the current release.',
                'reviewGate' => 'Spec194GovernanceActionSemanticsGuardTest',
                'allowedUntil' => null,
            ],
            [
                'actionKey' => 'retry_run',
                'surfaceKey' => 'system_view_run',
                'deviationType' => 'reason_override',
                'rationale' => 'Retry stays queue-first and does not collect free-text rationale unless a documented future case requires it.',
                'reviewGate' => 'Spec194GovernanceActionSemanticsGuardTest',
                'allowedUntil' => null,
            ],
            [
                'actionKey' => 'restore_tenant',
                'surfaceKey' => 'view_tenant',
                'deviationType' => 'reason_override',
                'rationale' => 'Restore remains a confirmed F1 lifecycle action with no required rationale in the current release.',
                'reviewGate' => 'Spec194GovernanceActionSemanticsGuardTest',
                'allowedUntil' => null,
            ],
        ];
    }

    /**
     * @return array<int, array{
     *     surfaceKey: string,
     *     pageClass: string,
     *     actionName: string,
     *     familyKey: string,
     *     statePredicate: string,
     *     primaryOrSecondary: string,
     *     capabilityKey: string|null,
     *     uiFieldKey: string|null,
     *     auditChannel: string
     * }>
     */
    public static function bindingsForSurface(string $surfaceKey): array
    {
        return array_values(array_filter(
            static::surfaceBindings(),
            static fn (array $binding): bool => $binding['surfaceKey'] === $surfaceKey,
        ));
    }

    /**
     * @return array<int, string>
     */
    public static function actionKeys(): array
    {
        return array_keys(static::rules());
    }
}
