<?php

namespace App\Filament\Resources\PolicyResource\RelationManagers;

use App\Filament\Concerns\ResolvesPanelTenantContext;
use App\Filament\Resources\PolicyVersionResource;
use App\Filament\Resources\RestoreRunResource;
use App\Models\Policy;
use App\Models\PolicyVersion;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Services\Auth\CapabilityResolver;
use App\Services\Intune\RestoreService;
use App\Support\Auth\Capabilities;
use App\Support\Badges\TagBadgeDomain;
use App\Support\Badges\TagBadgeRenderer;
use App\Support\Rbac\UiEnforcement;
use App\Support\Rbac\UiTooltips;
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 Filament\Actions;
use Filament\Forms;
use Filament\Notifications\Notification;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;

class VersionsRelationManager extends RelationManager
{
    use ResolvesPanelTenantContext;

    protected static string $relationship = 'versions';

    /**
     * @param  array<string, mixed>  $arguments
     * @param  array<string, mixed>  $context
     */
    public function mountAction(string $name, array $arguments = [], array $context = []): mixed
    {
        if (($context['table'] ?? false) === true && $name === 'restore_to_intune' && filled($context['recordKey'] ?? null)) {
            $this->resolveOwnerScopedVersionRecord($this->getOwnerRecord(), $context['recordKey']);
        }

        return parent::mountAction($name, $arguments, $context);
    }

    public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
    {
        return ActionSurfaceDeclaration::forRelationManager(ActionSurfaceProfile::RelationManager)
            ->exempt(ActionSurfaceSlot::ListHeader, 'Versions sub-list intentionally has no header actions.')
            ->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ClickableRow->value)
            ->exempt(ActionSurfaceSlot::ListRowMoreMenu, 'Clickable-row inspection stays primary while restore remains the only inline row shortcut.')
            ->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'Bulk actions are intentionally omitted for version restore safety.')
            ->exempt(ActionSurfaceSlot::ListEmptyState, 'No inline empty-state action is exposed in this embedded relation manager.');
    }

    public function table(Table $table): Table
    {
        $restoreToIntune = Actions\Action::make('restore_to_intune')
            ->label($this->text('relation.restore_to_microsoft_intune'))
            ->icon('heroicon-o-arrow-path-rounded-square')
            ->color('danger')
            ->requiresConfirmation()
            ->modalHeading(fn (PolicyVersion $record): string => $this->text('relation.restore_heading', ['version' => $record->version_number]))
            ->modalSubheading($this->text('relation.restore_subheading'))
            ->form([
                Forms\Components\Toggle::make('is_dry_run')
                    ->label($this->text('common.preview_only_dry_run'))
                    ->default(true),
            ])
            ->action(function (mixed $record, array $data, RestoreService $restoreService) {
                $record = $this->resolveOwnerScopedVersionRecord($this->getOwnerRecord(), $record);
                $tenant = static::resolveTenantContextForCurrentPanel();
                $user = auth()->user();

                if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
                    Notification::make()
                        ->title($this->text('relation.missing_context_title'))
                        ->danger()
                        ->send();

                    return;
                }

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

                    return;
                }

                try {
                    $run = $restoreService->executeFromPolicyVersion(
                        tenant: $tenant,
                        version: $record,
                        dryRun: (bool) ($data['is_dry_run'] ?? true),
                        actorEmail: $user->email,
                        actorName: $user->name,
                    );
                } catch (\Throwable $throwable) {
                    Notification::make()
                        ->title($this->text('relation.restore_run_failed_title'))
                        ->body($throwable->getMessage())
                        ->danger()
                        ->send();

                    return;
                }

                Notification::make()
                    ->title($this->text('relation.restore_run_started_title'))
                    ->success()
                    ->send();

                return redirect(RestoreRunResource::getUrl('view', ['record' => $run]));
            });

        UiEnforcement::forAction($restoreToIntune)
            ->requireCapability(Capabilities::TENANT_MANAGE)
            ->apply();

        $restoreToIntune
            ->disabled(function (PolicyVersion $record): bool {
                if (($record->metadata['source'] ?? null) === 'metadata_only') {
                    return true;
                }

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

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

                $resolver = app(CapabilityResolver::class);

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

                return ! $resolver->can($user, $tenant, Capabilities::TENANT_MANAGE);
            })
            ->tooltip(function (PolicyVersion $record): ?string {
                if (($record->metadata['source'] ?? null) === 'metadata_only') {
                    return $this->text('versions.metadata_only_tooltip');
                }

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

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

                $resolver = app(CapabilityResolver::class);

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

                if (! $resolver->can($user, $tenant, Capabilities::TENANT_MANAGE)) {
                    return UiTooltips::INSUFFICIENT_PERMISSION;
                }

                return null;
            });

        return $table
            ->columns([
                Tables\Columns\TextColumn::make('version_number')->label($this->text('common.version'))->sortable(),
                Tables\Columns\TextColumn::make('captured_at')->label($this->text('common.captured'))->dateTime()->sortable(),
                Tables\Columns\TextColumn::make('created_by')->label($this->text('common.actor')),
                Tables\Columns\TextColumn::make('policy_type')
                    ->label($this->text('common.type'))
                    ->badge()
                    ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::PolicyType))
                    ->color(TagBadgeRenderer::color(TagBadgeDomain::PolicyType))
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->defaultSort('version_number', 'desc')
            ->paginated(\App\Support\Filament\TablePaginationProfiles::relationManager())
            ->recordUrl(fn (PolicyVersion $record): string => PolicyVersionResource::getUrl('view', ['record' => $record]))
            ->filters([])
            ->headerActions([])
            ->actions([
                $restoreToIntune,
            ])
            ->bulkActions([])
            ->emptyStateHeading($this->text('relation.no_versions_captured'))
            ->emptyStateDescription($this->text('relation.no_versions_captured_description'));
    }

    private function resolveOwnerScopedVersionRecord(Policy $policy, mixed $record): PolicyVersion
    {
        $recordId = $record instanceof PolicyVersion
            ? (int) $record->getKey()
            : (is_numeric($record) ? (int) $record : 0);

        if ($recordId <= 0) {
            abort(404);
        }

        $resolvedRecord = $policy->versions()
            ->where('managed_environment_id', (int) $policy->managed_environment_id)
            ->whereKey($recordId)
            ->first();

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

        return $resolvedRecord;
    }

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