<?php

namespace App\Filament\Resources\InventoryItemResource\Pages;

use App\Filament\Concerns\ResolvesPanelTenantContext;
use App\Filament\Resources\InventoryItemResource;
use App\Filament\Widgets\Inventory\InventoryKpiHeader;
use App\Jobs\RunInventorySyncJob;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Services\Intune\AuditLogger;
use App\Services\Inventory\InventorySyncService;
use App\Services\OperationRunService;
use App\Support\Auth\Capabilities;
use App\Support\Filament\CanonicalAdminEnvironmentFilterState;
use App\Support\Inventory\InventoryPolicyTypeMeta;
use App\Support\OperationRunLinks;
use App\Support\OperationRunType;
use App\Support\OpsUx\OperationUxPresenter;
use App\Support\OpsUx\OpsUxBrowserEvents;
use App\Support\Rbac\UiEnforcement;
use App\Support\Rbac\UiTooltips;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Actions\Action;
use Filament\Actions\Action as HintAction;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Toggle;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\ListRecords;
use Filament\Support\Enums\Size;
use Filament\Support\Enums\Width;

class ListInventoryItems extends ListRecords
{
    use ResolvesPanelTenantContext;

    protected static string $resource = InventoryItemResource::class;

    protected Width|string|null $maxContentWidth = Width::Full;

    public function mount(): void
    {
        app(CanonicalAdminEnvironmentFilterState::class)->sync(
            $this->getTableFiltersSessionKey(),
            request: request(),
            environmentFilterName: null,
        );

        $tenant = static::resolveTenantContextForCurrentPanel();

        if ($tenant instanceof ManagedEnvironment) {
            app(WorkspaceContext::class)->rememberEnvironmentContext($tenant, request());
        }

        parent::mount();
    }

    protected function getHeaderWidgets(): array
    {
        return [
            InventoryKpiHeader::class,
        ];
    }

    protected function getHeaderActions(): array
    {
        return [
            UiEnforcement::forAction(
                Action::make('run_inventory_sync')
                    ->label('Run Inventory Sync')
                    ->icon('heroicon-o-arrow-path')
                    ->color('primary')
                    ->form([
                        Select::make('policy_types')
                            ->label('Policy types')
                            ->multiple()
                            ->searchable()
                            ->preload()
                            ->native(false)
                            ->hintActions([
                                fn (Select $component): HintAction => HintAction::make('select_all_policy_types')
                                    ->label('Select all')
                                    ->link()
                                    ->size(Size::Small)
                                    ->action(function (InventorySyncService $inventorySyncService) use ($component): void {
                                        $component->state($inventorySyncService->defaultSelectionPayload()['policy_types']);
                                    }),
                                fn (Select $component): HintAction => HintAction::make('clear_policy_types')
                                    ->label('Clear')
                                    ->link()
                                    ->size(Size::Small)
                                    ->action(function () use ($component): void {
                                        $component->state([]);
                                    }),
                            ])
                            ->options(function (): array {
                                return collect(InventoryPolicyTypeMeta::supported())
                                    ->filter(fn (array $meta): bool => filled($meta['type'] ?? null))
                                    ->groupBy(fn (array $meta): string => (string) ($meta['category'] ?? 'Other'))
                                    ->mapWithKeys(function ($items, string $category): array {
                                        $options = collect($items)
                                            ->mapWithKeys(function (array $meta): array {
                                                $type = (string) $meta['type'];
                                                $label = (string) ($meta['label'] ?? $type);
                                                $platform = (string) ($meta['platform'] ?? 'all');

                                                return [$type => "{$label} • {$platform}"];
                                            })
                                            ->all();

                                        return [$category => $options];
                                    })
                                    ->all();
                            })
                            ->columnSpanFull(),
                        Toggle::make('include_foundations')
                            ->label('Include foundation types')
                            ->helperText('Include scope tags, assignment filters, notification templates, and Intune RBAC role definitions and assignments.')
                            ->default(true)
                            ->dehydrated()
                            ->rules(['boolean'])
                            ->columnSpanFull(),
                        Toggle::make('include_dependencies')
                            ->label('Include dependencies')
                            ->helperText('Include dependency extraction where supported.')
                            ->default(true)
                            ->dehydrated()
                            ->rules(['boolean'])
                            ->columnSpanFull(),
                        Hidden::make('managed_environment_id')
                            ->default(fn (): ?string => static::resolveTenantContextForCurrentPanel()?->getKey())
                            ->dehydrated(),
                    ])
                    ->visible(function (): bool {
                        $user = auth()->user();
                        if (! $user instanceof User) {
                            return false;
                        }

                        $tenant = static::resolveTenantContextForCurrentPanel();
                        if (! $tenant instanceof ManagedEnvironment) {
                            return false;
                        }

                        return $user->canAccessTenant($tenant);
                    })
                    ->action(function (array $data, self $livewire, InventorySyncService $inventorySyncService, AuditLogger $auditLogger): void {
                        $tenant = static::resolveTenantContextForCurrentPanel();
                        $user = auth()->user();

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

                        $requestedTenantId = $data['managed_environment_id'] ?? null;
                        if ($requestedTenantId !== null && (int) $requestedTenantId !== (int) $tenant->getKey()) {
                            Notification::make()
                                ->title('Not allowed')
                                ->danger()
                                ->send();

                            return;
                        }

                        $selectionPayload = $inventorySyncService->defaultSelectionPayload();
                        if (array_key_exists('policy_types', $data)) {
                            $selectionPayload['policy_types'] = $data['policy_types'];
                        }
                        if (array_key_exists('include_foundations', $data)) {
                            $selectionPayload['include_foundations'] = (bool) $data['include_foundations'];
                        }
                        if (array_key_exists('include_dependencies', $data)) {
                            $selectionPayload['include_dependencies'] = (bool) $data['include_dependencies'];
                        }
                        $computed = $inventorySyncService->normalizeAndHashSelection($selectionPayload);

                        /** @var OperationRunService $opService */
                        $opService = app(OperationRunService::class);
                        $opRun = $opService->ensureRunWithIdentity(
                            tenant: $tenant,
                            type: OperationRunType::InventorySync->value,
                            identityInputs: [
                                'selection_hash' => $computed['selection_hash'],
                            ],
                            context: array_merge($computed['selection'], [
                                'selection_hash' => $computed['selection_hash'],
                                'execution_authority_mode' => 'actor_bound',
                                'required_capability' => Capabilities::TENANT_INVENTORY_SYNC_RUN,
                                'target_scope' => [
                                    'entra_tenant_id' => $tenant->graphTenantId(),
                                ],
                            ]),
                            initiator: $user,
                        );

                        if (! $opRun->wasRecentlyCreated && in_array($opRun->status, ['queued', 'running'], true)) {
                            OperationUxPresenter::alreadyQueuedToast((string) $opRun->type)
                                ->actions([
                                    Action::make('view_run')
                                        ->label('Open operation')
                                        ->url(OperationRunLinks::view($opRun, $tenant)),
                                ])
                                ->send();

                            OpsUxBrowserEvents::dispatchRunEnqueued($livewire);

                            return;
                        }

                        $auditLogger->log(
                            tenant: $tenant,
                            action: 'inventory.sync.dispatched',
                            context: [
                                'metadata' => [
                                    'operation_run_id' => (int) $opRun->getKey(),
                                    'selection_hash' => $computed['selection_hash'],
                                ],
                            ],
                            actorId: $user->id,
                            actorEmail: $user->email,
                            actorName: $user->name,
                            resourceType: 'operation_run',
                            resourceId: (string) $opRun->getKey(),
                        );

                        $opService->dispatchOrFail($opRun, function () use ($tenant, $user, $opRun): void {
                            RunInventorySyncJob::dispatch(
                                tenantId: (int) $tenant->getKey(),
                                userId: (int) $user->getKey(),
                                operationRun: $opRun
                            );
                        });

                        OperationUxPresenter::queuedToast((string) $opRun->type)
                            ->actions([
                                Action::make('view_run')
                                    ->label('Open operation')
                                    ->url(OperationRunLinks::view($opRun, $tenant)),
                            ])
                            ->send();

                        OpsUxBrowserEvents::dispatchRunEnqueued($livewire);
                    })
            )
                ->preserveVisibility()
                ->requireCapability(Capabilities::TENANT_INVENTORY_SYNC_RUN)
                ->tooltip(UiTooltips::INSUFFICIENT_PERMISSION)
                ->apply(),
        ];
    }
}
