<?php

declare(strict_types=1);

namespace App\Support\OperateHub;

use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Models\Workspace;
use App\Services\Auth\CapabilityResolver;
use App\Services\Tenants\TenantOperabilityService;
use App\Support\ManagedEnvironmentLinks;
use App\Support\Navigation\AdminSurfaceScope;
use App\Support\Navigation\WorkspaceHubRegistry;
use App\Support\Tenants\TenantOperabilityQuestion;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Illuminate\Http\Request;

final class OperateHubShell
{
    private const string REQUEST_ATTRIBUTE = 'tenantpilot.resolved_shell_context';

    public function __construct(
        private WorkspaceContext $workspaceContext,
        private CapabilityResolver $capabilityResolver,
        private TenantOperabilityService $tenantOperabilityService,
    ) {}

    public function scopeLabel(?Request $request = null): string
    {
        $activeEnvironment = $this->activeEntitledTenant($request);

        if ($activeEnvironment instanceof ManagedEnvironment) {
            return __('localization.shell.environment_scope').': '.$activeEnvironment->name;
        }

        return __('localization.shell.all_environments');
    }

    /**
     * @return array{label: string, url: string}|null
     */
    public function returnAffordance(?Request $request = null): ?array
    {
        $activeEnvironment = $this->activeEntitledTenant($request);

        if ($activeEnvironment instanceof ManagedEnvironment) {
            return [
                'label' => 'Back to '.$activeEnvironment->name,
                'url' => ManagedEnvironmentLinks::viewUrl($activeEnvironment),
            ];
        }

        return null;
    }

    /**
     * @return array<Action>
     */
    public function headerActions(
        string $scopeActionName = 'operate_hub_scope',
        string $returnActionName = 'operate_hub_return',
        ?Request $request = null,
    ): array {
        $actions = [
            Action::make($scopeActionName)
                ->label($this->scopeLabel($request))
                ->color('gray')
                ->disabled(),
        ];

        $returnAffordance = $this->returnAffordance($request);

        if (is_array($returnAffordance)) {
            $actions[] = Action::make($returnActionName)
                ->label($returnAffordance['label'])
                ->icon('heroicon-o-arrow-left')
                ->color('gray')
                ->url($returnAffordance['url']);
        }

        return $actions;
    }

    public function activeEntitledTenant(?Request $request = null): ?ManagedEnvironment
    {
        return $this->resolvedContext($request)->tenant;
    }

    public function tenantOwnedPanelContext(?Request $request = null): ?ManagedEnvironment
    {
        return $this->activeEntitledTenant($request);
    }

    public function resolvedContext(?Request $request = null): ResolvedShellContext
    {
        $request ??= request();

        if ($request instanceof Request) {
            $cached = $request->attributes->get(self::REQUEST_ATTRIBUTE);

            if ($cached instanceof ResolvedShellContext) {
                return $cached;
            }
        }

        $resolved = $this->buildResolvedContext($request);

        if ($request instanceof Request) {
            $request->attributes->set(self::REQUEST_ATTRIBUTE, $resolved);
        }

        return $resolved;
    }

    private function buildResolvedContext(?Request $request = null): ResolvedShellContext
    {
        $pageCategory = $this->pageCategory($request);
        $routeTenantCandidate = $this->resolveRouteTenantCandidate($request, $pageCategory);
        $sessionWorkspace = $this->workspaceContext->currentWorkspace($request);
        $workspace = $this->resolveWorkspaceForPageCategory($routeTenantCandidate, $pageCategory, $request);

        $workspaceSource = match (true) {
            $workspace instanceof Workspace && $sessionWorkspace instanceof Workspace && $workspace->is($sessionWorkspace) => 'session_workspace',
            $workspace instanceof Workspace && $routeTenantCandidate instanceof ManagedEnvironment && (int) $routeTenantCandidate->workspace_id === (int) $workspace->getKey() => 'route',
            default => 'none',
        };

        if (! $workspace instanceof Workspace) {
            return new ResolvedShellContext(
                workspace: null,
                tenant: null,
                pageCategory: $pageCategory,
                state: 'missing_workspace',
                displayMode: 'recovery',
                recoveryAction: $pageCategory === AdminSurfaceScope::WorkspaceChooserException ? 'none' : 'redirect_choose_workspace',
                recoveryDestination: '/admin/choose-workspace',
                recoveryReason: 'missing_workspace',
            );
        }

        $routeTenant = $this->resolveValidatedRouteTenant($routeTenantCandidate, $workspace, $request, $pageCategory);

        if ($routeTenant['tenant'] instanceof ManagedEnvironment) {
            return new ResolvedShellContext(
                workspace: $workspace,
                tenant: $routeTenant['tenant'],
                pageCategory: $pageCategory,
                state: 'tenant_scoped',
                displayMode: 'tenant_scoped',
                workspaceSource: $workspaceSource,
                tenantSource: 'route',
            );
        }

        $recoveryReason = $routeTenant['reason'];

        if ($pageCategory === AdminSurfaceScope::EnvironmentBound && $recoveryReason !== null) {
            return new ResolvedShellContext(
                workspace: $workspace,
                tenant: null,
                pageCategory: $pageCategory,
                state: 'invalid_tenant',
                displayMode: 'recovery',
                workspaceSource: $workspaceSource,
                recoveryAction: 'abort_not_found',
                recoveryReason: $recoveryReason,
            );
        }

        if ($pageCategory->forcesEnvironmentlessShellContext()) {
            return new ResolvedShellContext(
                workspace: $workspace,
                tenant: null,
                pageCategory: $pageCategory,
                state: 'tenantless_workspace',
                displayMode: 'tenantless',
                workspaceSource: $workspaceSource,
                recoveryReason: $recoveryReason,
            );
        }

        $queryHintTenant = $this->resolveValidatedQueryHintTenant($request, $workspace, $pageCategory);

        if ($queryHintTenant['tenant'] instanceof ManagedEnvironment) {
            return new ResolvedShellContext(
                workspace: $workspace,
                tenant: $queryHintTenant['tenant'],
                pageCategory: $pageCategory,
                state: 'tenant_scoped',
                displayMode: 'tenant_scoped',
                workspaceSource: $workspaceSource,
                tenantSource: 'query_hint',
            );
        }

        $recoveryReason ??= $queryHintTenant['reason'];

        if ($this->requiresStrictQueryTenantHintResolution($request)) {
            return new ResolvedShellContext(
                workspace: $workspace,
                tenant: null,
                pageCategory: $pageCategory,
                state: 'invalid_tenant',
                displayMode: 'recovery',
                workspaceSource: $workspaceSource,
                recoveryAction: 'abort_not_found',
                recoveryReason: $recoveryReason ?? 'missing_tenant',
            );
        }

        $tenant = $this->resolveValidatedFilamentTenant($request, $pageCategory, $workspace);

        if ($tenant instanceof ManagedEnvironment) {
            return new ResolvedShellContext(
                workspace: $workspace,
                tenant: $tenant,
                pageCategory: $pageCategory,
                state: 'tenant_scoped',
                displayMode: 'tenant_scoped',
                workspaceSource: $workspaceSource,
                tenantSource: 'filament_tenant',
            );
        }

        if ($pageCategory->allowsRememberedEnvironmentRestore()) {
            $rememberedEnvironment = $this->workspaceContext->rememberedEnvironment($request);

            if ($rememberedEnvironment instanceof ManagedEnvironment) {
                return new ResolvedShellContext(
                    workspace: $workspace,
                    tenant: $rememberedEnvironment,
                    pageCategory: $pageCategory,
                    state: 'tenant_scoped',
                    displayMode: 'tenant_scoped',
                    workspaceSource: $workspaceSource,
                    tenantSource: 'remembered',
                );
            }
        }

        if ($pageCategory->requiresExplicitEnvironment()) {
            return new ResolvedShellContext(
                workspace: $workspace,
                tenant: null,
                pageCategory: $pageCategory,
                state: 'missing_tenant',
                displayMode: 'recovery',
                workspaceSource: $workspaceSource,
                recoveryAction: $pageCategory === AdminSurfaceScope::EnvironmentScopedEvidence
                    ? 'redirect_evidence_overview'
                    : 'abort_not_found',
                recoveryDestination: $pageCategory === AdminSurfaceScope::EnvironmentScopedEvidence
                    ? '/admin/evidence/overview'
                    : null,
                recoveryReason: $recoveryReason ?? 'missing_tenant',
            );
        }

        return new ResolvedShellContext(
            workspace: $workspace,
            tenant: null,
            pageCategory: $pageCategory,
            state: 'tenantless_workspace',
            displayMode: 'tenantless',
            workspaceSource: $workspaceSource,
            recoveryReason: $recoveryReason,
        );
    }

    private function resolveValidatedFilamentTenant(
        ?Request $request = null,
        ?AdminSurfaceScope $pageCategory = null,
        ?Workspace $workspace = null,
    ): ?ManagedEnvironment {
        $tenant = Filament::getTenant();

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

        $pageCategory ??= $this->pageCategory($request);
        $workspace ??= $this->resolveWorkspaceForPageCategory($tenant, $pageCategory, $request);

        if ($workspace instanceof Workspace && $this->tenantValidationReason($tenant, $workspace, $request, $pageCategory) === null) {
            return $tenant;
        }

        Filament::setTenant(null, true);

        return null;
    }

    private function resolveValidatedRouteTenant(
        ?ManagedEnvironment $tenant,
        Workspace $workspace,
        ?Request $request = null,
        ?AdminSurfaceScope $pageCategory = null,
    ): array {
        $pageCategory ??= $this->pageCategory($request);

        if (! $tenant instanceof ManagedEnvironment) {
            return ['tenant' => null, 'reason' => null];
        }

        $reason = $this->tenantValidationReason($tenant, $workspace, $request, $pageCategory);

        if ($reason !== null) {
            return ['tenant' => null, 'reason' => $reason];
        }

        return ['tenant' => $tenant, 'reason' => null];
    }

    private function resolveWorkspaceForPageCategory(
        ?ManagedEnvironment $tenant,
        AdminSurfaceScope $pageCategory,
        ?Request $request = null,
    ): ?Workspace {
        return match ($pageCategory) {
            AdminSurfaceScope::EnvironmentScopedEvidence => $this->workspaceContext->currentWorkspace($request),
            AdminSurfaceScope::EnvironmentBound => $this->workspaceContext->currentWorkspaceOrEnvironmentWorkspace($tenant, $request),
            default => $this->workspaceContext->currentWorkspaceOrEnvironmentWorkspace($tenant, $request),
        };
    }

    private function resolveValidatedQueryHintTenant(
        ?Request $request,
        Workspace $workspace,
        AdminSurfaceScope $pageCategory,
    ): array {
        if (! $pageCategory->allowsQueryEnvironmentHints()) {
            return ['tenant' => null, 'reason' => null];
        }

        $queryTenant = $this->resolveQueryTenantHint($request);

        if (! $queryTenant instanceof ManagedEnvironment) {
            return ['tenant' => null, 'reason' => null];
        }

        $reason = $this->tenantValidationReason($queryTenant, $workspace, $request, $pageCategory);

        if ($reason !== null) {
            return ['tenant' => null, 'reason' => $reason];
        }

        return ['tenant' => $queryTenant, 'reason' => null];
    }

    private function resolveRouteTenantCandidate(?Request $request = null, ?AdminSurfaceScope $pageCategory = null): ?ManagedEnvironment
    {
        $route = $request?->route();
        $pageCategory ??= $this->pageCategory($request);

        if ($route?->hasParameter('environment')) {
            return $this->resolveTenantIdentifier($route->parameter('environment'));
        }

        if ($route?->hasParameter('tenant')) {
            return $this->resolveTenantIdentifier($route->parameter('tenant'));
        }

        return null;
    }

    private function resolveQueryTenantHint(?Request $request = null): ?ManagedEnvironment
    {
        if ($request instanceof Request && WorkspaceHubRegistry::isWorkspaceHubPath('/'.ltrim((string) $request->path(), '/'))) {
            return null;
        }

        $queryTenant = $request?->query('tenant');

        if (filled($queryTenant)) {
            return $this->resolveTenantIdentifier($queryTenant);
        }

        $queryTenantId = $request?->query('managed_environment_id');

        if (filled($queryTenantId)) {
            return $this->resolveTenantIdentifier($queryTenantId);
        }

        return null;
    }

    private function hasExplicitQueryTenantHint(?Request $request = null): bool
    {
        if ($request instanceof Request && WorkspaceHubRegistry::isWorkspaceHubPath('/'.ltrim((string) $request->path(), '/'))) {
            return false;
        }

        return filled($request?->query('tenant')) || filled($request?->query('managed_environment_id'));
    }

    private function requiresStrictQueryTenantHintResolution(?Request $request = null): bool
    {
        if (! $this->hasExplicitQueryTenantHint($request)) {
            return false;
        }

        $path = '/'.ltrim((string) $request?->path(), '/');

        if (! str_starts_with($path, '/admin/')) {
            return false;
        }

        if (str_starts_with($path, '/admin/finding-exceptions/queue')) {
            return false;
        }

        return preg_match('#^/admin/(inventory|policies|policy-versions|backup-sets|backup-schedules|findings|finding-exceptions)(/|$)#', $path) === 1;
    }

    private function resolveTenantIdentifier(mixed $tenantIdentifier): ?ManagedEnvironment
    {
        if ($tenantIdentifier instanceof ManagedEnvironment) {
            return $tenantIdentifier;
        }

        $tenantIdentifier = trim((string) $tenantIdentifier);

        if ($tenantIdentifier === '') {
            return null;
        }

        $tenantKeyColumn = (new ManagedEnvironment)->getQualifiedKeyName();

        return ManagedEnvironment::query()
            ->withTrashed()
            ->where(static function ($query) use ($tenantIdentifier, $tenantKeyColumn): void {
                $query->where('slug', $tenantIdentifier);

                if (ctype_digit($tenantIdentifier)) {
                    $query->orWhere($tenantKeyColumn, (int) $tenantIdentifier);
                }
            })
            ->first();
    }

    private function tenantValidationReason(
        ManagedEnvironment $tenant,
        Workspace $workspace,
        ?Request $request = null,
        ?AdminSurfaceScope $pageCategory = null,
    ): ?string {
        $pageCategory ??= $this->pageCategory($request);

        if ((int) $tenant->workspace_id !== (int) $workspace->getKey()) {
            return 'mismatched_workspace';
        }

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

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

        if (! $this->capabilityResolver->isMember($user, $tenant)) {
            return 'not_member';
        }

        $question = $pageCategory === AdminSurfaceScope::EnvironmentBound
            ? TenantOperabilityQuestion::EnvironmentBoundViewability
            : TenantOperabilityQuestion::AdministrativeDiscoverability;

        $allowed = $this->tenantOperabilityService->outcomeFor(
            tenant: $tenant,
            question: $question,
            actor: $user,
            workspaceId: (int) $workspace->getKey(),
            lane: $pageCategory->lane(),
            selectedTenant: Filament::getTenant() instanceof ManagedEnvironment ? Filament::getTenant() : null,
        )->allowed;

        if ($allowed) {
            return null;
        }

        return $pageCategory === AdminSurfaceScope::EnvironmentBound
            ? 'inaccessible'
            : 'not_operable';
    }

    private function pageCategory(?Request $request = null): AdminSurfaceScope
    {
        return AdminSurfaceScope::fromRequest($request);
    }
}
