<?php

namespace App\Filament\Resources;

use App\Filament\Concerns\InteractsWithTenantOwnedRecords;
use App\Filament\Concerns\ResolvesPanelTenantContext;
use App\Filament\Concerns\ScopesGlobalSearchToTenant;
use App\Filament\Concerns\WorkspaceScopedEnvironmentRoutes;
use App\Filament\Resources\PolicyVersionResource\Pages;
use App\Filament\Support\NormalizedDiffSurface;
use App\Filament\Support\NormalizedSettingsSurface;
use App\Jobs\BulkPolicyVersionForceDeleteJob;
use App\Jobs\BulkPolicyVersionPruneJob;
use App\Jobs\BulkPolicyVersionRestoreJob;
use App\Models\BackupItem;
use App\Models\BackupSet;
use App\Models\ManagedEnvironment;
use App\Models\PolicyVersion;
use App\Models\User;
use App\Services\Auth\CapabilityResolver;
use App\Services\Intune\AuditLogger;
use App\Services\Intune\PolicyNormalizer;
use App\Services\Intune\VersionDiff;
use App\Services\OperationRunService;
use App\Services\Operations\BulkSelectionIdentity;
use App\Support\Auth\Capabilities;
use App\Support\BackupQuality\BackupQualityResolver;
use App\Support\Badges\BadgeDomain;
use App\Support\Badges\BadgeRenderer;
use App\Support\Badges\TagBadgeDomain;
use App\Support\Badges\TagBadgeRenderer;
use App\Support\Baselines\PolicyVersionCapturePurpose;
use App\Support\Filament\FilterOptionCatalog;
use App\Support\Filament\FilterPresets;
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\OpsUx\OperationUxPresenter;
use App\Support\Rbac\UiEnforcement;
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 BackedEnum;
use Carbon\CarbonImmutable;
use Filament\Actions;
use Filament\Actions\BulkAction;
use Filament\Actions\BulkActionGroup;
use Filament\Forms;
use Filament\Infolists;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Tabs;
use Filament\Schemas\Components\Tabs\Tab;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use UnitEnum;

class PolicyVersionResource extends Resource
{
    use InteractsWithTenantOwnedRecords;
    use ResolvesPanelTenantContext;
    use ScopesGlobalSearchToTenant;
    use WorkspaceScopedEnvironmentRoutes;

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

    protected static ?string $tenantOwnershipRelationshipName = 'tenant';

    protected static bool $isGloballySearchable = false;

    protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-list-bullet';

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

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

    public static function canViewAny(): bool
    {
        $tenant = static::resolveTenantContextForCurrentPanel();
        $user = auth()->user();

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

        /** @var CapabilityResolver $resolver */
        $resolver = app(CapabilityResolver::class);

        return $resolver->isMember($user, $tenant)
            && $resolver->can($user, $tenant, Capabilities::TENANT_VIEW);
    }

    public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
    {
        return ActionSurfaceDeclaration::forResource(ActionSurfaceProfile::CrudListAndView)
            ->exempt(ActionSurfaceSlot::ListHeader, 'Policy versions list intentionally has no header actions; versions are created by sync and captures.')
            ->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ClickableRow->value)
            ->satisfy(ActionSurfaceSlot::ListRowMoreMenu, 'Secondary row actions are grouped under "More".')
            ->satisfy(ActionSurfaceSlot::ListBulkMoreGroup, 'Bulk actions are grouped under "More".')
            ->satisfy(ActionSurfaceSlot::ListEmptyState, 'Empty-state CTA routes operators to backup sets when no versions are available yet.')
            ->exempt(ActionSurfaceSlot::DetailHeader, 'View page header actions are intentionally minimal for now.');
    }

    public static function infolist(Schema $schema): Schema
    {
        return $schema
            ->schema([
                Infolists\Components\TextEntry::make('policy.display_name')
                    ->label(static::text('common.policy'))
                    ->state(fn (PolicyVersion $record): string => static::resolvedDisplayName($record)),
                Infolists\Components\TextEntry::make('version_number')->label(static::text('common.version')),
                Infolists\Components\TextEntry::make('policy_type')
                    ->label(static::text('common.type'))
                    ->badge()
                    ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::PolicyType))
                    ->color(TagBadgeRenderer::color(TagBadgeDomain::PolicyType)),
                Infolists\Components\TextEntry::make('platform')
                    ->label(static::text('common.platform'))
                    ->badge()
                    ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::Platform))
                    ->color(TagBadgeRenderer::color(TagBadgeDomain::Platform)),
                Infolists\Components\TextEntry::make('created_by')->label(static::text('common.actor')),
                Infolists\Components\TextEntry::make('captured_at')->dateTime()->label(static::text('common.captured')),
                Section::make(static::text('versions.backup_quality_section'))
                    ->schema([
                        Infolists\Components\TextEntry::make('quality_snapshot_mode')
                            ->label(static::text('common.snapshot'))
                            ->badge()
                            ->state(fn (PolicyVersion $record): string => static::policyVersionQualitySummary($record)->snapshotMode)
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::PolicySnapshotMode))
                            ->color(BadgeRenderer::color(BadgeDomain::PolicySnapshotMode))
                            ->icon(BadgeRenderer::icon(BadgeDomain::PolicySnapshotMode))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::PolicySnapshotMode)),
                        Infolists\Components\TextEntry::make('quality_summary')
                            ->label(static::text('versions.backup_quality'))
                            ->state(fn (PolicyVersion $record): string => static::policyVersionQualitySummary($record)->compactSummary),
                        Infolists\Components\TextEntry::make('quality_assignment_signal')
                            ->label(static::text('versions.assignment_quality'))
                            ->state(fn (PolicyVersion $record): string => static::policyVersionAssignmentQualityLabel($record)),
                        Infolists\Components\TextEntry::make('quality_next_action')
                            ->label(static::text('versions.next_action'))
                            ->state(fn (PolicyVersion $record): string => static::policyVersionQualitySummary($record)->nextAction),
                        Infolists\Components\TextEntry::make('quality_integrity_warning')
                            ->label(static::text('versions.integrity_note'))
                            ->state(fn (PolicyVersion $record): ?string => static::policyVersionQualitySummary($record)->integrityWarning)
                            ->visible(fn (PolicyVersion $record): bool => static::policyVersionQualitySummary($record)->hasIntegrityWarning())
                            ->columnSpanFull(),
                        Infolists\Components\TextEntry::make('quality_boundary')
                            ->label(static::text('versions.boundary'))
                            ->state(fn (PolicyVersion $record): string => static::policyVersionQualitySummary($record)->positiveClaimBoundary)
                            ->columnSpanFull(),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),
                Section::make(static::text('versions.related_context_section'))
                    ->schema([
                        Infolists\Components\ViewEntry::make('related_context')
                            ->label('')
                            ->view('filament.infolists.entries.related-context')
                            ->state(fn (PolicyVersion $record): array => static::relatedContextEntries($record))
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull(),
                Tabs::make()
                    ->activeTab(1)
                    ->persistTabInQueryString('tab')
                    ->columnSpanFull()
                    ->tabs([
                        Tab::make(static::text('common.settings'))
                            ->id('normalized-settings')
                            ->schema([
                                Infolists\Components\ViewEntry::make('normalized_settings')
                                    ->view('filament.infolists.entries.normalized-settings')
                                    ->state(function (PolicyVersion $record) {
                                        $normalized = app(PolicyNormalizer::class)->normalize(
                                            is_array($record->snapshot) ? $record->snapshot : [],
                                            $record->policy_type ?? '',
                                            $record->platform
                                        );

                                        $normalized['context'] = 'version';
                                        $normalized['record_id'] = (string) $record->getKey();
                                        $normalized['policy_type'] = $record->policy_type;

                                        return NormalizedSettingsSurface::build($normalized, 'policy_version');
                                    }),
                            ]),
                        Tab::make(static::text('resource.tab_json'))
                            ->id('raw-json')
                            ->schema([
                                Infolists\Components\ViewEntry::make('snapshot_pretty')
                                    ->view('filament.infolists.entries.snapshot-json')
                                    ->state(fn (PolicyVersion $record) => $record->snapshot ?? []),
                            ]),
                        Tab::make(static::text('versions.diff_tab'))
                            ->id('diff')
                            ->schema([
                                Infolists\Components\ViewEntry::make('normalized_diff')
                                    ->view('filament.infolists.entries.normalized-diff')
                                    ->state(function (PolicyVersion $record) {
                                        $normalizer = app(PolicyNormalizer::class);
                                        $diff = app(VersionDiff::class);

                                        $previous = $record->previous();
                                        $from = $previous
                                            ? $normalizer->flattenForDiff($previous->snapshot ?? [], $previous->policy_type ?? '', $previous->platform)
                                            : [];
                                        $to = $normalizer->flattenForDiff($record->snapshot ?? [], $record->policy_type ?? '', $record->platform);

                                        $result = $diff->compare($from, $to);
                                        $result['policy_type'] = $record->policy_type;

                                        return NormalizedDiffSurface::build($result, 'policy_version');
                                    }),
                                Infolists\Components\ViewEntry::make('diff_json')
                                    ->label(static::text('versions.raw_diff_advanced'))
                                    ->view('filament.infolists.entries.snapshot-json')
                                    ->state(function (PolicyVersion $record) {
                                        $previous = $record->previous();

                                        if (! $previous) {
                                            return ['summary' => 'No previous version'];
                                        }

                                        $diff = app(VersionDiff::class)->compare(
                                            $previous->snapshot ?? [],
                                            $record->snapshot ?? []
                                        );

                                        $filter = static fn (array $items): array => array_filter(
                                            $items,
                                            static fn (mixed $value, string $key): bool => ! str_contains($key, '@odata.context'),
                                            ARRAY_FILTER_USE_BOTH
                                        );

                                        $added = $filter($diff['added'] ?? []);
                                        $removed = $filter($diff['removed'] ?? []);
                                        $changed = $filter($diff['changed'] ?? []);

                                        return [
                                            'summary' => [
                                                'added' => count($added),
                                                'removed' => count($removed),
                                                'changed' => count($changed),
                                                'message' => sprintf(
                                                    '%d added, %d removed, %d changed',
                                                    count($added),
                                                    count($removed),
                                                    count($changed)
                                                ),
                                            ],
                                            'added' => $added,
                                            'removed' => $removed,
                                            'changed' => $changed,
                                        ];
                                    }),
                            ]),
                    ]),
            ]);
    }

    public static function table(Table $table): Table
    {
        $bulkPruneVersions = BulkAction::make('bulk_prune_versions')
            ->label(static::text('versions.prune_versions'))
            ->icon('heroicon-o-trash')
            ->color('danger')
            ->requiresConfirmation()
            ->modalDescription(static::text('versions.prune_modal_description'))
            ->hidden(function (HasTable $livewire): bool {
                $trashedFilterState = $livewire->getTableFilterState(TrashedFilter::class) ?? [];
                $value = $trashedFilterState['value'] ?? null;

                $isOnlyTrashed = in_array($value, [0, '0', false], true);

                return $isOnlyTrashed;
            })
            ->form(function (Collection $records) {
                $fields = [
                    Forms\Components\TextInput::make('retention_days')
                        ->label(static::text('versions.retention_days'))
                        ->helperText(static::text('versions.retention_days_helper'))
                        ->numeric()
                        ->required()
                        ->default(90)
                        ->minValue(1),
                ];

                if ($records->count() >= 20) {
                    $fields[] = Forms\Components\TextInput::make('confirmation')
                        ->label(static::text('common.type_delete_to_confirm'))
                        ->required()
                        ->in(['DELETE'])
                        ->validationMessages([
                            'in' => static::text('common.type_delete_to_confirm_validation'),
                        ]);
                }

                return $fields;
            })
            ->action(function (Collection $records, array $data) {
                $tenant = static::resolveTenantContextForCurrentPanel();
                $user = auth()->user();
                $count = $records->count();
                $ids = $records->pluck('id')->toArray();

                $retentionDays = (int) ($data['retention_days'] ?? 90);

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

                if (! $user instanceof User) {
                    abort(403);
                }

                $initiator = $user;

                /** @var BulkSelectionIdentity $selection */
                $selection = app(BulkSelectionIdentity::class);
                $selectionIdentity = $selection->fromIds($ids);

                /** @var OperationRunService $runs */
                $runs = app(OperationRunService::class);

                $opRun = $runs->enqueueBulkOperation(
                    tenant: $tenant,
                    type: 'policy_version.prune',
                    targetScope: [
                        'entra_tenant_id' => (string) ($tenant->managed_environment_id ?? $tenant->external_id),
                    ],
                    selectionIdentity: $selectionIdentity,
                    dispatcher: function ($operationRun) use ($tenant, $initiator, $ids, $retentionDays): void {
                        BulkPolicyVersionPruneJob::dispatch(
                            tenantId: (int) $tenant->getKey(),
                            userId: (int) $initiator->getKey(),
                            policyVersionIds: $ids,
                            retentionDays: $retentionDays,
                            operationRun: $operationRun,
                        );
                    },
                    initiator: $initiator,
                    extraContext: [
                        'policy_version_count' => $count,
                        'retention_days' => $retentionDays,
                    ],
                    emitQueuedNotification: false,
                );

                OperationUxPresenter::queuedToast('policy_version.prune')
                    ->actions([
                        Actions\Action::make('view_run')
                            ->label(static::text('common.open_operation'))
                            ->url(OperationRunLinks::view($opRun, $tenant)),
                    ])
                    ->send();
            })
            ->deselectRecordsAfterCompletion();

        UiEnforcement::forBulkAction($bulkPruneVersions)
            ->requireCapability(Capabilities::TENANT_MANAGE)
            ->tooltip(static::text('versions.manage_permission_tooltip'))
            ->apply();

        $bulkRestoreVersions = BulkAction::make('bulk_restore_versions')
            ->label(static::text('versions.restore_versions'))
            ->icon('heroicon-o-arrow-uturn-left')
            ->color('success')
            ->requiresConfirmation()
            ->hidden(function (HasTable $livewire): bool {
                $trashedFilterState = $livewire->getTableFilterState(TrashedFilter::class) ?? [];
                $value = $trashedFilterState['value'] ?? null;

                $isOnlyTrashed = in_array($value, [0, '0', false], true);

                return ! $isOnlyTrashed;
            })
            ->modalHeading(fn (Collection $records) => static::text('versions.restore_versions_modal_heading', ['count' => $records->count()]))
            ->modalDescription(static::text('versions.restore_versions_modal_description'))
            ->action(function (Collection $records) {
                $tenant = static::resolveTenantContextForCurrentPanel();
                $user = auth()->user();
                $count = $records->count();
                $ids = $records->pluck('id')->toArray();

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

                if (! $user instanceof User) {
                    abort(403);
                }

                $initiator = $user;

                /** @var BulkSelectionIdentity $selection */
                $selection = app(BulkSelectionIdentity::class);
                $selectionIdentity = $selection->fromIds($ids);

                /** @var OperationRunService $runs */
                $runs = app(OperationRunService::class);

                $opRun = $runs->enqueueBulkOperation(
                    tenant: $tenant,
                    type: 'policy_version.restore',
                    targetScope: [
                        'entra_tenant_id' => (string) ($tenant->managed_environment_id ?? $tenant->external_id),
                    ],
                    selectionIdentity: $selectionIdentity,
                    dispatcher: function ($operationRun) use ($tenant, $initiator, $ids): void {
                        BulkPolicyVersionRestoreJob::dispatch(
                            tenantId: (int) $tenant->getKey(),
                            userId: (int) $initiator->getKey(),
                            policyVersionIds: $ids,
                            operationRun: $operationRun,
                        );
                    },
                    initiator: $initiator,
                    extraContext: [
                        'policy_version_count' => $count,
                    ],
                    emitQueuedNotification: false,
                );

                OperationUxPresenter::queuedToast('policy_version.restore')
                    ->actions([
                        Actions\Action::make('view_run')
                            ->label(static::text('common.open_operation'))
                            ->url(OperationRunLinks::view($opRun, $tenant)),
                    ])
                    ->send();
            })
            ->deselectRecordsAfterCompletion();

        UiEnforcement::forBulkAction($bulkRestoreVersions)
            ->requireCapability(Capabilities::TENANT_MANAGE)
            ->tooltip(static::text('versions.manage_permission_tooltip'))
            ->apply();

        $bulkForceDeleteVersions = BulkAction::make('bulk_force_delete_versions')
            ->label(static::text('versions.force_delete_versions'))
            ->icon('heroicon-o-trash')
            ->color('danger')
            ->requiresConfirmation()
            ->hidden(function (HasTable $livewire): bool {
                $trashedFilterState = $livewire->getTableFilterState(TrashedFilter::class) ?? [];
                $value = $trashedFilterState['value'] ?? null;

                $isOnlyTrashed = in_array($value, [0, '0', false], true);

                return ! $isOnlyTrashed;
            })
            ->modalHeading(fn (Collection $records) => static::text('versions.force_delete_versions_modal_heading', ['count' => $records->count()]))
            ->modalDescription(static::text('versions.force_delete_versions_modal_description'))
            ->form([
                Forms\Components\TextInput::make('confirmation')
                    ->label(static::text('common.type_delete_to_confirm'))
                    ->required()
                    ->in(['DELETE'])
                    ->validationMessages([
                        'in' => static::text('common.type_delete_to_confirm_validation'),
                    ]),
            ])
            ->action(function (Collection $records, array $data) {
                $tenant = static::resolveTenantContextForCurrentPanel();
                $user = auth()->user();
                $count = $records->count();
                $ids = $records->pluck('id')->toArray();

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

                if (! $user instanceof User) {
                    abort(403);
                }

                $initiator = $user;

                /** @var BulkSelectionIdentity $selection */
                $selection = app(BulkSelectionIdentity::class);
                $selectionIdentity = $selection->fromIds($ids);

                /** @var OperationRunService $runs */
                $runs = app(OperationRunService::class);

                $opRun = $runs->enqueueBulkOperation(
                    tenant: $tenant,
                    type: 'policy_version.force_delete',
                    targetScope: [
                        'entra_tenant_id' => (string) ($tenant->managed_environment_id ?? $tenant->external_id),
                    ],
                    selectionIdentity: $selectionIdentity,
                    dispatcher: function ($operationRun) use ($tenant, $initiator, $ids): void {
                        BulkPolicyVersionForceDeleteJob::dispatch(
                            tenantId: (int) $tenant->getKey(),
                            userId: (int) $initiator->getKey(),
                            policyVersionIds: $ids,
                            operationRun: $operationRun,
                        );
                    },
                    initiator: $initiator,
                    extraContext: [
                        'policy_version_count' => $count,
                    ],
                    emitQueuedNotification: false,
                );

                OperationUxPresenter::queuedToast('policy_version.force_delete')
                    ->actions([
                        Actions\Action::make('view_run')
                            ->label(static::text('common.open_operation'))
                            ->url(OperationRunLinks::view($opRun, $tenant)),
                    ])
                    ->send();
            })
            ->deselectRecordsAfterCompletion();

        UiEnforcement::forBulkAction($bulkForceDeleteVersions)
            ->requireCapability(Capabilities::TENANT_MANAGE)
            ->tooltip(static::text('versions.manage_permission_tooltip'))
            ->apply();

        return $table
            ->defaultSort('captured_at', 'desc')
            ->paginated(\App\Support\Filament\TablePaginationProfiles::resource())
            ->persistFiltersInSession()
            ->persistSearchInSession()
            ->persistSortInSession()
            ->columns([
                Tables\Columns\TextColumn::make('policy.display_name')
                    ->label(static::text('common.policy'))
                    ->sortable()
                    ->searchable()
                    ->getStateUsing(fn (PolicyVersion $record): string => static::resolvedDisplayName($record)),
                Tables\Columns\TextColumn::make('version_number')
                    ->label(static::text('common.version'))
                    ->sortable(),
                Tables\Columns\TextColumn::make('snapshot_mode')
                    ->label(static::text('common.snapshot'))
                    ->badge()
                    ->state(fn (PolicyVersion $record): string => static::policyVersionQualitySummary($record)->snapshotMode)
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::PolicySnapshotMode))
                    ->color(BadgeRenderer::color(BadgeDomain::PolicySnapshotMode))
                    ->icon(BadgeRenderer::icon(BadgeDomain::PolicySnapshotMode))
                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::PolicySnapshotMode)),
                Tables\Columns\TextColumn::make('backup_quality')
                    ->label(static::text('versions.backup_quality'))
                    ->state(fn (PolicyVersion $record): string => static::policyVersionQualitySummary($record)->compactSummary)
                    ->description(fn (PolicyVersion $record): string => static::policyVersionQualitySummary($record)->nextAction)
                    ->wrap(),
                Tables\Columns\TextColumn::make('policy_type')
                    ->label(static::text('common.type'))
                    ->badge()
                    ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::PolicyType))
                    ->color(TagBadgeRenderer::color(TagBadgeDomain::PolicyType)),
                Tables\Columns\TextColumn::make('platform')
                    ->label(static::text('common.platform'))
                    ->badge()
                    ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::Platform))
                    ->color(TagBadgeRenderer::color(TagBadgeDomain::Platform)),
                Tables\Columns\TextColumn::make('created_by')->label(static::text('common.actor'))->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('captured_at')->label(static::text('common.captured'))->dateTime()->sortable(),
            ])
            ->filters([
                Tables\Filters\SelectFilter::make('policy_type')
                    ->label(static::text('common.type'))
                    ->options(FilterOptionCatalog::policyTypes())
                    ->searchable(),
                Tables\Filters\SelectFilter::make('platform')
                    ->label(static::text('common.platform'))
                    ->options(FilterOptionCatalog::platforms())
                    ->searchable(),
                FilterPresets::dateRange('captured_at', static::text('common.captured'), 'captured_at'),
                FilterPresets::archived(),
            ])
            ->recordUrl(static fn (PolicyVersion $record): ?string => static::canView($record)
                ? static::getUrl('view', ['record' => $record])
                : null)
            ->actions([
                static::primaryRelatedAction(),
                Actions\ActionGroup::make([
                    (function (): Actions\Action {
                        $action = Actions\Action::make('restore_via_wizard')
                            ->label(static::text('versions.restore_via_wizard'))
                            ->icon('heroicon-o-arrow-path-rounded-square')
                            ->color('primary')
                            ->requiresConfirmation()
                            ->modalHeading(fn (PolicyVersion $record): string => static::text('versions.restore_via_wizard_modal_heading', ['version' => $record->version_number]))
                            ->modalSubheading(static::text('versions.restore_via_wizard_modal_subheading'))
                            ->visible(function (): bool {
                                $tenant = static::resolveTenantContextForCurrentPanel();
                                $user = auth()->user();

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

                                /** @var CapabilityResolver $resolver */
                                $resolver = app(CapabilityResolver::class);

                                return $resolver->isMember($user, $tenant);
                            })
                            ->disabled(function (PolicyVersion $record): bool {
                                if (static::policyVersionQualitySummary($record)->snapshotMode === 'metadata_only') {
                                    return true;
                                }

                                $tenant = static::resolveTenantContextForCurrentPanel();
                                $user = auth()->user();

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

                                /** @var CapabilityResolver $resolver */
                                $resolver = app(CapabilityResolver::class);

                                if (! $resolver->isMember($user, $tenant)) {
                                    return true;
                                }

                                return ! $resolver->can($user, $tenant, Capabilities::TENANT_MANAGE);
                            })
                            ->tooltip(function (PolicyVersion $record): ?string {
                                $tenant = static::resolveTenantContextForCurrentPanel();
                                $user = auth()->user();

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

                                /** @var CapabilityResolver $resolver */
                                $resolver = app(CapabilityResolver::class);

                                if (! $resolver->isMember($user, $tenant)) {
                                    return null;
                                }

                                if (! $resolver->can($user, $tenant, Capabilities::TENANT_MANAGE)) {
                                    return static::text('versions.restore_run_permission_tooltip');
                                }

                                if (static::policyVersionQualitySummary($record)->snapshotMode === 'metadata_only') {
                                    return static::text('versions.metadata_only_tooltip');
                                }

                                return null;
                            })
                            ->action(function (PolicyVersion $record) {
                                $tenant = static::resolveTenantContextForCurrentPanel();
                                $user = auth()->user();

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

                                /** @var CapabilityResolver $resolver */
                                $resolver = app(CapabilityResolver::class);

                                if (! $resolver->isMember($user, $tenant)) {
                                    abort(404);
                                }

                                if (! $resolver->can($user, $tenant, Capabilities::TENANT_MANAGE)) {
                                    abort(403);
                                }

                                if (static::policyVersionQualitySummary($record)->snapshotMode === 'metadata_only') {
                                    Notification::make()
                                        ->title(static::text('versions.restore_disabled_metadata_title'))
                                        ->body(static::text('versions.restore_disabled_metadata_body'))
                                        ->warning()
                                        ->send();

                                    return;
                                }

                                if (! $tenant || $record->managed_environment_id !== $tenant->id) {
                                    Notification::make()
                                        ->title(static::text('versions.different_tenant_title'))
                                        ->danger()
                                        ->send();

                                    return;
                                }

                                $policy = $record->policy;

                                if (! $policy) {
                                    Notification::make()
                                        ->title(static::text('versions.missing_policy_title'))
                                        ->danger()
                                        ->send();

                                    return;
                                }

                                $backupSet = BackupSet::create([
                                    'managed_environment_id' => $tenant->id,
                                    'name' => static::text('versions.backup_set_name', [
                                        'policy' => $policy->display_name,
                                        'version' => $record->version_number,
                                    ]),
                                    'created_by' => $user?->email,
                                    'status' => 'completed',
                                    'item_count' => 1,
                                    'completed_at' => CarbonImmutable::now(),
                                    'metadata' => [
                                        'source' => 'policy_version',
                                        'policy_version_id' => $record->id,
                                        'policy_version_number' => $record->version_number,
                                        'policy_id' => $policy->id,
                                        'redaction_version' => $record->redaction_version,
                                        'integrity_warning' => RedactionIntegrity::noteForPolicyVersion($record),
                                    ],
                                ]);

                                $scopeTags = is_array($record->scope_tags) ? $record->scope_tags : [];
                                $scopeTagIds = $scopeTags['ids'] ?? null;
                                $scopeTagNames = $scopeTags['names'] ?? null;

                                $backupItemMetadata = [
                                    'source' => 'policy_version',
                                    'snapshot_source' => $record->snapshotSource(),
                                    'display_name' => $policy->display_name,
                                    'policy_version_id' => $record->id,
                                    'policy_version_number' => $record->version_number,
                                    'version_captured_at' => $record->captured_at?->toIso8601String(),
                                    'redaction_version' => $record->redaction_version,
                                    'warnings' => $record->warningMessages(),
                                    'assignments_fetch_failed' => $record->assignmentsFetchFailed(),
                                    'has_orphaned_assignments' => $record->hasOrphanedAssignments(),
                                ];

                                $integrityWarning = RedactionIntegrity::noteForPolicyVersion($record);

                                if ($integrityWarning !== null) {
                                    $backupItemMetadata['integrity_warning'] = $integrityWarning;
                                }

                                $secretFingerprints = is_array($record->secret_fingerprints) ? $record->secret_fingerprints : [];
                                $protectedPathsCount = RedactionIntegrity::fingerprintCount($secretFingerprints);

                                if ($protectedPathsCount > 0) {
                                    $backupItemMetadata['protected_paths_count'] = $protectedPathsCount;
                                }

                                if (is_array($scopeTagIds) && $scopeTagIds !== []) {
                                    $backupItemMetadata['scope_tag_ids'] = $scopeTagIds;
                                }

                                if (is_array($scopeTagNames) && $scopeTagNames !== []) {
                                    $backupItemMetadata['scope_tag_names'] = $scopeTagNames;
                                }

                                $backupItem = BackupItem::create([
                                    'managed_environment_id' => $tenant->id,
                                    'backup_set_id' => $backupSet->id,
                                    'policy_id' => $policy->id,
                                    'policy_version_id' => $record->id,
                                    'policy_identifier' => $policy->external_id,
                                    'policy_type' => $policy->policy_type,
                                    'platform' => $policy->platform,
                                    'captured_at' => $record->captured_at ?? CarbonImmutable::now(),
                                    'payload' => $record->snapshot ?? [],
                                    'metadata' => $backupItemMetadata,
                                    'assignments' => $record->assignments,
                                ]);

                                return redirect()->to(RestoreRunResource::getUrl('create', [
                                    'backup_set_id' => $backupSet->id,
                                    'scope_mode' => 'selected',
                                    'backup_item_ids' => [$backupItem->id],
                                ]));
                            });

                        return $action;
                    })(),
                    (function (): Actions\Action {
                        $action = Actions\Action::make('archive')
                            ->label(static::text('versions.archive'))
                            ->color('danger')
                            ->icon('heroicon-o-archive-box-x-mark')
                            ->requiresConfirmation()
                            ->visible(fn (PolicyVersion $record) => ! $record->trashed())
                            ->action(function (PolicyVersion $record, AuditLogger $auditLogger) {
                                $user = auth()->user();
                                $tenant = $record->tenant;

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

                                $record->delete();

                                if ($record->tenant) {
                                    $auditLogger->log(
                                        tenant: $record->tenant,
                                        action: 'policy_version.deleted',
                                        resourceType: 'policy_version',
                                        resourceId: (string) $record->id,
                                        status: 'success',
                                        context: ['metadata' => ['policy_id' => $record->policy_id, 'version' => $record->version_number]]
                                    );
                                }

                                Notification::make()
                                    ->title(static::text('versions.archived_title'))
                                    ->success()
                                    ->send();
                            });

                        UiEnforcement::forAction($action)
                            ->preserveVisibility()
                            ->requireCapability(Capabilities::TENANT_MANAGE)
                            ->tooltip(static::text('versions.manage_permission_tooltip'))
                            ->apply();

                        return $action;
                    })(),
                    (function (): Actions\Action {
                        $action = Actions\Action::make('forceDelete')
                            ->label(static::text('versions.force_delete'))
                            ->color('danger')
                            ->icon('heroicon-o-trash')
                            ->requiresConfirmation()
                            ->visible(fn (PolicyVersion $record) => $record->trashed())
                            ->action(function (PolicyVersion $record, AuditLogger $auditLogger) {
                                $user = auth()->user();
                                $tenant = $record->tenant;

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

                                if ($record->tenant) {
                                    $auditLogger->log(
                                        tenant: $record->tenant,
                                        action: 'policy_version.force_deleted',
                                        resourceType: 'policy_version',
                                        resourceId: (string) $record->id,
                                        status: 'success',
                                        context: ['metadata' => ['policy_id' => $record->policy_id, 'version' => $record->version_number]]
                                    );
                                }

                                $record->forceDelete();

                                Notification::make()
                                    ->title(static::text('versions.force_deleted_title'))
                                    ->success()
                                    ->send();
                            });

                        UiEnforcement::forAction($action)
                            ->preserveVisibility()
                            ->requireCapability(Capabilities::TENANT_MANAGE)
                            ->tooltip(static::text('versions.manage_permission_tooltip'))
                            ->apply();

                        return $action;
                    })(),

                    (function (): Actions\Action {
                        $action = Actions\Action::make('restore')
                            ->label(static::text('common.restore'))
                            ->color('success')
                            ->icon('heroicon-o-arrow-uturn-left')
                            ->requiresConfirmation()
                            ->visible(fn (PolicyVersion $record) => $record->trashed())
                            ->action(function (PolicyVersion $record, AuditLogger $auditLogger) {
                                $user = auth()->user();
                                $tenant = $record->tenant;

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

                                $record->restore();

                                if ($record->tenant) {
                                    $auditLogger->log(
                                        tenant: $record->tenant,
                                        action: 'policy_version.restored',
                                        resourceType: 'policy_version',
                                        resourceId: (string) $record->id,
                                        status: 'success',
                                        context: ['metadata' => ['policy_id' => $record->policy_id, 'version' => $record->version_number]]
                                    );
                                }

                                Notification::make()
                                    ->title(static::text('versions.restored_title'))
                                    ->success()
                                    ->send();
                            });

                        UiEnforcement::forAction($action)
                            ->preserveVisibility()
                            ->requireCapability(Capabilities::TENANT_MANAGE)
                            ->tooltip(static::text('versions.manage_permission_tooltip'))
                            ->apply();

                        return $action;
                    })(),
                ])
                    ->label(static::text('common.more'))
                    ->icon('heroicon-o-ellipsis-vertical')
                    ->color('gray'),
            ])
            ->bulkActions([
                BulkActionGroup::make([
                    $bulkPruneVersions,
                    $bulkRestoreVersions,
                    $bulkForceDeleteVersions,
                ])->label(static::text('common.more')),
            ])
            ->emptyStateHeading(static::text('versions.empty_state_heading'))
            ->emptyStateDescription(static::text('versions.empty_state_description'))
            ->emptyStateIcon('heroicon-o-clock')
            ->emptyStateActions([
                Actions\Action::make('open_backup_sets')
                    ->label(static::text('versions.open_backup_sets'))
                    ->url(fn (): string => BackupSetResource::getUrl('index', tenant: static::resolveTenantContextForCurrentPanel()))
                    ->color('gray'),
            ]);
    }

    public static function getEloquentQuery(): Builder
    {
        $tenant = static::resolveTenantContextForCurrentPanelOrFail();
        $user = auth()->user();

        $resolver = app(CapabilityResolver::class);
        $canSeeBaselinePurposeEvidence = $user instanceof User
            && (
                $resolver->can($user, $tenant, Capabilities::TENANT_SYNC)
                || $resolver->can($user, $tenant, Capabilities::TENANT_FINDINGS_VIEW)
            );

        return static::getTenantOwnedEloquentQuery()
            ->when(! $canSeeBaselinePurposeEvidence, function (Builder $query): Builder {
                return $query->where(function (Builder $query): void {
                    $query
                        ->whereNull('capture_purpose')
                        ->orWhereNotIn('capture_purpose', [
                            PolicyVersionCapturePurpose::BaselineCapture->value,
                            PolicyVersionCapturePurpose::BaselineCompare->value,
                        ]);
                });
            })
            ->with('policy');
    }

    public static function resolveScopedRecordOrFail(int|string $key): \Illuminate\Database\Eloquent\Model
    {
        $tenant = static::resolveTenantContextForCurrentPanelOrFail();
        $user = auth()->user();

        $resolver = app(CapabilityResolver::class);
        $canSeeBaselinePurposeEvidence = $user instanceof User
            && (
                $resolver->can($user, $tenant, Capabilities::TENANT_SYNC)
                || $resolver->can($user, $tenant, Capabilities::TENANT_FINDINGS_VIEW)
            );

        return static::resolveTenantOwnedRecordOrFail(
            $key,
            parent::getEloquentQuery()
                ->withTrashed()
                ->when(! $canSeeBaselinePurposeEvidence, function (Builder $query): Builder {
                    return $query->where(function (Builder $query): void {
                        $query
                            ->whereNull('capture_purpose')
                            ->orWhereNotIn('capture_purpose', [
                                PolicyVersionCapturePurpose::BaselineCapture->value,
                                PolicyVersionCapturePurpose::BaselineCompare->value,
                            ]);
                    });
                })
                ->with('policy'),
        );
    }

    /**
     * @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(PolicyVersion $record): array
    {
        return app(RelatedNavigationResolver::class)
            ->detailEntries(CrossResourceNavigationMatrix::SOURCE_POLICY_VERSION, $record);
    }

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

    private static function policyVersionQualitySummary(PolicyVersion $record): \App\Support\BackupQuality\BackupQualitySummary
    {
        return app(BackupQualityResolver::class)->forPolicyVersion($record);
    }

    private static function policyVersionAssignmentQualityLabel(PolicyVersion $record): string
    {
        $summary = static::policyVersionQualitySummary($record);

        return match (true) {
            $summary->hasAssignmentIssues && $summary->hasOrphanedAssignments => static::text('versions.assignment_fetch_failed_orphaned'),
            $summary->hasAssignmentIssues => static::text('versions.assignment_fetch_failed'),
            $summary->hasOrphanedAssignments => static::text('versions.assignment_orphaned'),
            default => static::text('versions.assignment_no_issues'),
        };
    }

    private static function primaryRelatedEntry(PolicyVersion $record): ?RelatedContextEntry
    {
        return app(RelatedNavigationResolver::class)
            ->primaryListAction(CrossResourceNavigationMatrix::SOURCE_POLICY_VERSION, $record);
    }

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

    private static function resolvedDisplayName(PolicyVersion $record): string
    {
        $snapshot = is_array($record->snapshot) ? $record->snapshot : [];
        $displayName = $snapshot['displayName']
            ?? $snapshot['name']
            ?? $record->policy?->display_name
            ?? null;

        if (is_string($displayName) && $displayName !== '') {
            return $displayName;
        }

        return static::text('versions.fallback_display_name', ['version' => (int) $record->version_number]);
    }

    private static function text(string $key, array $replace = []): string
    {
        return __('localization.policy.'.$key, $replace);
    }
}
