<?php
declare(strict_types=1);

namespace App\Core;

class DomainRouter
{
    private const AREA_PREFIXES = [
        'music' => '/music',
        'studio' => '/studyo',
        'zpanel' => '/zpanel',
    ];

    public static function area(string $host, string $uri, array $config): string
    {
        $host = self::cleanHost($host);
        $path = self::withoutBasePath(parse_url($uri, PHP_URL_PATH) ?: '/', $config);

        if (str_starts_with($path, '/api/')) {
            return 'api';
        }

        if (self::matchesAreaHost($host, $config['MUSIC_URL'] ?? '') || str_starts_with($host, 'music.')) {
            return 'music';
        }

        if (self::matchesAreaHost($host, $config['STUDIO_URL'] ?? '') || str_starts_with($host, 'studyo.')) {
            return 'studio';
        }

        if (self::matchesAreaHost($host, $config['ZPANEL_URL'] ?? '') || str_starts_with($host, 'zpanel.')) {
            return 'zpanel';
        }

        foreach (self::AREA_PREFIXES as $area => $prefix) {
            if ($path === $prefix || str_starts_with($path, $prefix . '/')) {
                return $area;
            }
        }

        return 'main';
    }

    public static function routePath(string $uri, string $area, array $config): string
    {
        $path = parse_url($uri, PHP_URL_PATH) ?: '/';
        $path = self::withoutBasePath($path, $config);

        if (isset(self::AREA_PREFIXES[$area])) {
            $prefix = self::AREA_PREFIXES[$area];

            if ($path === $prefix) {
                return '/';
            }

            if (str_starts_with($path, $prefix . '/')) {
                return substr($path, strlen($prefix)) ?: '/';
            }
        }

        return self::normalizePath($path);
    }

    public static function url(string $path, ?string $area, array $config): string
    {
        $path = self::normalizePath($path);

        if (self::isPublicPath($path)) {
            return rtrim((string) $config['APP_URL'], '/') . $path;
        }

        $area ??= self::inferAreaFromPath($path);
        $path = self::stripAreaPrefix($path, $area);

        if (!($config['SUBDOMAIN_MODE'] ?? false) && isset(self::AREA_PREFIXES[$area])) {
            $path = self::AREA_PREFIXES[$area] . ($path === '/' ? '' : $path);
            return rtrim((string) $config['APP_URL'], '/') . $path;
        }

        $base = match ($area) {
            'music' => $config['MUSIC_URL'] ?? $config['APP_URL'],
            'studio' => $config['STUDIO_URL'] ?? $config['APP_URL'],
            'zpanel' => $config['ZPANEL_URL'] ?? $config['APP_URL'],
            default => $config['APP_URL'],
        };

        return rtrim((string) $base, '/') . ($path === '/' ? '' : $path);
    }

    private static function withoutBasePath(string $path, array $config): string
    {
        $path = self::normalizePath($path);
        $basePath = parse_url((string) ($config['APP_URL'] ?? ''), PHP_URL_PATH) ?: '';
        $basePath = rtrim($basePath, '/');

        if ($basePath !== '' && ($path === $basePath || str_starts_with($path, $basePath . '/'))) {
            $path = substr($path, strlen($basePath)) ?: '/';
        }

        return self::normalizePath($path);
    }

    private static function cleanHost(string $host): string
    {
        $host = strtolower($host);
        return explode(':', $host)[0] ?? $host;
    }

    private static function matchesAreaHost(string $host, string $url): bool
    {
        $urlHost = parse_url($url, PHP_URL_HOST);
        $urlPath = parse_url($url, PHP_URL_PATH) ?: '';

        if ($urlPath !== '' && $urlPath !== '/') {
            return false;
        }

        return $urlHost !== null && $host === strtolower($urlHost);
    }

    private static function inferAreaFromPath(string $path): string
    {
        foreach (self::AREA_PREFIXES as $area => $prefix) {
            if ($path === $prefix || str_starts_with($path, $prefix . '/')) {
                return $area;
            }
        }

        return 'main';
    }

    private static function stripAreaPrefix(string $path, string $area): string
    {
        $prefix = self::AREA_PREFIXES[$area] ?? null;

        if ($prefix === null) {
            return $path;
        }

        if ($path === $prefix) {
            return '/';
        }

        if (str_starts_with($path, $prefix . '/')) {
            return substr($path, strlen($prefix)) ?: '/';
        }

        return $path;
    }

    private static function isPublicPath(string $path): bool
    {
        return str_starts_with($path, '/assets/')
            || str_starts_with($path, '/uploads/')
            || str_starts_with($path, '/favicon');
    }

    private static function normalizePath(string $path): string
    {
        $path = '/' . ltrim($path, '/');
        $path = preg_replace('~/+~', '/', $path) ?: '/';

        return $path === '' ? '/' : $path;
    }
}
