<?php

declare(strict_types=1);

namespace App\Filament\Resources\BaselineProfileResource\Pages;

use App\Filament\Resources\BaselineProfileResource;
use App\Models\BaselineProfile;
use App\Models\BaselineTenantAssignment;
use App\Models\Tenant;
use App\Models\User;
use App\Models\Workspace;
use App\Services\Auth\CapabilityResolver;
use App\Services\Baselines\BaselineCaptureService;
use App\Services\Baselines\BaselineCompareService;
use App\Support\Auth\Capabilities;
use App\Support\Baselines\BaselineCaptureMode;
use App\Support\Baselines\BaselineReasonCodes;
use App\Support\Navigation\CrossResourceNavigationMatrix;
use App\Support\Navigation\RelatedContextEntry;
use App\Support\Navigation\RelatedNavigationResolver;
use App\Support\OperationRunLinks;
use App\Support\OpsUx\OperationUxPresenter;
use App\Support\OpsUx\OpsUxBrowserEvents;
use App\Support\Rbac\WorkspaceUiEnforcement;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Actions\Action;
use Filament\Actions\EditAction;
use Filament\Forms\Components\Select;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\ViewRecord;

class ViewBaselineProfile extends ViewRecord
{
    protected static string $resource = BaselineProfileResource::class;

    protected function getHeaderActions(): array
    {
        return [
            Action::make('view_active_snapshot')
                ->label(fn (): string => $this->activeSnapshotEntry()?->actionLabel ?? 'View snapshot')
                ->url(fn (): ?string => $this->activeSnapshotEntry()?->targetUrl)
                ->hidden(fn (): bool => ! ($this->activeSnapshotEntry()?->isAvailable() ?? false))
                ->color('gray'),
            $this->captureAction(),
            $this->compareNowAction(),
            EditAction::make()
                ->visible(fn (): bool => $this->hasManageCapability()),
        ];
    }

    private function activeSnapshotEntry(): ?RelatedContextEntry
    {
        return app(RelatedNavigationResolver::class)
            ->headerEntries(CrossResourceNavigationMatrix::SOURCE_BASELINE_PROFILE, $this->getRecord())[0] ?? null;
    }

    private function captureAction(): Action
    {
        /** @var BaselineProfile $profile */
        $profile = $this->getRecord();

        $captureMode = $profile->capture_mode instanceof BaselineCaptureMode
            ? $profile->capture_mode
            : BaselineCaptureMode::Opportunistic;

        $label = $captureMode === BaselineCaptureMode::FullContent
            ? 'Capture baseline (full content)'
            : 'Capture baseline';

        $modalDescription = $captureMode === BaselineCaptureMode::FullContent
            ? 'Select the source tenant. This will capture content evidence on demand (redacted) and may take longer depending on scope.'
            : 'Select the source tenant whose current inventory will be captured as the baseline snapshot.';

        $action = Action::make('capture')
            ->label($label)
            ->icon('heroicon-o-camera')
            ->color('primary')
            ->requiresConfirmation()
            ->modalHeading($label)
            ->modalDescription($modalDescription)
            ->form([
                Select::make('source_tenant_id')
                    ->label('Source Tenant')
                    ->options(fn (): array => $this->getWorkspaceTenantOptions())
                    ->required()
                    ->searchable(),
            ])
            ->action(function (array $data): void {
                $user = auth()->user();

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

                /** @var BaselineProfile $profile */
                $profile = $this->getRecord();
                $sourceTenant = Tenant::query()->find((int) $data['source_tenant_id']);

                if (! $sourceTenant instanceof Tenant) {
                    Notification::make()
                        ->title('Source tenant not found')
                        ->danger()
                        ->send();

                    return;
                }

                $service = app(BaselineCaptureService::class);
                $result = $service->startCapture($profile, $sourceTenant, $user);

                if (! $result['ok']) {
                    $reasonCode = is_string($result['reason_code'] ?? null) ? (string) $result['reason_code'] : 'unknown';

                    $message = match ($reasonCode) {
                        BaselineReasonCodes::CAPTURE_ROLLOUT_DISABLED => 'Full-content baseline capture is currently disabled for controlled rollout.',
                        BaselineReasonCodes::CAPTURE_PROFILE_NOT_ACTIVE => 'This baseline profile is not active.',
                        BaselineReasonCodes::CAPTURE_MISSING_SOURCE_TENANT => 'The selected tenant is not available for this baseline profile.',
                        default => 'Reason: '.str_replace('.', ' ', $reasonCode),
                    };

                    Notification::make()
                        ->title('Cannot start capture')
                        ->body($message)
                        ->danger()
                        ->send();

                    return;
                }

                $run = $result['run'] ?? null;

                if (! $run instanceof \App\Models\OperationRun) {
                    Notification::make()
                        ->title('Cannot start capture')
                        ->body('Reason: missing operation run')
                        ->danger()
                        ->send();

                    return;
                }

                $viewAction = Action::make('view_run')
                    ->label('View run')
                    ->url(OperationRunLinks::view($run, $sourceTenant));

                if (! $run->wasRecentlyCreated && in_array((string) $run->status, ['queued', 'running'], true)) {
                    OpsUxBrowserEvents::dispatchRunEnqueued($this);

                    OperationUxPresenter::alreadyQueuedToast((string) $run->type)
                        ->actions([$viewAction])
                        ->send();

                    return;
                }

                OpsUxBrowserEvents::dispatchRunEnqueued($this);

                OperationUxPresenter::queuedToast((string) $run->type)
                    ->actions([$viewAction])
                    ->send();
            });

        return WorkspaceUiEnforcement::forTableAction($action, fn (): ?Workspace => Workspace::query()
            ->whereKey((int) $this->getRecord()->workspace_id)
            ->first())
            ->requireCapability(Capabilities::WORKSPACE_BASELINES_MANAGE)
            ->apply();
    }

    private function compareNowAction(): Action
    {
        /** @var BaselineProfile $profile */
        $profile = $this->getRecord();

        $captureMode = $profile->capture_mode instanceof BaselineCaptureMode
            ? $profile->capture_mode
            : BaselineCaptureMode::Opportunistic;

        $label = $captureMode === BaselineCaptureMode::FullContent
            ? 'Compare now (full content)'
            : 'Compare now';

        $modalDescription = $captureMode === BaselineCaptureMode::FullContent
            ? 'Select the target tenant. This will refresh content evidence on demand (redacted) before comparing.'
            : 'Select the target tenant to compare its current inventory against the active baseline snapshot.';

        return Action::make('compareNow')
            ->label($label)
            ->icon('heroicon-o-play')
            ->requiresConfirmation()
            ->modalHeading($label)
            ->modalDescription($modalDescription)
            ->form([
                Select::make('target_tenant_id')
                    ->label('Target Tenant')
                    ->options(fn (): array => $this->getEligibleCompareTenantOptions())
                    ->required()
                    ->searchable(),
            ])
            ->disabled(fn (): bool => $this->getEligibleCompareTenantOptions() === [])
            ->action(function (array $data): void {
                $user = auth()->user();

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

                /** @var BaselineProfile $profile */
                $profile = $this->getRecord();

                $targetTenant = Tenant::query()->find((int) $data['target_tenant_id']);

                if (! $targetTenant instanceof Tenant || (int) $targetTenant->workspace_id !== (int) $profile->workspace_id) {
                    Notification::make()
                        ->title('Target tenant not found')
                        ->danger()
                        ->send();

                    return;
                }

                $assignment = BaselineTenantAssignment::query()
                    ->where('workspace_id', (int) $profile->workspace_id)
                    ->where('tenant_id', (int) $targetTenant->getKey())
                    ->where('baseline_profile_id', (int) $profile->getKey())
                    ->first();

                if (! $assignment instanceof BaselineTenantAssignment) {
                    Notification::make()
                        ->title('Tenant not assigned')
                        ->body('This tenant is not assigned to this baseline profile.')
                        ->warning()
                        ->send();

                    return;
                }

                $resolver = app(CapabilityResolver::class);

                if (! $resolver->can($user, $targetTenant, Capabilities::TENANT_SYNC)) {
                    Notification::make()
                        ->title('Permission denied')
                        ->danger()
                        ->send();

                    return;
                }

                $service = app(BaselineCompareService::class);
                $result = $service->startCompare($targetTenant, $user);

                if (! ($result['ok'] ?? false)) {
                    $reasonCode = is_string($result['reason_code'] ?? null) ? (string) $result['reason_code'] : 'unknown';

                    $message = match ($reasonCode) {
                        BaselineReasonCodes::COMPARE_ROLLOUT_DISABLED => 'Full-content baseline compare is currently disabled for controlled rollout.',
                        BaselineReasonCodes::COMPARE_PROFILE_NOT_ACTIVE => 'This baseline profile is not active.',
                        BaselineReasonCodes::COMPARE_NO_ACTIVE_SNAPSHOT => 'This baseline profile has no active snapshot.',
                        default => 'Reason: '.str_replace('.', ' ', $reasonCode),
                    };

                    Notification::make()
                        ->title('Cannot start comparison')
                        ->body($message)
                        ->danger()
                        ->send();

                    return;
                }

                $run = $result['run'] ?? null;

                if (! $run instanceof \App\Models\OperationRun) {
                    Notification::make()
                        ->title('Cannot start comparison')
                        ->body('Reason: missing operation run')
                        ->danger()
                        ->send();

                    return;
                }

                $viewAction = Action::make('view_run')
                    ->label('View run')
                    ->url(OperationRunLinks::view($run, $targetTenant));

                if (! $run->wasRecentlyCreated && in_array((string) $run->status, ['queued', 'running'], true)) {
                    OpsUxBrowserEvents::dispatchRunEnqueued($this);

                    OperationUxPresenter::alreadyQueuedToast((string) $run->type)
                        ->actions([$viewAction])
                        ->send();

                    return;
                }

                OpsUxBrowserEvents::dispatchRunEnqueued($this);

                OperationUxPresenter::queuedToast((string) $run->type)
                    ->actions([$viewAction])
                    ->send();
            });
    }

    /**
     * @return array<int, string>
     */
    private function getWorkspaceTenantOptions(): array
    {
        $workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());

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

        return Tenant::query()
            ->where('workspace_id', $workspaceId)
            ->orderBy('name')
            ->pluck('name', 'id')
            ->all();
    }

    /**
     * @return array<int, string>
     */
    private function getEligibleCompareTenantOptions(): array
    {
        $user = auth()->user();

        if (! $user instanceof User) {
            return [];
        }

        /** @var BaselineProfile $profile */
        $profile = $this->getRecord();

        $tenantIds = BaselineTenantAssignment::query()
            ->where('workspace_id', (int) $profile->workspace_id)
            ->where('baseline_profile_id', (int) $profile->getKey())
            ->pluck('tenant_id')
            ->all();

        if ($tenantIds === []) {
            return [];
        }

        $resolver = app(CapabilityResolver::class);

        $options = [];

        $tenants = Tenant::query()
            ->where('workspace_id', (int) $profile->workspace_id)
            ->whereIn('id', $tenantIds)
            ->orderBy('name')
            ->get(['id', 'name']);

        foreach ($tenants as $tenant) {
            if (! $tenant instanceof Tenant) {
                continue;
            }

            if (! $resolver->can($user, $tenant, Capabilities::TENANT_SYNC)) {
                continue;
            }

            $options[(int) $tenant->getKey()] = (string) $tenant->name;
        }

        return $options;
    }

    private function hasManageCapability(): bool
    {
        $user = auth()->user();

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

        $workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());

        if ($workspaceId === null) {
            return false;
        }

        $workspace = Workspace::query()->whereKey($workspaceId)->first();

        if (! $workspace instanceof Workspace) {
            return false;
        }

        $resolver = app(\App\Services\Auth\WorkspaceCapabilityResolver::class);

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