<?php

declare(strict_types=1);

namespace App\Support\Workspaces;

use App\Filament\Pages\ChooseTenant;
use App\Filament\Pages\ChooseWorkspace;
use App\Filament\Pages\TenantDashboard;
use App\Models\Tenant;
use App\Models\User;
use App\Models\Workspace;
use App\Services\Tenants\TenantOperabilityService;

/**
 * Resolves the explicit post-selection destination after a workspace is set.
 *
 * Tenant-count branching stays available for chooser-driven flows:
 *  - 0 tenants  → Managed Tenants index
 *  - 1 tenant   → Tenant Dashboard directly
 *  - >1 tenants → Choose Tenant page
 */
final class WorkspaceRedirectResolver
{
    public function __construct(
        private TenantOperabilityService $tenantOperabilityService,
    ) {}

    /**
     * Resolve the redirect URL for the given workspace + user.
     *
     * Returns a fully qualified URL string.
     */
    public function resolve(Workspace $workspace, User $user, ?string $intendedUrl = null): string
    {
        if (is_string($intendedUrl) && $this->intendedUrlMatchesWorkspace($intendedUrl, $workspace, $user)) {
            return $intendedUrl;
        }

        $selectableTenants = $this->tenantOperabilityService->filterSelectable($user->tenants()
            ->where('workspace_id', $workspace->getKey())
            ->orderBy('name')
            ->get());

        $tenantCount = (int) $selectableTenants->count();

        if ($tenantCount === 0) {
            return route('admin.workspace.managed-tenants.index', [
                'workspace' => $workspace->slug ?? $workspace->getKey(),
            ]);
        }

        if ($tenantCount === 1) {
            $tenant = $selectableTenants->first();

            if ($tenant !== null) {
                return TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant);
            }
        }

        return ChooseTenant::getUrl();
    }

    /**
     * Resolve the redirect URL using a workspace ID.
     *
     * Falls back to the chooser page if the workspace cannot be resolved.
     */
    public function resolveFromId(int $workspaceId, User $user): string
    {
        $workspace = Workspace::query()->whereKey($workspaceId)->first();

        if (! $workspace instanceof Workspace) {
            return ChooseWorkspace::getUrl();
        }

        return $this->resolve($workspace, $user);
    }

    private function intendedUrlMatchesWorkspace(string $intendedUrl, Workspace $workspace, User $user): bool
    {
        $path = '/'.ltrim((string) (parse_url($intendedUrl, PHP_URL_PATH) ?? ''), '/');

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

        if (preg_match('#^/admin/(?:t|tenants)/([^/]+)(?:/|$)#', $path, $matches) === 1) {
            return $this->tenantIdentifierMatchesWorkspace($matches[1], $workspace, $user);
        }

        parse_str((string) (parse_url($intendedUrl, PHP_URL_QUERY) ?? ''), $query);

        $tenantIdentifier = $query['tenant'] ?? $query['tenant_id'] ?? null;

        if ($tenantIdentifier !== null && ! $this->tenantIdentifierMatchesWorkspace((string) $tenantIdentifier, $workspace, $user)) {
            return false;
        }

        return true;
    }

    private function tenantIdentifierMatchesWorkspace(string $identifier, Workspace $workspace, User $user): bool
    {
        $tenant = Tenant::query()
            ->withTrashed()
            ->where(static function ($query) use ($identifier): void {
                $query->where('external_id', $identifier);

                if (ctype_digit($identifier)) {
                    $query->orWhereKey((int) $identifier);
                }
            })
            ->first();

        return $tenant instanceof Tenant
            && (int) $tenant->workspace_id === (int) $workspace->getKey()
            && $user->canAccessTenant($tenant);
    }
}
