<?php
namespace EasyChat\Library\Catalog;




final class CatalogUrlPolicy {

    public static function isSafeLink(string $link): bool {
        if (!self::hasSafeCharacters($link)) {
            return false;
        }
        if ($link[0] === '/') {
            return strpos($link, '//') !== 0;
        }

        $parts = self::parts($link);
        if ($parts === null) {
            return false;
        }
        $scheme = strtolower((string)($parts['scheme'] ?? ''));
        return in_array($scheme, array('http', 'https'), true)
            && !isset($parts['user'])
            && !isset($parts['pass'])
            && self::isSafeHost((string)($parts['host'] ?? ''))
            && self::isSafePort($parts['port'] ?? null);
    }

    



    public static function normalizeBaseUrl(string $url): string {
        $url = trim($url);
        if (!self::hasSafeCharacters($url)) {
            return '';
        }

        $parts = self::parts($url);
        if ($parts === null || isset($parts['query']) || isset($parts['fragment'])
            || isset($parts['user']) || isset($parts['pass'])) {
            return '';
        }
        $scheme = strtolower((string)($parts['scheme'] ?? ''));
        $host = trim((string)($parts['host'] ?? ''), '[]');
        if (!in_array($scheme, array('http', 'https'), true)
            || !self::isSafeHost($host)
            || !self::isSafePort($parts['port'] ?? null)) {
            return '';
        }

        $host_for_url = strpos($host, ':') !== false ? '[' . $host . ']' : strtolower($host);
        $port = isset($parts['port']) ? ':' . (int)$parts['port'] : '';
        $path = isset($parts['path']) ? (string)$parts['path'] : '';
        if ($path !== '' && $path[0] !== '/') {
            return '';
        }

        return rtrim($scheme . '://' . $host_for_url . $port . $path, '/');
    }

    private static function hasSafeCharacters(string $value): bool {
        $unsafe = preg_match('/[\x00-\x20\x7F]/u', $value);
        return $value !== ''
            && strpos($value, '\\') === false
            && $unsafe === 0;
    }

    private static function parts(string $url) {
        try {
            $parts = @parse_url($url);
        } catch (\Throwable $e) {
            return null;
        }
        return is_array($parts) ? $parts : null;
    }

    private static function isSafePort($port): bool {
        if ($port === null || $port === '') {
            return true;
        }
        return is_numeric($port) && (int)$port >= 1 && (int)$port <= 65535;
    }

    private static function isSafeHost(string $host): bool {
        $host = trim($host, '[]');
        if ($host === '') {
            return false;
        }
        if (filter_var($host, FILTER_VALIDATE_IP) !== false) {
            return true;
        }
        return strlen($host) <= 253
            && preg_match('/^(?=.{1,253}$)(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)*[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$/D', $host) === 1;
    }
}
