<?php

declare(strict_types=1);

namespace App\Filament\Pages\Operations;

use App\Filament\Resources\OperationRunResource;
use App\Models\OperationRun;
use App\Models\Tenant;
use App\Models\User;
use App\Services\Auth\CapabilityResolver;
use App\Services\Auth\WorkspaceCapabilityResolver;
use App\Services\Baselines\BaselineEvidenceCaptureResumeService;
use App\Support\Auth\Capabilities;
use App\Support\Navigation\CanonicalNavigationContext;
use App\Support\OperateHub\OperateHubShell;
use App\Support\OperationRunLinks;
use App\Support\OpsUx\OperationUxPresenter;
use App\Support\OpsUx\OpsUxBrowserEvents;
use App\Support\RedactionIntegrity;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Schemas\Components\EmbeddedSchema;
use Filament\Schemas\Schema;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Str;

class TenantlessOperationRunViewer extends Page
{
    use AuthorizesRequests;

    protected static bool $shouldRegisterNavigation = false;

    protected static bool $isDiscovered = false;

    protected static ?string $title = 'Operation run';

    protected string $view = 'filament.pages.operations.tenantless-operation-run-viewer';

    public OperationRun $run;

    /**
     * @var array<string, mixed>|null
     */
    public ?array $navigationContextPayload = null;

    public bool $opsUxIsTabHidden = false;

    /**
     * @return array<Action|ActionGroup>
     */
    protected function getHeaderActions(): array
    {
        $operateHubShell = app(OperateHubShell::class);
        $navigationContext = $this->navigationContext();

        $actions = [
            Action::make('operate_hub_scope_run_detail')
                ->label($operateHubShell->scopeLabel(request()))
                ->color('gray')
                ->disabled(),
        ];

        $activeTenant = $operateHubShell->activeEntitledTenant(request());

        if ($navigationContext?->backLinkLabel !== null && $navigationContext->backLinkUrl !== null) {
            $actions[] = Action::make('operate_hub_back_to_origin_run_detail')
                ->label($navigationContext->backLinkLabel)
                ->color('gray')
                ->url($navigationContext->backLinkUrl);
        } elseif ($activeTenant instanceof Tenant) {
            $actions[] = Action::make('operate_hub_back_to_tenant_run_detail')
                ->label('← Back to '.$activeTenant->name)
                ->color('gray')
                ->url(\App\Filament\Pages\TenantDashboard::getUrl(panel: 'tenant', tenant: $activeTenant));
        } else {
            $actions[] = Action::make('operate_hub_back_to_operations')
                ->label('Back to Operations')
                ->color('gray')
                ->url(fn (): string => route('admin.operations.index'));
        }

        if ($activeTenant instanceof Tenant) {
            $actions[] = Action::make('operate_hub_show_all_operations')
                ->label('Show all operations')
                ->color('gray')
                ->url(fn (): string => route('admin.operations.index'));
        }

        $actions[] = Action::make('refresh')
            ->label('Refresh')
            ->icon('heroicon-o-arrow-path')
            ->color('gray')
            ->url(fn (): string => isset($this->run)
                ? OperationRunLinks::tenantlessView($this->run, $navigationContext)
                : route('admin.operations.index'));

        if (! isset($this->run)) {
            return $actions;
        }

        $user = auth()->user();
        $tenant = $this->run->tenant;

        if ($tenant instanceof Tenant && (! $user instanceof User || ! app(CapabilityResolver::class)->isMember($user, $tenant))) {
            $tenant = null;
        }

        $related = OperationRunLinks::related($this->run, $tenant);

        $relatedActions = [];

        foreach ($related as $label => $url) {
            $relatedActions[] = Action::make(Str::slug((string) $label, '_'))
                ->label((string) $label)
                ->url((string) $url)
                ->openUrlInNewTab();
        }

        if ($relatedActions !== []) {
            $actions[] = ActionGroup::make($relatedActions)
                ->label('Open')
                ->icon('heroicon-o-arrow-top-right-on-square')
                ->color('gray');
        }

        $actions[] = $this->resumeCaptureAction();

        return $actions;
    }

    public function mount(OperationRun $run): void
    {
        $user = auth()->user();

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

        $this->authorize('view', $run);

        $this->run = $run->loadMissing(['workspace', 'tenant', 'user']);
        $this->navigationContextPayload = is_array(request()->query('nav')) ? request()->query('nav') : null;
    }

    public function infolist(Schema $schema): Schema
    {
        return OperationRunResource::infolist($schema);
    }

    public function defaultInfolist(Schema $schema): Schema
    {
        return $schema
            ->record($this->run)
            ->columns(2);
    }

    public function redactionIntegrityNote(): ?string
    {
        return isset($this->run) ? RedactionIntegrity::noteForRun($this->run) : null;
    }

    public function content(Schema $schema): Schema
    {
        return $schema->schema([
            EmbeddedSchema::make('infolist'),
        ]);
    }

    private function resumeCaptureAction(): Action
    {
        return Action::make('resumeCapture')
            ->label('Resume capture')
            ->icon('heroicon-o-forward')
            ->requiresConfirmation()
            ->modalHeading('Resume capture')
            ->modalDescription('This will start a follow-up operation to capture remaining baseline evidence for this scope.')
            ->visible(fn (): bool => $this->canResumeCapture())
            ->action(function (): void {
                $user = auth()->user();

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

                if (! isset($this->run)) {
                    Notification::make()
                        ->title('Run not loaded')
                        ->danger()
                        ->send();

                    return;
                }

                $service = app(BaselineEvidenceCaptureResumeService::class);
                $result = $service->resume($this->run, $user);

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

                    Notification::make()
                        ->title('Cannot resume capture')
                        ->body('Reason: '.str_replace('.', ' ', $reason))
                        ->danger()
                        ->send();

                    return;
                }

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

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

                    return;
                }

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

                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();
            });
    }

    private function navigationContext(): ?CanonicalNavigationContext
    {
        if (! is_array($this->navigationContextPayload)) {
            return CanonicalNavigationContext::fromRequest(request());
        }

        $request = request()->duplicate(query: ['nav' => $this->navigationContextPayload]);

        return CanonicalNavigationContext::fromRequest($request);
    }

    private function canResumeCapture(): bool
    {
        if (! isset($this->run)) {
            return false;
        }

        if ((string) $this->run->status !== 'completed') {
            return false;
        }

        if (! in_array((string) $this->run->type, ['baseline_capture', 'baseline_compare'], true)) {
            return false;
        }

        $context = is_array($this->run->context) ? $this->run->context : [];
        $tokenKey = (string) $this->run->type === 'baseline_capture'
            ? 'baseline_capture.resume_token'
            : 'baseline_compare.resume_token';
        $token = data_get($context, $tokenKey);

        if (! is_string($token) || trim($token) === '') {
            return false;
        }

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

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

        $workspace = $this->run->workspace;

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

        $resolver = app(WorkspaceCapabilityResolver::class);

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