<?php

namespace App\Filament\Resources;

use App\Filament\Concerns\InteractsWithTenantOwnedRecords;
use App\Filament\Concerns\ResolvesPanelTenantContext;
use App\Filament\Concerns\WorkspaceScopedEnvironmentRoutes;
use App\Filament\Resources\FindingResource\Pages;
use App\Filament\Support\NormalizedDiffSurface;
use App\Models\Finding;
use App\Models\FindingException;
use App\Models\ManagedEnvironment;
use App\Models\PolicyVersion;
use App\Models\User;
use App\Services\Auth\ManagedEnvironmentAccessScopeResolver;
use App\Services\Drift\DriftFindingDiffBuilder;
use App\Services\Findings\FindingExceptionService;
use App\Services\Findings\FindingRiskGovernanceResolver;
use App\Services\Findings\FindingWorkflowService;
use App\Support\Auth\Capabilities;
use App\Support\Badges\BadgeDomain;
use App\Support\Badges\BadgeRenderer;
use App\Support\Filament\FilterOptionCatalog;
use App\Support\Filament\FilterPresets;
use App\Support\Filament\TablePaginationProfiles;
use App\Support\Findings\FindingOutcomeSemantics;
use App\Support\Navigation\CanonicalNavigationContext;
use App\Support\Navigation\CrossResourceNavigationMatrix;
use App\Support\Navigation\NavigationScope;
use App\Support\Navigation\RelatedContextEntry;
use App\Support\Navigation\RelatedNavigationResolver;
use App\Support\OperationRunLinks;
use App\Support\Rbac\UiEnforcement;
use App\Support\Rbac\UiTooltips;
use App\Support\RedactionIntegrity;
use App\Support\Ui\ActionSurface\ActionSurfaceDeclaration;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceInspectAffordance;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceProfile;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceSlot;
use App\Support\Ui\GovernanceActions\GovernanceActionCatalog;
use BackedEnum;
use Filament\Actions;
use Filament\Actions\BulkAction;
use Filament\Actions\BulkActionGroup;
use Filament\Facades\Filament;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Infolists\Components\TextEntry;
use Filament\Infolists\Components\ViewEntry;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Throwable;
use UnitEnum;

class FindingResource extends Resource
{
    use InteractsWithTenantOwnedRecords;
    use ResolvesPanelTenantContext;
    use WorkspaceScopedEnvironmentRoutes;

    protected static ?string $model = Finding::class;

    protected static ?string $tenantOwnershipRelationshipName = 'tenant';

    protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-exclamation-triangle';

    protected static string|UnitEnum|null $navigationGroup = 'Governance';

    public static function shouldRegisterNavigation(): bool
    {
        return NavigationScope::shouldRegisterEnvironmentNavigation()
            && parent::shouldRegisterNavigation();
    }

    public static function getNavigationLabel(): string
    {
        return __('localization.navigation.findings');
    }

    public static function getNavigationGroup(): string
    {
        return __('localization.navigation.governance');
    }

    public static function getModelLabel(): string
    {
        return __('localization.navigation.findings');
    }

    public static function getPluralModelLabel(): string
    {
        return __('localization.navigation.findings');
    }

    public static function canViewAny(): bool
    {
        $tenant = static::resolveTenantContextForCurrentPanel();

        $user = auth()->user();

        if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
            return false;
        }

        if (! $user->canAccessTenant($tenant)) {
            return false;
        }

        return $user->can(Capabilities::TENANT_FINDINGS_VIEW, $tenant);
    }

    public static function canView(Model $record): bool
    {
        $tenant = static::resolveTenantContextForCurrentPanel();

        $user = auth()->user();

        if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
            return false;
        }

        if (! $user->canAccessTenant($tenant)) {
            return false;
        }

        if (! $user->can(Capabilities::TENANT_FINDINGS_VIEW, $tenant)) {
            return false;
        }

        if ($record instanceof Finding) {
            return (int) $record->managed_environment_id === (int) $tenant->getKey()
                && (int) $record->workspace_id === (int) $tenant->workspace_id;
        }

        return true;
    }

    public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
    {
        return ActionSurfaceDeclaration::forResource(ActionSurfaceProfile::CrudListAndView)
            ->satisfy(ActionSurfaceSlot::ListHeader, 'Header actions support filtered findings operations (legacy acknowledge-all-matching remains until bulk workflow migration).')
            ->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ClickableRow->value)
            ->satisfy(ActionSurfaceSlot::ListRowMoreMenu, 'Secondary workflow actions are grouped under "More"; the only inline row action is the related-record drill-down.')
            ->satisfy(ActionSurfaceSlot::ListBulkMoreGroup, 'Bulk actions are grouped under "More".')
            ->exempt(ActionSurfaceSlot::ListEmptyState, 'Findings are generated by drift detection and intentionally have no create CTA.')
            ->satisfy(ActionSurfaceSlot::DetailHeader, 'View page exposes capability-gated workflow actions for finding lifecycle management.');
    }

    public static function form(Schema $schema): Schema
    {
        return $schema;
    }

    public static function infolist(Schema $schema): Schema
    {
        return $schema
            ->schema([
                Section::make('Status and next action')
                    ->schema([
                        TextEntry::make('status')
                            ->badge()
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingStatus))
                            ->color(BadgeRenderer::color(BadgeDomain::FindingStatus))
                            ->icon(BadgeRenderer::icon(BadgeDomain::FindingStatus))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingStatus)),
                        TextEntry::make('finding_terminal_outcome')
                            ->label('Terminal outcome')
                            ->state(fn (Finding $record): ?string => static::terminalOutcomeLabel($record))
                            ->visible(fn (Finding $record): bool => static::terminalOutcomeLabel($record) !== null),
                        TextEntry::make('finding_verification_state')
                            ->label('Verification')
                            ->state(fn (Finding $record): ?string => static::verificationStateLabel($record))
                            ->visible(fn (Finding $record): bool => static::verificationStateLabel($record) !== null),
                        TextEntry::make('severity')
                            ->badge()
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingSeverity))
                            ->color(BadgeRenderer::color(BadgeDomain::FindingSeverity))
                            ->icon(BadgeRenderer::icon(BadgeDomain::FindingSeverity))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingSeverity)),
                        TextEntry::make('finding_due_attention')
                            ->label('Due state')
                            ->badge()
                            ->state(fn (Finding $record): ?string => static::dueAttentionLabelFor($record))
                            ->color(fn (Finding $record): string => static::dueAttentionColorFor($record))
                            ->visible(fn (Finding $record): bool => static::dueAttentionLabelFor($record) !== null),
                        TextEntry::make('finding_governance_validity_leading')
                            ->label('Governance')
                            ->badge()
                            ->state(fn (Finding $record): ?string => static::governanceValidityState($record))
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingRiskGovernanceValidity))
                            ->color(BadgeRenderer::color(BadgeDomain::FindingRiskGovernanceValidity))
                            ->icon(BadgeRenderer::icon(BadgeDomain::FindingRiskGovernanceValidity))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingRiskGovernanceValidity))
                            ->visible(fn (Finding $record): bool => static::governanceValidityState($record) !== null),
                        TextEntry::make('finding_responsibility_state_leading')
                            ->label('Responsibility state')
                            ->badge()
                            ->state(fn (Finding $record): string => $record->responsibilityStateLabel())
                            ->color(fn (Finding $record): string => static::responsibilityStateColor($record)),
                        TextEntry::make('finding_primary_narrative')
                            ->label('Current reading')
                            ->state(fn (Finding $record): string => static::primaryNarrative($record))
                            ->columnSpanFull(),
                        TextEntry::make('finding_governance_warning_leading')
                            ->label('Governance warning')
                            ->state(fn (Finding $record): ?string => static::governanceWarning($record))
                            ->color(fn (Finding $record): string => static::governanceWarningColor($record))
                            ->columnSpanFull()
                            ->visible(fn (Finding $record): bool => static::governanceWarning($record) !== null),
                        TextEntry::make('finding_historical_context')
                            ->label('Historical context')
                            ->state(fn (Finding $record): ?string => static::historicalContext($record))
                            ->columnSpanFull()
                            ->visible(fn (Finding $record): bool => static::historicalContext($record) !== null),
                        TextEntry::make('finding_primary_next_action')
                            ->label('Next action')
                            ->state(fn (Finding $record): ?string => static::primaryNextAction($record))
                            ->columnSpanFull()
                            ->visible(fn (Finding $record): bool => static::primaryNextAction($record) !== null),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),

                Section::make('Responsibility')
                    ->schema([
                        TextEntry::make('finding_responsibility_state')
                            ->label('Responsibility state')
                            ->badge()
                            ->state(fn (Finding $record): string => $record->responsibilityStateLabel())
                            ->color(fn (Finding $record): string => static::responsibilityStateColor($record)),
                        TextEntry::make('owner_user_id_leading')
                            ->label('Accountable owner')
                            ->state(fn (Finding $record): string => static::accountableOwnerDisplayFor($record)),
                        TextEntry::make('assignee_user_id_leading')
                            ->label('Active assignee')
                            ->state(fn (Finding $record): string => static::activeAssigneeDisplayFor($record)),
                        TextEntry::make('finding_responsibility_summary')
                            ->label('Current split')
                            ->state(fn (Finding $record): string => static::responsibilitySummary($record))
                            ->columnSpanFull(),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),

                Section::make('Artifact source')
                    ->schema([
                        TextEntry::make('artifact_source_family')
                            ->label('Source family')
                            ->badge()
                            ->state(fn (Finding $record): string => static::artifactDescriptorValue($record, 'source_family'))
                            ->formatStateUsing(fn (string $state): string => Str::headline($state)),
                        TextEntry::make('artifact_source_kind')
                            ->label('Source kind')
                            ->state(fn (Finding $record): string => static::artifactDescriptorValue($record, 'source_kind'))
                            ->formatStateUsing(fn (string $state): string => Str::headline($state)),
                        TextEntry::make('artifact_source_target')
                            ->label('Source target')
                            ->state(fn (Finding $record): string => static::artifactDescriptorValue($record, 'source_target_kind'))
                            ->formatStateUsing(fn (string $state): string => Str::headline($state)),
                        TextEntry::make('artifact_source_target_identifier')
                            ->label('Target identifier')
                            ->state(fn (Finding $record): ?string => static::artifactDescriptorNullableValue($record, 'source_target_identifier'))
                            ->copyable()
                            ->placeholder('—'),
                        TextEntry::make('artifact_detector_key')
                            ->label('Detector')
                            ->state(fn (Finding $record): ?string => static::artifactDescriptorNullableValue($record, 'detector_key'))
                            ->placeholder('—'),
                        TextEntry::make('artifact_control_key')
                            ->label('Control')
                            ->state(fn (Finding $record): ?string => static::artifactDescriptorNullableValue($record, 'control_key'))
                            ->formatStateUsing(fn (string $state): string => Str::headline($state))
                            ->placeholder('—'),
                        TextEntry::make('artifact_provider_key')
                            ->label('Provider')
                            ->state(fn (Finding $record): string => static::artifactDescriptorValue($record, 'provider_key'))
                            ->formatStateUsing(fn (string $state): string => Str::headline($state)),
                        TextEntry::make('artifact_provider_object_type')
                            ->label('Provider object type')
                            ->state(fn (Finding $record): ?string => static::artifactProviderDetailValue($record, 'provider_object_type'))
                            ->placeholder('—'),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),

                Section::make('Finding')
                    ->schema([
                        TextEntry::make('finding_type')->badge()->label('Provider finding type'),
                        TextEntry::make('drift_surface_label')
                            ->label('Drift surface')
                            ->badge()
                            ->color('gray')
                            ->state(fn (Finding $record): ?string => static::driftSurfaceLabel($record))
                            ->visible(fn (Finding $record): bool => static::driftSurfaceLabel($record) !== null),
                        TextEntry::make('evidence_fidelity')
                            ->label('Fidelity')
                            ->badge()
                            ->formatStateUsing(fn (?string $state): string => is_string($state) && $state !== '' ? $state : 'meta')
                            ->color(fn (?string $state): string => match ((string) $state) {
                                'content' => 'success',
                                'meta' => 'gray',
                                default => 'gray',
                            }),
                        TextEntry::make('status')
                            ->badge()
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingStatus))
                            ->color(BadgeRenderer::color(BadgeDomain::FindingStatus))
                            ->icon(BadgeRenderer::icon(BadgeDomain::FindingStatus))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingStatus)),
                        TextEntry::make('severity')
                            ->badge()
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingSeverity))
                            ->color(BadgeRenderer::color(BadgeDomain::FindingSeverity))
                            ->icon(BadgeRenderer::icon(BadgeDomain::FindingSeverity))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingSeverity)),
                        TextEntry::make('fingerprint')->label('Fingerprint')->copyable(),
                        TextEntry::make('scope_key')->label('Scope')->copyable(),
                        TextEntry::make('subject_display_name')
                            ->label('Subject')
                            ->placeholder('—')
                            ->state(fn (Finding $record): ?string => $record->resolvedSubjectDisplayName()),
                        TextEntry::make('subject_type')
                            ->label('Subject type')
                            ->formatStateUsing(fn (mixed $state, Finding $record): string => static::subjectTypeLabel($record, $state)),
                        TextEntry::make('subject_external_id')->label('External ID')->copyable(),
                        TextEntry::make('baseline_operation_run_id')
                            ->label('Baseline run')
                            ->formatStateUsing(static fn (?int $state): string => $state ? '#'.$state : '—')
                            ->url(fn (Finding $record): ?string => $record->baseline_operation_run_id
                                ? OperationRunLinks::tenantlessView((int) $record->baseline_operation_run_id, static::findingRunNavigationContext($record))
                                : null)
                            ->openUrlInNewTab(),
                        TextEntry::make('current_operation_run_id')
                            ->label('Current run')
                            ->formatStateUsing(static fn (?int $state): string => $state ? '#'.$state : '—')
                            ->url(fn (Finding $record): ?string => $record->current_operation_run_id
                                ? OperationRunLinks::tenantlessView((int) $record->current_operation_run_id, static::findingRunNavigationContext($record))
                                : null)
                            ->openUrlInNewTab(),
                        TextEntry::make('first_seen_at')->label('First seen')->dateTime()->placeholder('—'),
                        TextEntry::make('last_seen_at')->label('Last seen')->dateTime()->placeholder('—'),
                        TextEntry::make('times_seen')->label('Times seen')->placeholder('—'),
                        TextEntry::make('sla_days')->label('SLA days')->placeholder('—'),
                        TextEntry::make('due_at')->label('Due at')->dateTime()->placeholder('—'),
                        TextEntry::make('triaged_at')->label('Triaged at')->dateTime()->placeholder('—'),
                        TextEntry::make('in_progress_at')->label('In progress at')->dateTime()->placeholder('—'),
                        TextEntry::make('reopened_at')->label('Reopened at')->dateTime()->placeholder('—'),
                        TextEntry::make('resolved_at')->label('Resolved at')->dateTime()->placeholder('—'),
                        TextEntry::make('resolved_reason')
                            ->label('Resolved reason')
                            ->formatStateUsing(fn (?string $state): string => static::resolveReasonLabel($state) ?? '—')
                            ->placeholder('—'),
                        TextEntry::make('closed_at')->label('Closed at')->dateTime()->placeholder('—'),
                        TextEntry::make('closed_reason')
                            ->label('Closed/risk reason')
                            ->formatStateUsing(fn (?string $state): string => static::closeReasonLabel($state) ?? '—')
                            ->placeholder('—'),
                        TextEntry::make('closed_by_user_id')
                            ->label('Closed by')
                            ->formatStateUsing(fn (mixed $state, Finding $record): string => $record->closedByUser?->name ?? ($state ? 'User #'.$state : '—')),
                        TextEntry::make('created_at')->label('Created')->dateTime(),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),

                Section::make('Risk governance')
                    ->schema([
                        TextEntry::make('finding_governance_status')
                            ->label('Exception status')
                            ->badge()
                            ->state(fn (Finding $record): ?string => $record->findingException?->status)
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingExceptionStatus))
                            ->color(BadgeRenderer::color(BadgeDomain::FindingExceptionStatus))
                            ->icon(BadgeRenderer::icon(BadgeDomain::FindingExceptionStatus))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingExceptionStatus))
                            ->placeholder('—'),
                        TextEntry::make('finding_governance_validity')
                            ->label('Validity')
                            ->badge()
                            ->state(function (Finding $record): ?string {
                                if ($record->findingException instanceof FindingException) {
                                    return $record->findingException->current_validity_state;
                                }

                                return (string) $record->status === Finding::STATUS_RISK_ACCEPTED
                                    ? FindingException::VALIDITY_MISSING_SUPPORT
                                    : null;
                            })
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingRiskGovernanceValidity))
                            ->color(BadgeRenderer::color(BadgeDomain::FindingRiskGovernanceValidity))
                            ->icon(BadgeRenderer::icon(BadgeDomain::FindingRiskGovernanceValidity))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingRiskGovernanceValidity))
                            ->placeholder('—'),
                        TextEntry::make('finding_governance_warning')
                            ->label('Governance warning')
                            ->state(fn (Finding $record): ?string => static::governanceWarning($record))
                            ->color(fn (Finding $record): string => static::governanceWarningColor($record))
                            ->columnSpanFull()
                            ->visible(fn (Finding $record): bool => static::governanceWarning($record) !== null),
                        TextEntry::make('finding_governance_owner')
                            ->label('Exception owner')
                            ->state(fn (Finding $record): ?string => $record->findingException?->owner?->name)
                            ->placeholder('—'),
                        TextEntry::make('finding_governance_approver')
                            ->label('Approver')
                            ->state(fn (Finding $record): ?string => $record->findingException?->approver?->name)
                            ->placeholder('—'),
                        TextEntry::make('finding_governance_review_due')
                            ->label('Review due')
                            ->state(fn (Finding $record): mixed => $record->findingException?->review_due_at)
                            ->dateTime()
                            ->placeholder('—'),
                        TextEntry::make('finding_governance_expires')
                            ->label('Expires')
                            ->state(fn (Finding $record): mixed => $record->findingException?->expires_at)
                            ->dateTime()
                            ->placeholder('—'),
                    ])
                    ->columns(2)
                    ->visible(fn (Finding $record): bool => $record->findingException instanceof FindingException || (string) $record->status === Finding::STATUS_RISK_ACCEPTED),

                Section::make('Evidence')
                    ->schema([
                        TextEntry::make('redaction_integrity_note')
                            ->label('Integrity note')
                            ->state(fn (Finding $record): ?string => static::redactionIntegrityNoteForRecord($record))
                            ->columnSpanFull()
                            ->visible(fn (Finding $record): bool => static::redactionIntegrityNoteForRecord($record) !== null),
                        TextEntry::make('baseline_evidence_fidelity')
                            ->label('Baseline fidelity')
                            ->badge()
                            ->state(fn (Finding $record): ?string => Arr::get($record->evidence_jsonb ?? [], 'baseline.provenance.fidelity'))
                            ->color(fn (?string $state): string => match ((string) $state) {
                                'content' => 'success',
                                'meta' => 'gray',
                                default => 'gray',
                            })
                            ->placeholder('—'),
                        TextEntry::make('baseline_evidence_source')
                            ->label('Baseline source')
                            ->state(fn (Finding $record): ?string => Arr::get($record->evidence_jsonb ?? [], 'baseline.provenance.source'))
                            ->placeholder('—'),
                        TextEntry::make('baseline_evidence_observed_at')
                            ->label('Baseline observed at')
                            ->state(fn (Finding $record): ?string => Arr::get($record->evidence_jsonb ?? [], 'baseline.provenance.observed_at'))
                            ->placeholder('—')
                            ->copyable(),

                        TextEntry::make('current_evidence_fidelity')
                            ->label('Current fidelity')
                            ->badge()
                            ->state(fn (Finding $record): ?string => Arr::get($record->evidence_jsonb ?? [], 'current.provenance.fidelity'))
                            ->color(fn (?string $state): string => match ((string) $state) {
                                'content' => 'success',
                                'meta' => 'gray',
                                default => 'gray',
                            })
                            ->placeholder('—'),
                        TextEntry::make('current_evidence_source')
                            ->label('Current source')
                            ->state(fn (Finding $record): ?string => Arr::get($record->evidence_jsonb ?? [], 'current.provenance.source'))
                            ->placeholder('—'),
                        TextEntry::make('current_evidence_observed_at')
                            ->label('Current observed at')
                            ->state(fn (Finding $record): ?string => Arr::get($record->evidence_jsonb ?? [], 'current.provenance.observed_at'))
                            ->placeholder('—')
                            ->copyable(),
                    ])
                    ->columns(3)
                    ->visible(function (Finding $record): bool {
                        $evidence = is_array($record->evidence_jsonb) ? $record->evidence_jsonb : [];

                        return Arr::has($evidence, 'baseline.provenance') || Arr::has($evidence, 'current.provenance');
                    })
                    ->columnSpanFull(),

                Section::make('Related context')
                    ->schema([
                        ViewEntry::make('related_context')
                            ->label('')
                            ->view('filament.infolists.entries.related-context')
                            ->state(fn (Finding $record): array => static::relatedContextEntries($record))
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull(),

                Section::make('Diff')
                    ->visible(fn (Finding $record): bool => $record->finding_type === Finding::FINDING_TYPE_DRIFT)
                    ->schema([
                        ViewEntry::make('rbac_role_definition_diff')
                            ->label('')
                            ->view('filament.infolists.entries.rbac-role-definition-diff')
                            ->state(fn (Finding $record): array => Arr::get($record->evidence_jsonb ?? [], 'rbac_role_definition', []))
                            ->visible(fn (Finding $record): bool => static::driftSummaryKind($record) === 'rbac_role_definition' && is_array(Arr::get($record->evidence_jsonb ?? [], 'rbac_role_definition')))
                            ->columnSpanFull(),
                        ViewEntry::make('settings_diff')
                            ->label('')
                            ->view('filament.infolists.entries.normalized-diff')
                            ->state(function (Finding $record): array {
                                $tenant = static::resolveTenantContextForCurrentPanel();
                                if (! $tenant) {
                                    return NormalizedDiffSurface::build(static::unavailableDiffState('No tenant context'), 'finding');
                                }

                                [$baselineVersion, $currentVersion] = static::resolveDriftDiffVersions($record, $tenant);

                                if (! static::hasRequiredDiffVersions($record, $baselineVersion, $currentVersion)) {
                                    return NormalizedDiffSurface::build(static::unavailableDiffState('Diff unavailable — referenced policy versions are missing.'), 'finding');
                                }

                                $diff = app(DriftFindingDiffBuilder::class)->buildSettingsDiff($baselineVersion, $currentVersion);

                                $addedCount = (int) Arr::get($diff, 'summary.added', 0);
                                $removedCount = (int) Arr::get($diff, 'summary.removed', 0);
                                $changedCount = (int) Arr::get($diff, 'summary.changed', 0);

                                if (($addedCount + $removedCount + $changedCount) === 0) {
                                    Arr::set(
                                        $diff,
                                        'summary.message',
                                        'No normalized changes were found. This drift finding may be based on fields that are intentionally excluded from normalization.'
                                    );
                                }

                                return NormalizedDiffSurface::build($diff, 'finding');
                            })
                            ->visible(fn (Finding $record): bool => Arr::get($record->evidence_jsonb ?? [], 'summary.kind') === 'policy_snapshot')
                            ->columnSpanFull(),

                        ViewEntry::make('scope_tags_diff')
                            ->label('')
                            ->view('filament.infolists.entries.scope-tags-diff')
                            ->state(function (Finding $record): array {
                                $tenant = static::resolveTenantContextForCurrentPanel();
                                if (! $tenant) {
                                    return static::unavailableDiffState('No tenant context');
                                }

                                [$baselineVersion, $currentVersion] = static::resolveDriftDiffVersions($record, $tenant);

                                if (! static::hasRequiredDiffVersions($record, $baselineVersion, $currentVersion)) {
                                    return static::unavailableDiffState('Diff unavailable — referenced policy versions are missing.');
                                }

                                return app(DriftFindingDiffBuilder::class)->buildScopeTagsDiff($baselineVersion, $currentVersion);
                            })
                            ->visible(fn (Finding $record): bool => static::canRenderDriftDiff($record) && Arr::get($record->evidence_jsonb ?? [], 'summary.kind') === 'policy_scope_tags')
                            ->columnSpanFull(),

                        ViewEntry::make('assignments_diff')
                            ->label('')
                            ->view('filament.infolists.entries.assignments-diff')
                            ->state(function (Finding $record): array {
                                $tenant = static::resolveTenantContextForCurrentPanel();
                                if (! $tenant) {
                                    return static::unavailableDiffState('No tenant context');
                                }

                                [$baselineVersion, $currentVersion] = static::resolveDriftDiffVersions($record, $tenant);

                                if (! static::hasRequiredDiffVersions($record, $baselineVersion, $currentVersion)) {
                                    return static::unavailableDiffState('Diff unavailable — referenced policy versions are missing.');
                                }

                                return app(DriftFindingDiffBuilder::class)->buildAssignmentsDiff($tenant, $baselineVersion, $currentVersion);
                            })
                            ->visible(fn (Finding $record): bool => static::canRenderDriftDiff($record) && Arr::get($record->evidence_jsonb ?? [], 'summary.kind') === 'policy_assignments')
                            ->columnSpanFull(),
                    ])
                    ->collapsed()
                    ->columnSpanFull(),

                Section::make('Evidence (Sanitized)')
                    ->schema([
                        ViewEntry::make('evidence_jsonb')
                            ->label('')
                            ->view('filament.infolists.entries.snapshot-json')
                            ->state(fn (Finding $record) => $record->evidence_jsonb ?? [])
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull(),
            ]);
    }

    private static function driftChangeType(Finding $record): string
    {
        $changeType = Arr::get($record->evidence_jsonb ?? [], 'change_type');

        return is_string($changeType) ? trim($changeType) : '';
    }

    private static function driftSummaryKind(Finding $record): string
    {
        $summaryKind = Arr::get($record->evidence_jsonb ?? [], 'summary.kind');

        return is_string($summaryKind) ? trim($summaryKind) : '';
    }

    private static function isRbacRoleDefinitionDrift(Finding $record): bool
    {
        return static::driftSummaryKind($record) === 'rbac_role_definition'
            || (string) Arr::get($record->evidence_jsonb ?? [], 'policy_type') === 'intuneRoleDefinition';
    }

    private static function driftSurfaceLabel(Finding $record): ?string
    {
        if (static::isRbacRoleDefinitionDrift($record)) {
            return __('findings.drift.rbac_role_definition');
        }

        return null;
    }

    private static function subjectTypeLabel(Finding $record, mixed $state): string
    {
        $policyType = Arr::get($record->evidence_jsonb ?? [], 'policy_type');

        if (is_string($policyType) && $policyType !== '') {
            $translated = __('findings.subject_types.'.$policyType);

            if ($translated !== 'findings.subject_types.'.$policyType) {
                return $translated;
            }
        }

        $value = is_string($state) ? trim($state) : '';

        return $value !== '' ? $value : '—';
    }

    private static function driftContextDescription(Finding $record): ?string
    {
        if (! static::isRbacRoleDefinitionDrift($record)) {
            return null;
        }

        $parts = [__('findings.drift.rbac_role_definition')];
        $diffKind = Arr::get($record->evidence_jsonb ?? [], 'rbac_role_definition.diff_kind');

        if (is_string($diffKind) && $diffKind !== '') {
            $parts[] = __('findings.rbac.'.$diffKind);
        }

        return implode(' | ', array_filter($parts, fn (?string $part): bool => is_string($part) && $part !== ''));
    }

    public static function findingSubheading(Finding $record): ?string
    {
        $parts = [];

        if (static::isRbacRoleDefinitionDrift($record)) {
            $parts[] = __('findings.rbac.detail_heading');
            $parts[] = __('findings.rbac.detail_subheading');
        }

        $integrity = static::redactionIntegrityNoteForRecord($record);

        if (is_string($integrity) && trim($integrity) !== '') {
            $parts[] = $integrity;
        }

        return $parts !== [] ? implode(' ', $parts) : null;
    }

    private static function hasBaselinePolicyVersionReference(Finding $record): bool
    {
        return is_numeric(Arr::get($record->evidence_jsonb ?? [], 'baseline.policy_version_id'));
    }

    private static function hasCurrentPolicyVersionReference(Finding $record): bool
    {
        return is_numeric(Arr::get($record->evidence_jsonb ?? [], 'current.policy_version_id'));
    }

    private static function canRenderDriftDiff(Finding $record): bool
    {
        if (static::driftSummaryKind($record) === 'rbac_role_definition') {
            return is_array(Arr::get($record->evidence_jsonb ?? [], 'rbac_role_definition'));
        }

        return match (static::driftChangeType($record)) {
            'missing_policy' => static::hasBaselinePolicyVersionReference($record),
            'unexpected_policy' => static::hasCurrentPolicyVersionReference($record),
            default => static::hasBaselinePolicyVersionReference($record) && static::hasCurrentPolicyVersionReference($record),
        };
    }

    public static function redactionIntegrityNoteForRecord(Finding $record): ?string
    {
        $evidence = is_array($record->evidence_jsonb) ? $record->evidence_jsonb : [];

        return RedactionIntegrity::noteForFindingEvidence($evidence);
    }

    private static function driftDiffUnavailableMessage(Finding $record): string
    {
        if (static::driftSummaryKind($record) === 'rbac_role_definition') {
            return 'RBAC evidence unavailable — normalized role definition evidence is missing.';
        }

        return match (static::driftChangeType($record)) {
            'missing_policy' => 'Diff unavailable — missing baseline policy version reference.',
            'unexpected_policy' => 'Diff unavailable — missing current policy version reference.',
            default => 'Diff unavailable — missing baseline/current policy version references.',
        };
    }

    /**
     * @return array{0: ?PolicyVersion, 1: ?PolicyVersion}
     */
    private static function resolveDriftDiffVersions(Finding $record, ManagedEnvironment $tenant): array
    {
        $baselineId = Arr::get($record->evidence_jsonb ?? [], 'baseline.policy_version_id');
        $currentId = Arr::get($record->evidence_jsonb ?? [], 'current.policy_version_id');

        $baselineVersion = is_numeric($baselineId)
            ? PolicyVersion::query()->where('managed_environment_id', $tenant->getKey())->find((int) $baselineId)
            : null;

        $currentVersion = is_numeric($currentId)
            ? PolicyVersion::query()->where('managed_environment_id', $tenant->getKey())->find((int) $currentId)
            : null;

        return [$baselineVersion, $currentVersion];
    }

    private static function hasRequiredDiffVersions(
        Finding $record,
        ?PolicyVersion $baselineVersion,
        ?PolicyVersion $currentVersion,
    ): bool {
        return match (static::driftChangeType($record)) {
            'missing_policy' => $baselineVersion instanceof PolicyVersion,
            'unexpected_policy' => $currentVersion instanceof PolicyVersion,
            default => $baselineVersion instanceof PolicyVersion && $currentVersion instanceof PolicyVersion,
        };
    }

    /**
     * @return array{summary: array{message: string}, added: array<int, mixed>, removed: array<int, mixed>, changed: array<int, mixed>}
     */
    private static function unavailableDiffState(string $message): array
    {
        return [
            'summary' => ['message' => $message],
            'added' => [],
            'removed' => [],
            'changed' => [],
        ];
    }

    public static function table(Table $table): Table
    {
        return $table
            ->defaultSort('created_at', 'desc')
            ->paginated(TablePaginationProfiles::resource())
            ->persistFiltersInSession()
            ->persistSearchInSession()
            ->persistSortInSession()
            ->columns([
                Tables\Columns\TextColumn::make('finding_type')
                    ->badge()
                    ->label('Type')
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingType))
                    ->color(BadgeRenderer::color(BadgeDomain::FindingType))
                    ->icon(BadgeRenderer::icon(BadgeDomain::FindingType)),
                Tables\Columns\TextColumn::make('subject_display_name')
                    ->label('Subject')
                    ->placeholder('—')
                    ->searchable()
                    ->limit(40)
                    ->wrap()
                    ->state(fn (Finding $record): ?string => $record->resolvedSubjectDisplayName())
                    ->tooltip(fn (Finding $record): ?string => $record->resolvedSubjectDisplayName())
                    ->description(fn (Finding $record): ?string => static::driftContextDescription($record)),
                Tables\Columns\TextColumn::make('severity')
                    ->badge()
                    ->sortable()
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingSeverity))
                    ->color(BadgeRenderer::color(BadgeDomain::FindingSeverity))
                    ->icon(BadgeRenderer::icon(BadgeDomain::FindingSeverity))
                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingSeverity)),
                Tables\Columns\TextColumn::make('status')
                    ->badge()
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingStatus))
                    ->color(BadgeRenderer::color(BadgeDomain::FindingStatus))
                    ->icon(BadgeRenderer::icon(BadgeDomain::FindingStatus))
                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingStatus))
                    ->description(fn (Finding $record): string => static::statusDescription($record)),
                Tables\Columns\TextColumn::make('governance_validity')
                    ->label('Governance')
                    ->badge()
                    ->state(fn (Finding $record): ?string => static::governanceValidityState($record))
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingRiskGovernanceValidity))
                    ->color(BadgeRenderer::color(BadgeDomain::FindingRiskGovernanceValidity))
                    ->icon(BadgeRenderer::icon(BadgeDomain::FindingRiskGovernanceValidity))
                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingRiskGovernanceValidity))
                    ->placeholder('—')
                    ->description(fn (Finding $record): ?string => static::governanceListDescription($record)),
                Tables\Columns\TextColumn::make('responsibility_state')
                    ->label('Responsibility')
                    ->badge()
                    ->state(fn (Finding $record): string => $record->responsibilityStateLabel())
                    ->color(fn (Finding $record): string => static::responsibilityStateColor($record))
                    ->description(fn (Finding $record): string => static::responsibilitySummary($record)),
                Tables\Columns\TextColumn::make('evidence_fidelity')
                    ->label('Fidelity')
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => is_string($state) && $state !== '' ? $state : 'meta')
                    ->color(fn (?string $state): string => match ((string) $state) {
                        'content' => 'success',
                        'meta' => 'gray',
                        default => 'gray',
                    })
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('subject_type')
                    ->label('Subject type')
                    ->searchable()
                    ->formatStateUsing(fn (mixed $state, Finding $record): string => static::subjectTypeLabel($record, $state))
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('due_at')
                    ->label('Due')
                    ->dateTime()
                    ->sortable()
                    ->placeholder('—')
                    ->description(fn (Finding $record): ?string => FindingExceptionResource::relativeTimeDescription($record->due_at) ?? static::dueAttentionLabelFor($record))
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('ownerUser.name')
                    ->label('Accountable owner')
                    ->placeholder('—'),
                Tables\Columns\TextColumn::make('assigneeUser.name')
                    ->label('Active assignee')
                    ->placeholder('—'),
                Tables\Columns\TextColumn::make('subject_external_id')->label('External ID')->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('scope_key')->label('Scope')->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('created_at')
                    ->since()
                    ->label('Created')
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->filters([
                Tables\Filters\Filter::make('open')
                    ->label('Active workflow')
                    ->query(fn (Builder $query): Builder => $query->whereIn('status', Finding::openStatusesForQuery())),
                Tables\Filters\Filter::make('overdue')
                    ->label('Overdue')
                    ->query(fn (Builder $query): Builder => $query
                        ->whereIn('status', Finding::openStatusesForQuery())
                        ->whereNotNull('due_at')
                        ->where('due_at', '<', now())),
                Tables\Filters\Filter::make('high_severity')
                    ->label('High severity')
                    ->query(fn (Builder $query): Builder => $query->whereIn('severity', [
                        Finding::SEVERITY_HIGH,
                        Finding::SEVERITY_CRITICAL,
                    ])),
                Tables\Filters\Filter::make('my_assigned')
                    ->label('My assigned work')
                    ->query(function (Builder $query): Builder {
                        $userId = auth()->id();

                        if (! is_numeric($userId)) {
                            return $query->whereRaw('1 = 0');
                        }

                        return $query->where('assignee_user_id', (int) $userId);
                    }),
                Tables\Filters\Filter::make('my_accountability')
                    ->label('My accountability')
                    ->query(function (Builder $query): Builder {
                        $userId = auth()->id();

                        if (! is_numeric($userId)) {
                            return $query->whereRaw('1 = 0');
                        }

                        return $query->where('owner_user_id', (int) $userId);
                    }),
                Tables\Filters\SelectFilter::make('status')
                    ->options(FilterOptionCatalog::findingStatuses())
                    ->label('Status'),
                Tables\Filters\SelectFilter::make('terminal_outcome')
                    ->label('Terminal outcome')
                    ->options(FilterOptionCatalog::findingTerminalOutcomes())
                    ->query(fn (Builder $query, array $data): Builder => static::applyTerminalOutcomeFilter($query, $data['value'] ?? null)),
                Tables\Filters\SelectFilter::make('verification_state')
                    ->label('Verification')
                    ->options(FilterOptionCatalog::findingVerificationStates())
                    ->query(fn (Builder $query, array $data): Builder => static::applyVerificationStateFilter($query, $data['value'] ?? null)),
                Tables\Filters\SelectFilter::make('workflow_family')
                    ->label('Workflow family')
                    ->options(FilterOptionCatalog::findingWorkflowFamilies())
                    ->query(function (Builder $query, array $data): Builder {
                        $value = $data['value'] ?? null;

                        if (! is_string($value) || $value === '') {
                            return $query;
                        }

                        return match ($value) {
                            'active' => $query->whereIn('status', Finding::openStatusesForQuery()),
                            'accepted_risk' => $query->where('status', Finding::STATUS_RISK_ACCEPTED),
                            'historical' => $query->whereIn('status', [Finding::STATUS_RESOLVED, Finding::STATUS_CLOSED]),
                            default => $query,
                        };
                    }),
                Tables\Filters\SelectFilter::make('governance_validity')
                    ->label('Governance')
                    ->options(FilterOptionCatalog::findingExceptionValidityStates())
                    ->query(function (Builder $query, array $data): Builder {
                        $value = $data['value'] ?? null;

                        if (! is_string($value) || $value === '') {
                            return $query;
                        }

                        if ($value === FindingException::VALIDITY_MISSING_SUPPORT) {
                            return $query
                                ->where('status', Finding::STATUS_RISK_ACCEPTED)
                                ->whereDoesntHave('findingException');
                        }

                        return $query
                            ->where('status', Finding::STATUS_RISK_ACCEPTED)
                            ->whereHas('findingException', function (Builder $exceptionQuery) use ($value): void {
                                $exceptionQuery->where('current_validity_state', $value);
                            });
                    }),
                Tables\Filters\SelectFilter::make('finding_type')
                    ->options([
                        Finding::FINDING_TYPE_DRIFT => 'Drift',
                        Finding::FINDING_TYPE_PERMISSION_POSTURE => 'Permission posture',
                        Finding::FINDING_TYPE_ENTRA_ADMIN_ROLES => 'Entra admin roles',
                    ])
                    ->label('Type'),
                Tables\Filters\SelectFilter::make('evidence_fidelity')
                    ->label('Fidelity')
                    ->options([
                        'content' => 'Content',
                        'meta' => 'Meta',
                    ]),
                Tables\Filters\Filter::make('scope_key')
                    ->form([
                        TextInput::make('scope_key')
                            ->label('Scope key')
                            ->placeholder('Inventory selection hash')
                            ->maxLength(255),
                    ])
                    ->query(function (Builder $query, array $data): Builder {
                        $scopeKey = $data['scope_key'] ?? null;

                        if (! is_string($scopeKey) || $scopeKey === '') {
                            return $query;
                        }

                        return $query->where('scope_key', $scopeKey);
                    }),
                Tables\Filters\Filter::make('run_ids')
                    ->label('Operation IDs')
                    ->form([
                        TextInput::make('baseline_operation_run_id')
                            ->label('Baseline operation ID')
                            ->numeric(),
                        TextInput::make('current_operation_run_id')
                            ->label('Current operation ID')
                            ->numeric(),
                    ])
                    ->query(function (Builder $query, array $data): Builder {
                        $baselineRunId = $data['baseline_operation_run_id'] ?? null;
                        if (is_numeric($baselineRunId)) {
                            $query->where('baseline_operation_run_id', (int) $baselineRunId);
                        }

                        $currentRunId = $data['current_operation_run_id'] ?? null;
                        if (is_numeric($currentRunId)) {
                            $query->where('current_operation_run_id', (int) $currentRunId);
                        }

                        return $query;
                    }),
                FilterPresets::dateRange('created_at', 'Created', 'created_at'),
            ])
            ->recordUrl(static fn (Finding $record): string => static::getUrl('view', ['record' => $record]))
            ->actions([
                static::primaryRelatedAction(),
                Actions\ActionGroup::make([
                    ...static::workflowActions(),
                ])
                    ->label('More')
                    ->icon('heroicon-o-ellipsis-vertical')
                    ->color('gray'),
            ])
            ->bulkActions([
                BulkActionGroup::make([
                    UiEnforcement::forBulkAction(
                        BulkAction::make('triage_selected')
                            ->label('Triage selected')
                            ->icon('heroicon-o-check')
                            ->color('gray')
                            ->requiresConfirmation()
                            ->action(function (Collection $records, FindingWorkflowService $workflow): void {
                                $tenant = static::resolveTenantContextForCurrentPanel();
                                $user = auth()->user();

                                if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
                                    return;
                                }

                                $triagedCount = 0;
                                $skippedCount = 0;
                                $failedCount = 0;

                                foreach ($records as $record) {
                                    if (! $record instanceof Finding) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    if ((int) $record->managed_environment_id !== (int) $tenant->getKey()) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    if (! in_array((string) $record->status, [
                                        Finding::STATUS_NEW,
                                        Finding::STATUS_REOPENED,
                                    ], true)) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    try {
                                        $record = static::resolveProtectedFindingRecordOrFail($record);
                                        $workflow->triage($record, $tenant, $user);
                                        $triagedCount++;
                                    } catch (Throwable) {
                                        $failedCount++;
                                    }
                                }

                                $body = "Triaged {$triagedCount} finding".($triagedCount === 1 ? '' : 's').'.';
                                if ($skippedCount > 0) {
                                    $body .= " Skipped {$skippedCount}.";
                                }
                                if ($failedCount > 0) {
                                    $body .= " Failed {$failedCount}.";
                                }

                                Notification::make()
                                    ->title('Bulk triage completed')
                                    ->body($body)
                                    ->status($failedCount > 0 ? 'warning' : 'success')
                                    ->send();
                            })
                            ->deselectRecordsAfterCompletion(),
                    )
                        ->requireCapability(Capabilities::TENANT_FINDINGS_TRIAGE)
                        ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
                        ->apply(),

                    UiEnforcement::forBulkAction(
                        BulkAction::make('assign_selected')
                            ->label('Assign selected')
                            ->icon('heroicon-o-user-plus')
                            ->color('gray')
                            ->requiresConfirmation()
                            ->form([
                                Select::make('assignee_user_id')
                                    ->label('Active assignee')
                                    ->placeholder('Unassigned')
                                    ->helperText('Assign the person currently expected to perform or coordinate the remediation work.')
                                    ->options(fn (): array => static::tenantMemberOptions())
                                    ->searchable(),
                                Select::make('owner_user_id')
                                    ->label('Accountable owner')
                                    ->placeholder('Unassigned')
                                    ->helperText('Assign the person accountable for ensuring the finding reaches a governed outcome.')
                                    ->options(fn (): array => static::tenantMemberOptions())
                                    ->searchable(),
                            ])
                            ->action(function (Collection $records, array $data, FindingWorkflowService $workflow): void {
                                $tenant = static::resolveTenantContextForCurrentPanel();
                                $user = auth()->user();

                                if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
                                    return;
                                }

                                $assigneeUserId = is_numeric($data['assignee_user_id'] ?? null) ? (int) $data['assignee_user_id'] : null;
                                $ownerUserId = is_numeric($data['owner_user_id'] ?? null) ? (int) $data['owner_user_id'] : null;

                                $assignedCount = 0;
                                $skippedCount = 0;
                                $failedCount = 0;
                                $classificationCounts = [];

                                foreach ($records as $record) {
                                    if (! $record instanceof Finding) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    if ((int) $record->managed_environment_id !== (int) $tenant->getKey()) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    if (! $record->hasOpenStatus()) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    try {
                                        $record = static::resolveProtectedFindingRecordOrFail($record);
                                        $classification = $workflow->responsibilityChangeClassification(
                                            beforeOwnerUserId: is_numeric($record->owner_user_id) ? (int) $record->owner_user_id : null,
                                            beforeAssigneeUserId: is_numeric($record->assignee_user_id) ? (int) $record->assignee_user_id : null,
                                            afterOwnerUserId: $ownerUserId,
                                            afterAssigneeUserId: $assigneeUserId,
                                        );
                                        $workflow->assign($record, $tenant, $user, $assigneeUserId, $ownerUserId);
                                        $assignedCount++;
                                        $classificationCounts[$classification ?? 'unchanged'] = ($classificationCounts[$classification ?? 'unchanged'] ?? 0) + 1;
                                    } catch (Throwable) {
                                        $failedCount++;
                                    }
                                }

                                $body = "Updated {$assignedCount} finding".($assignedCount === 1 ? '' : 's').'.';
                                $classificationSummary = static::bulkResponsibilityClassificationSummary($classificationCounts);
                                if ($classificationSummary !== null) {
                                    $body .= ' '.$classificationSummary;
                                }
                                if ($skippedCount > 0) {
                                    $body .= " Skipped {$skippedCount}.";
                                }
                                if ($failedCount > 0) {
                                    $body .= " Failed {$failedCount}.";
                                }

                                Notification::make()
                                    ->title('Bulk assign completed')
                                    ->body($body)
                                    ->status($failedCount > 0 ? 'warning' : 'success')
                                    ->send();
                            })
                            ->deselectRecordsAfterCompletion(),
                    )
                        ->requireCapability(Capabilities::TENANT_FINDINGS_ASSIGN)
                        ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
                        ->apply(),

                    UiEnforcement::forBulkAction(
                        BulkAction::make('resolve_selected')
                            ->label(GovernanceActionCatalog::rule('resolve_finding')->canonicalLabel.' selected')
                            ->icon('heroicon-o-check-badge')
                            ->color('success')
                            ->requiresConfirmation()
                            ->modalHeading(GovernanceActionCatalog::rule('resolve_finding')->modalHeading)
                            ->modalDescription(GovernanceActionCatalog::rule('resolve_finding')->modalDescription)
                            ->form([
                                Select::make('resolved_reason')
                                    ->label('Resolution outcome')
                                    ->options(static::resolveReasonOptions())
                                    ->helperText('Use the canonical manual remediation outcome. Trusted verification is recorded later by system evidence.')
                                    ->native(false)
                                    ->required()
                                    ->selectablePlaceholder(false),
                            ])
                            ->action(function (Collection $records, array $data, FindingWorkflowService $workflow): void {
                                $tenant = static::resolveTenantContextForCurrentPanel();
                                $user = auth()->user();

                                if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
                                    return;
                                }

                                $reason = (string) ($data['resolved_reason'] ?? '');

                                $resolvedCount = 0;
                                $skippedCount = 0;
                                $failedCount = 0;

                                foreach ($records as $record) {
                                    if (! $record instanceof Finding) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    if ((int) $record->managed_environment_id !== (int) $tenant->getKey()) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    if (! $record->hasOpenStatus()) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    try {
                                        $record = static::resolveProtectedFindingRecordOrFail($record);
                                        $workflow->resolve($record, $tenant, $user, $reason);
                                        $resolvedCount++;
                                    } catch (Throwable) {
                                        $failedCount++;
                                    }
                                }

                                $body = "Resolved {$resolvedCount} finding".($resolvedCount === 1 ? '' : 's').' pending verification.';
                                if ($skippedCount > 0) {
                                    $body .= " Skipped {$skippedCount}.";
                                }
                                if ($failedCount > 0) {
                                    $body .= " Failed {$failedCount}.";
                                }

                                Notification::make()
                                    ->title('Bulk resolve completed')
                                    ->body($body)
                                    ->status($failedCount > 0 ? 'warning' : 'success')
                                    ->send();
                            })
                            ->deselectRecordsAfterCompletion(),
                    )
                        ->requireCapability(Capabilities::TENANT_FINDINGS_RESOLVE)
                        ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
                        ->apply(),

                    UiEnforcement::forBulkAction(
                        BulkAction::make('close_selected')
                            ->label(GovernanceActionCatalog::rule('close_finding')->canonicalLabel.' selected')
                            ->icon('heroicon-o-x-circle')
                            ->color('warning')
                            ->requiresConfirmation()
                            ->modalHeading(GovernanceActionCatalog::rule('close_finding')->modalHeading)
                            ->modalDescription(GovernanceActionCatalog::rule('close_finding')->modalDescription)
                            ->form([
                                Select::make('closed_reason')
                                    ->label('Close reason')
                                    ->options(static::closeReasonOptions())
                                    ->helperText('Use the canonical administrative closure outcome for this finding.')
                                    ->native(false)
                                    ->required()
                                    ->selectablePlaceholder(false),
                            ])
                            ->action(function (Collection $records, array $data, FindingWorkflowService $workflow): void {
                                $tenant = static::resolveTenantContextForCurrentPanel();
                                $user = auth()->user();

                                if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
                                    return;
                                }

                                $reason = (string) ($data['closed_reason'] ?? '');

                                $closedCount = 0;
                                $skippedCount = 0;
                                $failedCount = 0;

                                foreach ($records as $record) {
                                    if (! $record instanceof Finding) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    if ((int) $record->managed_environment_id !== (int) $tenant->getKey()) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    if (! $record->hasOpenStatus()) {
                                        $skippedCount++;

                                        continue;
                                    }

                                    try {
                                        $record = static::resolveProtectedFindingRecordOrFail($record);
                                        $workflow->close($record, $tenant, $user, $reason);
                                        $closedCount++;
                                    } catch (Throwable) {
                                        $failedCount++;
                                    }
                                }

                                $body = "Closed {$closedCount} finding".($closedCount === 1 ? '' : 's').'.';
                                if ($skippedCount > 0) {
                                    $body .= " Skipped {$skippedCount}.";
                                }
                                if ($failedCount > 0) {
                                    $body .= " Failed {$failedCount}.";
                                }

                                Notification::make()
                                    ->title('Bulk close completed')
                                    ->body($body)
                                    ->status($failedCount > 0 ? 'warning' : 'success')
                                    ->send();
                            })
                            ->deselectRecordsAfterCompletion(),
                    )
                        ->requireCapability(Capabilities::TENANT_FINDINGS_CLOSE)
                        ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
                        ->apply(),

                ])->label('More'),
            ])
            ->emptyStateHeading('No findings match this view')
            ->emptyStateDescription('Adjust the current filters or wait for the next detection run to surface findings and governance follow-up.')
            ->emptyStateIcon('heroicon-o-exclamation-triangle');
    }

    public static function getEloquentQuery(): Builder
    {
        return static::getTenantOwnedEloquentQuery()
            ->with(['assigneeUser', 'ownerUser', 'closedByUser', 'findingException.owner', 'findingException.approver', 'findingException.currentDecision'])
            ->withSubjectDisplayName();
    }

    public static function resolveScopedRecordOrFail(int|string $key): Model
    {
        return static::resolveTenantOwnedRecordOrFail(
            $key,
            parent::getEloquentQuery()
                ->with(['assigneeUser', 'ownerUser', 'closedByUser', 'findingException.owner', 'findingException.approver', 'findingException.currentDecision'])
                ->withSubjectDisplayName(),
        );
    }

    /**
     * @return list<array{
     *     key: string,
     *     label: string,
     *     value: string,
     *     secondaryValue: ?string,
     *     targetUrl: ?string,
     *     targetKind: string,
     *     availability: string,
     *     unavailableReason: ?string,
     *     contextBadge: ?string,
     *     priority: int,
     *     actionLabel: string
     * }>
     */
    public static function relatedContextEntries(Finding $record): array
    {
        return app(RelatedNavigationResolver::class)
            ->detailEntries(CrossResourceNavigationMatrix::SOURCE_FINDING, $record);
    }

    private static function primaryRelatedAction(): Actions\Action
    {
        return Actions\Action::make('primary_drill_down')
            ->label(fn (Finding $record): string => static::primaryRelatedEntry($record)?->actionLabel ?? 'Open related record')
            ->url(fn (Finding $record): ?string => static::primaryRelatedEntry($record)?->targetUrl)
            ->hidden(fn (Finding $record): bool => ! (static::primaryRelatedEntry($record)?->isAvailable() ?? false))
            ->color('gray');
    }

    private static function primaryRelatedEntry(Finding $record, bool $fresh = false): ?RelatedContextEntry
    {
        $resolver = app(RelatedNavigationResolver::class);

        return $fresh
            ? $resolver->primaryListActionFresh(CrossResourceNavigationMatrix::SOURCE_FINDING, $record)
            : $resolver->primaryListAction(CrossResourceNavigationMatrix::SOURCE_FINDING, $record);
    }

    private static function findingRunNavigationContext(Finding $record): CanonicalNavigationContext
    {
        $incomingContext = CanonicalNavigationContext::fromRequest(request());

        if (
            $incomingContext instanceof CanonicalNavigationContext
            && str_starts_with($incomingContext->sourceSurface, 'baseline_compare_matrix')
            && $incomingContext->backLinkUrl !== null
        ) {
            return $incomingContext;
        }

        $tenant = $record->tenant;

        return new CanonicalNavigationContext(
            sourceSurface: 'finding.detail_section',
            canonicalRouteName: 'admin.operations.view',
            tenantId: $tenant?->getKey(),
            backLinkLabel: 'Back to finding',
            backLinkUrl: static::getUrl('view', ['record' => $record], tenant: $tenant),
            filterPayload: $tenant instanceof ManagedEnvironment ? [
                'tableFilters' => [
                    'managed_environment_id' => ['value' => (string) $tenant->getKey()],
                ],
            ] : [],
        );
    }

    private static function artifactDescriptorValue(Finding $record, string $key): string
    {
        return (string) (static::artifactDescriptorNullableValue($record, $key) ?? 'unknown');
    }

    private static function artifactDescriptorNullableValue(Finding $record, string $key): ?string
    {
        $descriptor = $record->artifactSourceDescriptor()->toArray();
        $value = $descriptor[$key] ?? null;

        return is_string($value) && trim($value) !== '' ? trim($value) : null;
    }

    private static function artifactProviderDetailValue(Finding $record, string $key): ?string
    {
        $detail = $record->artifactProviderDetail()->toArray();
        $value = $detail[$key] ?? null;

        return is_string($value) && trim($value) !== '' ? trim($value) : null;
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListFindings::route('/'),
            'view' => Pages\ViewFinding::route('/{record}'),
        ];
    }

    /**
     * @return array<int, Actions\Action>
     */
    public static function workflowActions(): array
    {
        return [
            static::triageAction(),
            static::startProgressAction(),
            static::assignAction(),
            static::resolveAction(),
            static::closeAction(),
            static::requestExceptionAction(),
            static::renewExceptionAction(),
            static::revokeExceptionAction(),
            static::reopenAction(),
        ];
    }

    public static function triageAction(): Actions\Action
    {
        return UiEnforcement::forAction(
            Actions\Action::make('triage')
                ->label('Triage')
                ->icon('heroicon-o-check')
                ->color('gray')
                ->visible(fn (Finding $record): bool => in_array((string) $record->status, [
                    Finding::STATUS_NEW,
                    Finding::STATUS_REOPENED,
                ], true))
                ->action(function (Finding $record, FindingWorkflowService $workflow): void {
                    static::runWorkflowMutation(
                        record: $record,
                        successTitle: 'Finding triaged',
                        callback: fn (Finding $finding, ManagedEnvironment $tenant, User $user): Finding => $workflow->triage($finding, $tenant, $user),
                    );
                })
        )
            ->preserveVisibility()
            ->requireCapability(Capabilities::TENANT_FINDINGS_TRIAGE)
            ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
            ->apply();
    }

    public static function startProgressAction(): Actions\Action
    {
        return UiEnforcement::forAction(
            Actions\Action::make('start_progress')
                ->label('Start progress')
                ->icon('heroicon-o-play')
                ->color('info')
                ->visible(fn (Finding $record): bool => in_array((string) $record->status, [
                    Finding::STATUS_TRIAGED,
                ], true))
                ->action(function (Finding $record, FindingWorkflowService $workflow): void {
                    static::runWorkflowMutation(
                        record: $record,
                        successTitle: 'Finding moved to in progress',
                        callback: fn (Finding $finding, ManagedEnvironment $tenant, User $user): Finding => $workflow->startProgress($finding, $tenant, $user),
                    );
                })
        )
            ->preserveVisibility()
            ->requireCapability(Capabilities::TENANT_FINDINGS_TRIAGE)
            ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
            ->apply();
    }

    public static function assignAction(): Actions\Action
    {
        return UiEnforcement::forAction(
            Actions\Action::make('assign')
                ->label('Assign')
                ->icon('heroicon-o-user-plus')
                ->color('gray')
                ->visible(fn (Finding $record): bool => $record->hasOpenStatus())
                ->fillForm(fn (Finding $record): array => [
                    'assignee_user_id' => $record->assignee_user_id,
                    'owner_user_id' => $record->owner_user_id,
                ])
                ->form([
                    Select::make('assignee_user_id')
                        ->label('Active assignee')
                        ->placeholder('Unassigned')
                        ->helperText('Assign the person currently expected to perform or coordinate the remediation work.')
                        ->options(fn (): array => static::tenantMemberOptions())
                        ->searchable(),
                    Select::make('owner_user_id')
                        ->label('Accountable owner')
                        ->placeholder('Unassigned')
                        ->helperText('Assign the person accountable for ensuring the finding reaches a governed outcome.')
                        ->options(fn (): array => static::tenantMemberOptions())
                        ->searchable(),
                ])
                ->action(function (Finding $record, array $data, FindingWorkflowService $workflow): void {
                    static::runResponsibilityMutation($record, $data, $workflow);
                })
        )
            ->preserveVisibility()
            ->requireCapability(Capabilities::TENANT_FINDINGS_ASSIGN)
            ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
            ->apply();
    }

    public static function resolveAction(): Actions\Action
    {
        $rule = GovernanceActionCatalog::rule('resolve_finding');

        return UiEnforcement::forAction(
            Actions\Action::make('resolve')
                ->label($rule->canonicalLabel)
                ->icon('heroicon-o-check-badge')
                ->color('success')
                ->visible(fn (Finding $record): bool => $record->hasOpenStatus())
                ->requiresConfirmation()
                ->modalHeading($rule->modalHeading)
                ->modalDescription($rule->modalDescription)
                ->form([
                    Select::make('resolved_reason')
                        ->label('Resolution outcome')
                        ->options(static::resolveReasonOptions())
                        ->helperText('Use the canonical manual remediation outcome. Trusted verification is recorded later by system evidence.')
                        ->native(false)
                        ->required()
                        ->selectablePlaceholder(false),
                ])
                ->action(function (Finding $record, array $data, FindingWorkflowService $workflow) use ($rule): void {
                    static::runWorkflowMutation(
                        record: $record,
                        successTitle: $rule->successTitle,
                        callback: fn (Finding $finding, ManagedEnvironment $tenant, User $user): Finding => $workflow->resolve(
                            $finding,
                            $tenant,
                            $user,
                            (string) ($data['resolved_reason'] ?? ''),
                        ),
                    );
                })
        )
            ->preserveVisibility()
            ->requireCapability(Capabilities::TENANT_FINDINGS_RESOLVE)
            ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
            ->apply();
    }

    public static function closeAction(): Actions\Action
    {
        $rule = GovernanceActionCatalog::rule('close_finding');

        return UiEnforcement::forAction(
            Actions\Action::make('close')
                ->label($rule->canonicalLabel)
                ->icon('heroicon-o-x-circle')
                ->color('warning')
                ->visible(fn (Finding $record): bool => $record->hasOpenStatus())
                ->requiresConfirmation()
                ->modalHeading($rule->modalHeading)
                ->modalDescription($rule->modalDescription)
                ->form([
                    Select::make('closed_reason')
                        ->label('Close reason')
                        ->options(static::closeReasonOptions())
                        ->helperText('Use the canonical administrative closure outcome for this finding.')
                        ->native(false)
                        ->required()
                        ->selectablePlaceholder(false),
                ])
                ->action(function (Finding $record, array $data, FindingWorkflowService $workflow) use ($rule): void {
                    static::runWorkflowMutation(
                        record: $record,
                        successTitle: $rule->successTitle,
                        callback: fn (Finding $finding, ManagedEnvironment $tenant, User $user): Finding => $workflow->close(
                            $finding,
                            $tenant,
                            $user,
                            (string) ($data['closed_reason'] ?? ''),
                        ),
                    );
                })
        )
            ->preserveVisibility()
            ->requireCapability(Capabilities::TENANT_FINDINGS_CLOSE)
            ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
            ->apply();
    }

    public static function requestExceptionAction(): Actions\Action
    {
        return UiEnforcement::forAction(
            Actions\Action::make('request_exception')
                ->label('Request exception')
                ->icon('heroicon-o-shield-exclamation')
                ->color('warning')
                ->visible(fn (Finding $record): bool => $record->hasOpenStatus())
                ->requiresConfirmation()
                ->form([
                    Select::make('owner_user_id')
                        ->label('Exception owner')
                        ->required()
                        ->helperText('Owns the exception record, not the finding outcome.')
                        ->options(fn (): array => static::tenantMemberOptions())
                        ->searchable(),
                    Textarea::make('request_reason')
                        ->label('Request reason')
                        ->rows(4)
                        ->required()
                        ->maxLength(2000),
                    DateTimePicker::make('review_due_at')
                        ->label('Review due at')
                        ->required()
                        ->seconds(false),
                    DateTimePicker::make('expires_at')
                        ->label('Expires at')
                        ->seconds(false),
                    Repeater::make('evidence_references')
                        ->label('Evidence references')
                        ->schema([
                            TextInput::make('label')
                                ->label('Label')
                                ->required()
                                ->maxLength(255),
                            TextInput::make('source_type')
                                ->label('Source type')
                                ->required()
                                ->maxLength(255),
                            TextInput::make('source_id')
                                ->label('Source ID')
                                ->maxLength(255),
                            TextInput::make('source_fingerprint')
                                ->label('Fingerprint')
                                ->maxLength(255),
                            DateTimePicker::make('measured_at')
                                ->label('Measured at')
                                ->seconds(false),
                        ])
                        ->defaultItems(0)
                        ->collapsed(),
                ])
                ->action(function (Finding $record, array $data, FindingExceptionService $service): void {
                    static::runExceptionRequestMutation($record, $data, $service);
                })
        )
            ->preserveVisibility()
            ->requireCapability(Capabilities::FINDING_EXCEPTION_MANAGE)
            ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
            ->apply();
    }

    public static function renewExceptionAction(): Actions\Action
    {
        $rule = GovernanceActionCatalog::rule('renew_exception');

        return UiEnforcement::forAction(
            Actions\Action::make('renew_exception')
                ->label($rule->canonicalLabel)
                ->icon('heroicon-o-arrow-path')
                ->color('primary')
                ->visible(fn (Finding $record): bool => static::loadedFindingException($record)?->canBeRenewed() ?? false)
                ->fillForm(fn (Finding $record): array => [
                    'owner_user_id' => static::loadedFindingException($record)?->owner_user_id,
                ])
                ->requiresConfirmation()
                ->modalHeading($rule->modalHeading)
                ->modalDescription($rule->modalDescription)
                ->form([
                    Select::make('owner_user_id')
                        ->label('Exception owner')
                        ->required()
                        ->helperText('Owns the exception record, not the finding outcome.')
                        ->options(fn (): array => static::tenantMemberOptions())
                        ->searchable(),
                    Textarea::make('request_reason')
                        ->label('Renewal reason')
                        ->rows(4)
                        ->required()
                        ->maxLength(2000),
                    DateTimePicker::make('review_due_at')
                        ->label('Review due at')
                        ->required()
                        ->seconds(false),
                    DateTimePicker::make('expires_at')
                        ->label('Requested expiry')
                        ->seconds(false),
                    Repeater::make('evidence_references')
                        ->label('Evidence references')
                        ->schema([
                            TextInput::make('label')
                                ->label('Label')
                                ->required()
                                ->maxLength(255),
                            TextInput::make('source_type')
                                ->label('Source type')
                                ->required()
                                ->maxLength(255),
                            TextInput::make('source_id')
                                ->label('Source ID')
                                ->maxLength(255),
                            TextInput::make('source_fingerprint')
                                ->label('Fingerprint')
                                ->maxLength(255),
                            DateTimePicker::make('measured_at')
                                ->label('Measured at')
                                ->seconds(false),
                        ])
                        ->defaultItems(0)
                        ->collapsed(),
                ])
                ->action(function (Finding $record, array $data, FindingExceptionService $service): void {
                    static::runExceptionRenewalMutation($record, $data, $service);
                })
        )
            ->preserveVisibility()
            ->requireCapability(Capabilities::FINDING_EXCEPTION_MANAGE)
            ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
            ->apply();
    }

    public static function revokeExceptionAction(): Actions\Action
    {
        $rule = GovernanceActionCatalog::rule('revoke_exception');

        return UiEnforcement::forAction(
            Actions\Action::make('revoke_exception')
                ->label($rule->canonicalLabel)
                ->icon('heroicon-o-no-symbol')
                ->color('danger')
                ->visible(fn (Finding $record): bool => static::loadedFindingException($record)?->canBeRevoked() ?? false)
                ->requiresConfirmation()
                ->modalHeading($rule->modalHeading)
                ->modalDescription($rule->modalDescription)
                ->form([
                    Textarea::make('revocation_reason')
                        ->label('Revocation reason')
                        ->rows(4)
                        ->required()
                        ->maxLength(2000),
                ])
                ->action(function (Finding $record, array $data, FindingExceptionService $service): void {
                    static::runExceptionRevocationMutation($record, $data, $service);
                })
        )
            ->preserveVisibility()
            ->requireCapability(Capabilities::FINDING_EXCEPTION_MANAGE)
            ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
            ->apply();
    }

    public static function reopenAction(): Actions\Action
    {
        $rule = GovernanceActionCatalog::rule('reopen_finding');

        return UiEnforcement::forAction(
            Actions\Action::make('reopen')
                ->label($rule->canonicalLabel)
                ->icon('heroicon-o-arrow-uturn-left')
                ->color('primary')
                ->requiresConfirmation()
                ->modalHeading($rule->modalHeading)
                ->modalDescription($rule->modalDescription)
                ->visible(fn (Finding $record): bool => Finding::isTerminalStatus((string) $record->status))
                ->fillForm([
                    'reopen_reason' => Finding::REOPEN_REASON_MANUAL_REASSESSMENT,
                ])
                ->form([
                    Select::make('reopen_reason')
                        ->label('Reopen reason')
                        ->options(static::reopenReasonOptions())
                        ->helperText('Use the canonical reopen reason that best describes why this finding needs active workflow again.')
                        ->native(false)
                        ->required()
                        ->selectablePlaceholder(false),
                ])
                ->action(function (Finding $record, array $data, FindingWorkflowService $workflow) use ($rule): void {
                    static::runWorkflowMutation(
                        record: $record,
                        successTitle: $rule->successTitle,
                        callback: fn (Finding $finding, ManagedEnvironment $tenant, User $user): Finding => $workflow->reopen(
                            $finding,
                            $tenant,
                            $user,
                            (string) ($data['reopen_reason'] ?? ''),
                        ),
                    );
                })
        )
            ->preserveVisibility()
            ->requireCapability(Capabilities::TENANT_FINDINGS_TRIAGE)
            ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
            ->apply();
    }

    /**
     * @param  callable(Finding, ManagedEnvironment, User): Finding  $callback
     */
    private static function runWorkflowMutation(Finding $record, string $successTitle, callable $callback): void
    {
        $pageRecord = $record;
        $record = static::resolveProtectedFindingRecordOrFail($record);
        $tenant = static::resolveTenantContextForCurrentPanel();
        $user = auth()->user();

        if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
            return;
        }

        if ((int) $record->managed_environment_id !== (int) $tenant->getKey()) {
            Notification::make()
                ->title('Finding belongs to a different tenant')
                ->danger()
                ->send();

            return;
        }

        if ((int) $record->workspace_id !== (int) $tenant->workspace_id) {
            Notification::make()
                ->title('Finding belongs to a different workspace')
                ->danger()
                ->send();

            return;
        }

        try {
            $callback($record, $tenant, $user);

            $pageRecord->refresh();
        } catch (InvalidArgumentException $e) {
            Notification::make()
                ->title('Workflow action failed')
                ->body($e->getMessage())
                ->danger()
                ->send();

            return;
        }

        Notification::make()
            ->title($successTitle)
            ->success()
            ->send();
    }

    /**
     * @param  array<string, mixed>  $data
     */
    private static function runResponsibilityMutation(Finding $record, array $data, FindingWorkflowService $workflow): void
    {
        $pageRecord = $record;
        $record = static::resolveProtectedFindingRecordOrFail($record);
        $tenant = static::resolveTenantContextForCurrentPanel();
        $user = auth()->user();

        if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
            return;
        }

        if ((int) $record->managed_environment_id !== (int) $tenant->getKey()) {
            Notification::make()
                ->title('Finding belongs to a different tenant')
                ->danger()
                ->send();

            return;
        }

        if ((int) $record->workspace_id !== (int) $tenant->workspace_id) {
            Notification::make()
                ->title('Finding belongs to a different workspace')
                ->danger()
                ->send();

            return;
        }

        $beforeOwnerUserId = is_numeric($record->owner_user_id) ? (int) $record->owner_user_id : null;
        $beforeAssigneeUserId = is_numeric($record->assignee_user_id) ? (int) $record->assignee_user_id : null;
        $assigneeUserId = is_numeric($data['assignee_user_id'] ?? null) ? (int) $data['assignee_user_id'] : null;
        $ownerUserId = is_numeric($data['owner_user_id'] ?? null) ? (int) $data['owner_user_id'] : null;

        try {
            $workflow->assign($record, $tenant, $user, $assigneeUserId, $ownerUserId);

            $pageRecord->refresh();
        } catch (InvalidArgumentException $e) {
            Notification::make()
                ->title('Responsibility update failed')
                ->body($e->getMessage())
                ->danger()
                ->send();

            return;
        }

        $classification = $workflow->responsibilityChangeClassification(
            beforeOwnerUserId: $beforeOwnerUserId,
            beforeAssigneeUserId: $beforeAssigneeUserId,
            afterOwnerUserId: $ownerUserId,
            afterAssigneeUserId: $assigneeUserId,
        );

        Notification::make()
            ->title($classification === null ? 'Finding responsibility unchanged' : 'Finding responsibility updated')
            ->body($workflow->responsibilityChangeSummary(
                beforeOwnerUserId: $beforeOwnerUserId,
                beforeAssigneeUserId: $beforeAssigneeUserId,
                afterOwnerUserId: $ownerUserId,
                afterAssigneeUserId: $assigneeUserId,
            ))
            ->success()
            ->send();
    }

    /**
     * @param  array<string, mixed>  $data
     */
    private static function runExceptionRequestMutation(Finding $record, array $data, FindingExceptionService $service): void
    {
        $record = static::resolveProtectedFindingRecordOrFail($record);
        $tenant = static::resolveTenantContextForCurrentPanel();
        $user = auth()->user();

        if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
            return;
        }

        try {
            $createdException = $service->request($record, $tenant, $user, $data);
        } catch (InvalidArgumentException $exception) {
            Notification::make()
                ->title('Exception request failed')
                ->body($exception->getMessage())
                ->danger()
                ->send();

            return;
        }

        Notification::make()
            ->title('Exception request submitted')
            ->body('Exception ownership stays separate from the finding owner.')
            ->success()
            ->actions([
                Actions\Action::make('view_exception')
                    ->label('View exception')
                    ->url(static::findingExceptionViewUrl($createdException, $tenant)),
            ])
            ->send();
    }

    /**
     * @param  array<string, mixed>  $data
     */
    private static function runExceptionRenewalMutation(Finding $record, array $data, FindingExceptionService $service): void
    {
        $tenant = static::resolveTenantContextForCurrentPanel();
        $user = auth()->user();

        if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
            return;
        }

        try {
            $renewedException = $service->renew(static::resolveCurrentFindingExceptionOrFail($record), $user, $data);
        } catch (InvalidArgumentException $exception) {
            Notification::make()
                ->title('Renewal request failed')
                ->body($exception->getMessage())
                ->danger()
                ->send();

            return;
        }

        Notification::make()
            ->title('Renewal request submitted')
            ->body('Exception ownership stays separate from the finding owner.')
            ->success()
            ->actions([
                Actions\Action::make('view_exception')
                    ->label('View exception')
                    ->url(static::findingExceptionViewUrl($renewedException, $tenant)),
            ])
            ->send();
    }

    /**
     * @param  array<string, mixed>  $data
     */
    private static function runExceptionRevocationMutation(Finding $record, array $data, FindingExceptionService $service): void
    {
        $tenant = static::resolveTenantContextForCurrentPanel();
        $user = auth()->user();

        if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
            return;
        }

        try {
            $revokedException = $service->revoke(static::resolveCurrentFindingExceptionOrFail($record), $user, $data);
        } catch (InvalidArgumentException $exception) {
            Notification::make()
                ->title('Exception revocation failed')
                ->body($exception->getMessage())
                ->danger()
                ->send();

            return;
        }

        Notification::make()
            ->title('Exception revoked')
            ->success()
            ->actions([
                Actions\Action::make('view_exception')
                    ->label('View exception')
                    ->url(static::findingExceptionViewUrl($revokedException, $tenant)),
            ])
            ->send();
    }

    private static function freshWorkflowRecord(Finding $record): Finding
    {
        return static::resolveProtectedFindingRecordOrFail($record);
    }

    private static function freshWorkflowStatus(Finding $record): string
    {
        return (string) static::freshWorkflowRecord($record)->status;
    }

    private static function resolveProtectedFindingRecordOrFail(Finding|int|string $record): Finding
    {
        $resolvedRecord = static::resolveScopedRecordOrFail($record instanceof Model ? $record->getKey() : $record);

        if (! $resolvedRecord instanceof Finding) {
            abort(404);
        }

        return $resolvedRecord;
    }

    private static function currentFindingException(Finding $record): ?FindingException
    {
        $finding = static::resolveProtectedFindingRecordOrFail($record);

        return static::resolvedFindingException($finding);
    }

    private static function loadedFindingException(Finding $finding): ?FindingException
    {
        $exception = $finding->relationLoaded('findingException')
            ? $finding->findingException
            : null;

        if (! $exception instanceof FindingException) {
            return null;
        }

        $exception->loadMissing('currentDecision');

        return $exception;
    }

    private static function resolvedFindingException(Finding $finding): ?FindingException
    {
        $exception = $finding->relationLoaded('findingException')
            ? $finding->findingException
            : $finding->findingException()->with('currentDecision')->first();

        if (! $exception instanceof FindingException) {
            return null;
        }

        $exception->loadMissing('currentDecision');

        return $exception;
    }

    private static function resolveCurrentFindingExceptionOrFail(Finding $record): FindingException
    {
        $exception = static::currentFindingException($record);

        if (! $exception instanceof FindingException) {
            throw new InvalidArgumentException('This finding does not have an exception to manage.');
        }

        return $exception;
    }

    private static function findingExceptionViewUrl(\App\Models\FindingException $exception, ManagedEnvironment $tenant): string
    {
        $panelId = Filament::getCurrentPanel()?->getId();

        if ($panelId === 'admin') {
            return FindingExceptionResource::getUrl('view', ['record' => $exception], panel: 'admin');
        }

        return FindingExceptionResource::getUrl('view', ['record' => $exception], tenant: $tenant);
    }

    /**
     * @param  array<string, int>  $classificationCounts
     */
    private static function bulkResponsibilityClassificationSummary(array $classificationCounts): ?string
    {
        $parts = [];

        foreach ($classificationCounts as $classification => $count) {
            $parts[] = static::responsibilityClassificationLabel($classification).': '.$count;
        }

        if ($parts === []) {
            return null;
        }

        return implode('. ', $parts).'.';
    }

    private static function responsibilityClassificationLabel(string $classification): string
    {
        return match ($classification) {
            'owner_only' => 'Owner only',
            'assignee_only' => 'Assignee only',
            'owner_and_assignee' => 'Owner and assignee',
            'clear_owner' => 'Cleared owner',
            'clear_assignee' => 'Cleared assignee',
            default => 'Unchanged',
        };
    }

    private static function responsibilityStateColor(Finding $finding): string
    {
        return match ($finding->responsibilityState()) {
            Finding::RESPONSIBILITY_STATE_ORPHANED_ACCOUNTABILITY => 'danger',
            Finding::RESPONSIBILITY_STATE_OWNED_UNASSIGNED => 'warning',
            default => 'success',
        };
    }

    public static function accountableOwnerDisplayFor(Finding $finding): string
    {
        return $finding->ownerUser?->name ?? 'Unassigned';
    }

    public static function activeAssigneeDisplayFor(Finding $finding): string
    {
        return $finding->assigneeUser?->name ?? 'Unassigned';
    }

    private static function responsibilitySummary(Finding $finding): string
    {
        $ownerName = $finding->ownerUser?->name;
        $assigneeName = $finding->assigneeUser?->name;

        return match ($finding->responsibilityState()) {
            Finding::RESPONSIBILITY_STATE_ORPHANED_ACCOUNTABILITY => $assigneeName !== null
                ? "No accountable owner is set. {$assigneeName} is currently carrying the active remediation work."
                : 'No accountable owner or active assignee is set.',
            Finding::RESPONSIBILITY_STATE_OWNED_UNASSIGNED => "{$ownerName} owns the outcome, but active remediation is still unassigned.",
            default => $ownerName === $assigneeName
                ? "{$ownerName} owns the outcome and is also the active assignee."
                : "{$ownerName} owns the outcome. {$assigneeName} is the active assignee.",
        };
    }

    private static function governanceListDescription(Finding $finding): ?string
    {
        $parts = array_values(array_filter([
            static::governanceWarning($finding),
            static::resolvedFindingException($finding)?->owner?->name !== null
                ? 'Exception owner: '.static::resolvedFindingException($finding)?->owner?->name
                : null,
        ]));

        if ($parts === []) {
            return null;
        }

        return implode(' ', $parts);
    }

    private static function governanceWarning(Finding $finding): ?string
    {
        return app(FindingRiskGovernanceResolver::class)
            ->resolveWarningMessage($finding, static::resolvedFindingException($finding));
    }

    private static function governanceWarningColor(Finding $finding): string
    {
        $exception = static::resolvedFindingException($finding);

        if (static::governanceValidityState($finding) === FindingException::VALIDITY_EXPIRING) {
            return 'warning';
        }

        if ($exception instanceof FindingException && $exception->requiresFreshDecisionForFinding($finding)) {
            return 'warning';
        }

        return 'danger';
    }

    private static function governanceValidityState(Finding $finding): ?string
    {
        return app(FindingRiskGovernanceResolver::class)
            ->resolveGovernanceValidity($finding, static::resolvedFindingException($finding));
    }

    private static function findingOutcomeSemantics(): FindingOutcomeSemantics
    {
        return app(FindingOutcomeSemantics::class);
    }

    /**
     * @return array{
     *     terminal_outcome_key: ?string,
     *     label: ?string,
     *     verification_state: string,
     *     verification_label: ?string,
     *     report_bucket: ?string
     * }
     */
    private static function findingOutcome(Finding $finding): array
    {
        return static::findingOutcomeSemantics()->describe($finding);
    }

    /**
     * @return array<string, string>
     */
    private static function resolveReasonOptions(): array
    {
        return [
            Finding::RESOLVE_REASON_REMEDIATED => 'Remediated',
        ];
    }

    /**
     * @return array<string, string>
     */
    private static function closeReasonOptions(): array
    {
        return [
            Finding::CLOSE_REASON_FALSE_POSITIVE => 'False positive',
            Finding::CLOSE_REASON_DUPLICATE => 'Duplicate',
            Finding::CLOSE_REASON_NO_LONGER_APPLICABLE => 'No longer applicable',
        ];
    }

    /**
     * @return array<string, string>
     */
    private static function reopenReasonOptions(): array
    {
        return [
            Finding::REOPEN_REASON_RECURRED_AFTER_RESOLUTION => 'Recurred after resolution',
            Finding::REOPEN_REASON_VERIFICATION_FAILED => 'Verification failed',
            Finding::REOPEN_REASON_MANUAL_REASSESSMENT => 'Manual reassessment',
        ];
    }

    private static function resolveReasonLabel(?string $reason): ?string
    {
        return static::resolveReasonOptions()[$reason] ?? match ($reason) {
            Finding::RESOLVE_REASON_NO_LONGER_DRIFTING => 'No longer drifting',
            Finding::RESOLVE_REASON_PERMISSION_GRANTED => 'Permission granted',
            Finding::RESOLVE_REASON_PERMISSION_REMOVED_FROM_REGISTRY => 'Permission removed from registry',
            Finding::RESOLVE_REASON_ROLE_ASSIGNMENT_REMOVED => 'Role assignment removed',
            Finding::RESOLVE_REASON_GA_COUNT_WITHIN_THRESHOLD => 'GA count within threshold',
            default => null,
        };
    }

    private static function closeReasonLabel(?string $reason): ?string
    {
        return static::closeReasonOptions()[$reason] ?? match ($reason) {
            Finding::CLOSE_REASON_ACCEPTED_RISK => 'Accepted risk',
            default => null,
        };
    }

    private static function reopenReasonLabel(?string $reason): ?string
    {
        return static::reopenReasonOptions()[$reason] ?? null;
    }

    private static function terminalOutcomeLabel(Finding $finding): ?string
    {
        return static::findingOutcome($finding)['label'] ?? null;
    }

    private static function verificationStateLabel(Finding $finding): ?string
    {
        return static::findingOutcome($finding)['verification_label'] ?? null;
    }

    private static function statusDescription(Finding $finding): string
    {
        return static::terminalOutcomeLabel($finding) ?? static::primaryNarrative($finding);
    }

    private static function applyTerminalOutcomeFilter(Builder $query, mixed $value): Builder
    {
        if (! is_string($value) || $value === '') {
            return $query;
        }

        return match ($value) {
            FindingOutcomeSemantics::OUTCOME_RESOLVED_PENDING_VERIFICATION => $query
                ->where('status', Finding::STATUS_RESOLVED)
                ->whereIn('resolved_reason', Finding::manualResolveReasonKeys()),
            FindingOutcomeSemantics::OUTCOME_VERIFIED_CLEARED => $query
                ->where('status', Finding::STATUS_RESOLVED)
                ->whereIn('resolved_reason', Finding::systemResolveReasonKeys()),
            FindingOutcomeSemantics::OUTCOME_CLOSED_FALSE_POSITIVE => $query
                ->where('status', Finding::STATUS_CLOSED)
                ->where('closed_reason', Finding::CLOSE_REASON_FALSE_POSITIVE),
            FindingOutcomeSemantics::OUTCOME_CLOSED_DUPLICATE => $query
                ->where('status', Finding::STATUS_CLOSED)
                ->where('closed_reason', Finding::CLOSE_REASON_DUPLICATE),
            FindingOutcomeSemantics::OUTCOME_CLOSED_NO_LONGER_APPLICABLE => $query
                ->where('status', Finding::STATUS_CLOSED)
                ->where('closed_reason', Finding::CLOSE_REASON_NO_LONGER_APPLICABLE),
            FindingOutcomeSemantics::OUTCOME_RISK_ACCEPTED => $query
                ->where('status', Finding::STATUS_RISK_ACCEPTED),
            default => $query,
        };
    }

    private static function applyVerificationStateFilter(Builder $query, mixed $value): Builder
    {
        if (! is_string($value) || $value === '') {
            return $query;
        }

        return match ($value) {
            FindingOutcomeSemantics::VERIFICATION_PENDING => $query
                ->where('status', Finding::STATUS_RESOLVED)
                ->whereIn('resolved_reason', Finding::manualResolveReasonKeys()),
            FindingOutcomeSemantics::VERIFICATION_VERIFIED => $query
                ->where('status', Finding::STATUS_RESOLVED)
                ->whereIn('resolved_reason', Finding::systemResolveReasonKeys()),
            FindingOutcomeSemantics::VERIFICATION_NOT_APPLICABLE => $query->where(function (Builder $verificationQuery): void {
                $verificationQuery
                    ->where('status', '!=', Finding::STATUS_RESOLVED)
                    ->orWhereNull('resolved_reason')
                    ->orWhereNotIn('resolved_reason', Finding::resolveReasonKeys());
            }),
            default => $query,
        };
    }

    private static function primaryNarrative(Finding $finding): string
    {
        return app(FindingRiskGovernanceResolver::class)
            ->resolvePrimaryNarrative($finding, static::resolvedFindingException($finding));
    }

    private static function historicalContext(Finding $finding): ?string
    {
        return app(FindingRiskGovernanceResolver::class)
            ->resolveHistoricalContext($finding);
    }

    private static function primaryNextAction(Finding $finding): ?string
    {
        return app(FindingRiskGovernanceResolver::class)
            ->resolvePrimaryNextAction($finding, static::resolvedFindingException($finding));
    }

    public static function dueAttentionLabelFor(Finding $finding): ?string
    {
        if (! $finding->hasOpenStatus() || ! $finding->due_at) {
            return null;
        }

        if ($finding->due_at->isPast()) {
            return 'Overdue';
        }

        if ($finding->due_at->lessThanOrEqualTo(now()->addDays(3))) {
            return 'Due soon';
        }

        return null;
    }

    public static function dueAttentionColorFor(Finding $finding): string
    {
        return match (static::dueAttentionLabelFor($finding)) {
            'Overdue' => 'danger',
            'Due soon' => 'warning',
            default => 'gray',
        };
    }

    /**
     * @return array<int, string>
     */
    private static function tenantMemberOptions(): array
    {
        $tenant = static::resolveTenantContextForCurrentPanel();

        if (! $tenant instanceof ManagedEnvironment) {
            return [];
        }

        /** @var ManagedEnvironmentAccessScopeResolver $scopeResolver */
        $scopeResolver = app(ManagedEnvironmentAccessScopeResolver::class);

        return User::query()
            ->whereHas('workspaceMemberships', fn (Builder $query): Builder => $query->where('workspace_id', (int) $tenant->workspace_id))
            ->orderBy('name')
            ->orderBy('email')
            ->get(['id', 'name', 'email'])
            ->filter(fn (User $user): bool => $scopeResolver->canAccess($user, $tenant))
            ->mapWithKeys(fn (User $user): array => [
                (int) $user->id => trim((string) ($user->name ?: $user->email)),
            ])
            ->all();
    }

    /**
     * @return array{open: int, overdue: int, high_severity: int, risk_accepted: int, total: int}
     */
    public static function findingStatsForCurrentTenant(): array
    {
        $tenant = static::resolveTenantContextForCurrentPanel();

        if (! $tenant instanceof ManagedEnvironment) {
            return ['open' => 0, 'overdue' => 0, 'high_severity' => 0, 'risk_accepted' => 0, 'total' => 0];
        }

        $now = now()->toDateTimeString();

        $counts = Finding::query()
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->selectRaw('count(*) as total')
            ->selectRaw("sum(case when status in ('new', 'triaged', 'in_progress', 'reopened') then 1 else 0 end) as open")
            ->selectRaw("sum(case when status in ('new', 'triaged', 'in_progress', 'reopened') and due_at is not null and due_at < ? then 1 else 0 end) as overdue", [$now])
            ->selectRaw("sum(case when severity in ('high', 'critical') and status in ('new', 'triaged', 'in_progress', 'reopened') then 1 else 0 end) as high_severity")
            ->selectRaw("sum(case when status = 'risk_accepted' then 1 else 0 end) as risk_accepted")
            ->first();

        return [
            'open' => (int) ($counts?->open ?? 0),
            'overdue' => (int) ($counts?->overdue ?? 0),
            'high_severity' => (int) ($counts?->high_severity ?? 0),
            'risk_accepted' => (int) ($counts?->risk_accepted ?? 0),
            'total' => (int) ($counts?->total ?? 0),
        ];
    }
}
