<?php

declare(strict_types=1);

namespace App\Support\Navigation;

use Illuminate\Http\Request;

final class WorkspaceHubRegistry
{
    /**
     * @var list<string>
     */
    private const FORBIDDEN_QUERY_KEYS = [
        'tenant',
        'tenant_id',
        'managed_environment_id',
        'environment_id',
        'environment',
        'tenant_scope',
        'tableFilters',
    ];

    /**
     * @var list<string>
     */
    private const ENVIRONMENT_FILTER_KEYS = [
        'tenant',
        'tenant_id',
        'managed_environment_id',
        'environment_id',
        'environment',
        'tenant_scope',
    ];

    /**
     * @var list<string>
     */
    private const ENVIRONMENT_FILTER_QUERY_KEYS = [
        'environment_id',
    ];

    /**
     * @var array<string, array{label: string, path: string, pattern: string}>
     */
    private const HUBS = [
        'workspace_home' => [
            'label' => 'Workspace Overview',
            'path' => '/admin',
            'pattern' => '#^/admin/?$#',
        ],
        'workspace_overview' => [
            'label' => 'Workspace Overview',
            'path' => '/admin/workspaces/{workspace}/overview',
            'pattern' => '#^/admin/workspaces/[^/]+/overview/?$#',
        ],
        'operations' => [
            'label' => 'Operations',
            'path' => '/admin/workspaces/{workspace}/operations',
            'pattern' => '#^/admin/workspaces/[^/]+/operations/?$#',
        ],
        'provider_connections' => [
            'label' => 'Provider Connections',
            'path' => '/admin/provider-connections',
            'pattern' => '#^/admin/provider-connections(?:/.*)?$#',
        ],
        'finding_exceptions_queue' => [
            'label' => 'Finding Exceptions Queue',
            'path' => '/admin/finding-exceptions/queue',
            'pattern' => '#^/admin/finding-exceptions/queue/?$#',
        ],
        'evidence_overview' => [
            'label' => 'Evidence Overview',
            'path' => '/admin/evidence/overview',
            'pattern' => '#^/admin/evidence/overview/?$#',
        ],
        'review_register' => [
            'label' => 'Review Register',
            'path' => '/admin/reviews',
            'pattern' => '#^/admin/reviews/?$#',
        ],
        'customer_review_workspace' => [
            'label' => 'Customer Review Workspace',
            'path' => '/admin/reviews/workspace',
            'pattern' => '#^/admin/reviews/workspace/?$#',
        ],
        'governance_inbox' => [
            'label' => 'Governance Inbox',
            'path' => '/admin/governance/inbox',
            'pattern' => '#^/admin/governance/inbox/?$#',
        ],
        'decision_register' => [
            'label' => 'Decision Register',
            'path' => '/admin/governance/decisions',
            'pattern' => '#^/admin/governance/decisions/?$#',
        ],
        'audit_log' => [
            'label' => 'Audit Log',
            'path' => '/admin/audit-log',
            'pattern' => '#^/admin/audit-log/?$#',
        ],
        'alerts' => [
            'label' => 'Alerts',
            'path' => '/admin/alerts',
            'pattern' => '#^/admin/alerts/?$#',
        ],
        'alert_deliveries' => [
            'label' => 'Alert Deliveries',
            'path' => '/admin/alerts/alert-deliveries',
            'pattern' => '#^/admin/alerts/alert-deliveries(?:/.*)?$#',
        ],
        'alert_rules' => [
            'label' => 'Alert Rules',
            'path' => '/admin/alerts/alert-rules',
            'pattern' => '#^/admin/alerts/alert-rules(?:/.*)?$#',
        ],
        'alert_destinations' => [
            'label' => 'Alert Destinations',
            'path' => '/admin/alerts/alert-destinations',
            'pattern' => '#^/admin/alerts/alert-destinations(?:/.*)?$#',
        ],
        'workspace_settings' => [
            'label' => 'Workspace Settings',
            'path' => '/admin/settings/workspace',
            'pattern' => '#^/admin/settings/workspace/?$#',
        ],
        'manage_workspaces' => [
            'label' => 'Manage Workspaces',
            'path' => '/admin/workspaces',
            'pattern' => '#^/admin/workspaces/?$#',
        ],
        'managed_environments_landing' => [
            'label' => 'Managed Environments Landing',
            'path' => '/admin/workspaces/{workspace}/environments',
            'pattern' => '#^/admin/workspaces/[^/]+/environments/?$#',
        ],
    ];

    /**
     * @var array<string, array{label: string, path: string, pattern: string}>
     */
    private const EXCLUSIONS = [
        'environment_dashboard' => [
            'label' => 'Environment Dashboard',
            'path' => '/admin/workspaces/{workspace}/environments/{environment}',
            'pattern' => '#^/admin/workspaces/[^/]+/environments/[^/]+(?:/.*)?$#',
        ],
        'stored_reports_environment_routes' => [
            'label' => 'Stored Reports environment routes',
            'path' => '/admin/workspaces/{workspace}/environments/{environment}/stored-reports',
            'pattern' => '#^/admin/workspaces/[^/]+/environments/[^/]+/stored-reports(?:/.*)?$#',
        ],
        'support_request_action_surface' => [
            'label' => 'Support Request action surface',
            'path' => 'modal/action-only',
            'pattern' => '#^$#',
        ],
    ];

    /**
     * @return array<string, array{label: string, path: string, pattern: string}>
     */
    public static function entries(): array
    {
        return self::HUBS;
    }

    /**
     * @return array<string, array{label: string, path: string, pattern: string}>
     */
    public static function exclusions(): array
    {
        return self::EXCLUSIONS;
    }

    /**
     * @return list<string>
     */
    public static function forbiddenQueryKeys(): array
    {
        return self::FORBIDDEN_QUERY_KEYS;
    }

    /**
     * @return list<string>
     */
    public static function environmentLikeFilterKeys(): array
    {
        return self::ENVIRONMENT_FILTER_KEYS;
    }

    public static function isWorkspaceHubPath(string $path): bool
    {
        $normalizedPath = self::normalizePath($path);

        foreach (self::HUBS as $hub) {
            if (preg_match($hub['pattern'], $normalizedPath) === 1) {
                return true;
            }
        }

        return false;
    }

    public static function isExplicitlyExcludedPath(string $path): bool
    {
        $normalizedPath = self::normalizePath($path);

        foreach (self::EXCLUSIONS as $exclusion) {
            if (preg_match($exclusion['pattern'], $normalizedPath) === 1) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param  array<string, mixed>  $query
     * @return array<string, mixed>
     */
    public static function cleanQuery(array $query): array
    {
        foreach (self::FORBIDDEN_QUERY_KEYS as $key) {
            unset($query[$key]);
        }

        return $query;
    }

    /**
     * @param  array<string, mixed>  $parameters
     * @return array<string, mixed>
     */
    public static function cleanParameters(array $parameters): array
    {
        return self::cleanQuery($parameters);
    }

    public static function cleanUrl(string $url): string
    {
        if (! str_contains($url, '?')) {
            return $url;
        }

        $parts = parse_url($url);

        if (! is_array($parts)) {
            return $url;
        }

        $query = [];
        parse_str((string) ($parts['query'] ?? ''), $query);

        $parts['query'] = http_build_query(self::cleanQuery($query), '', '&', PHP_QUERY_RFC3986);

        return self::buildUrl($parts);
    }

    public static function hasForbiddenQuery(string $url): bool
    {
        $parts = parse_url($url);

        if (! is_array($parts) || ! isset($parts['query'])) {
            return false;
        }

        $query = [];
        parse_str((string) $parts['query'], $query);

        foreach (self::FORBIDDEN_QUERY_KEYS as $key) {
            if (array_key_exists($key, $query)) {
                return true;
            }
        }

        return false;
    }

    public static function isCleanWorkspaceHubEntry(?Request $request = null): bool
    {
        $request ??= request();

        return self::isWorkspaceHubPath('/'.ltrim((string) $request->path(), '/'))
            && ! self::requestHasEnvironmentFilterQuery($request);
    }

    public static function requestHasEnvironmentFilterQuery(?Request $request = null): bool
    {
        $request ??= request();

        foreach (self::ENVIRONMENT_FILTER_QUERY_KEYS as $key) {
            if ($request->query->has($key) && filled($request->query($key))) {
                return true;
            }
        }

        return false;
    }

    private static function normalizePath(string $path): string
    {
        $parsedPath = parse_url($path, PHP_URL_PATH);
        $path = is_string($parsedPath) && $parsedPath !== '' ? $parsedPath : $path;

        return '/'.trim($path, '/');
    }

    /**
     * @param  array<string, mixed>  $parts
     */
    private static function buildUrl(array $parts): string
    {
        $url = '';

        if (isset($parts['scheme'])) {
            $url .= $parts['scheme'].'://';
        }

        if (isset($parts['user'])) {
            $url .= $parts['user'];

            if (isset($parts['pass'])) {
                $url .= ':'.$parts['pass'];
            }

            $url .= '@';
        }

        if (isset($parts['host'])) {
            $url .= $parts['host'];
        }

        if (isset($parts['port'])) {
            $url .= ':'.$parts['port'];
        }

        $url .= $parts['path'] ?? '';

        if (($parts['query'] ?? '') !== '') {
            $url .= '?'.$parts['query'];
        }

        if (isset($parts['fragment'])) {
            $url .= '#'.$parts['fragment'];
        }

        return $url;
    }
}
