<?php

declare(strict_types=1);

if (!function_exists('load_env_file')) {
    function load_env_file(string $filePath): void
    {
        /** @var array<string, true> $loadedFiles */
        static $loadedFiles = [];

        $realPath = realpath($filePath);
        if ($realPath === false) {
            return;
        }

        if (isset($loadedFiles[$realPath])) {
            return;
        }

        if (!is_readable($realPath)) {
            return;
        }

        $lines = file($realPath, FILE_IGNORE_NEW_LINES);
        if ($lines === false) {
            return;
        }

        foreach ($lines as $line) {
            load_env_line($line);
        }

        $loadedFiles[$realPath] = true;
    }
}

if (!function_exists('load_env_line')) {
    function load_env_line(string $line): void
    {
        $line = trim($line);
        if ($line === '' || str_starts_with($line, '#')) {
            return;
        }

        if (str_starts_with($line, 'export ')) {
            $line = ltrim(substr($line, 7));
        }

        $separatorPosition = strpos($line, '=');
        if ($separatorPosition === false) {
            return;
        }

        $name = trim(substr($line, 0, $separatorPosition));
        if ($name === '' || preg_match('/^[A-Z0-9_]+$/', $name) !== 1) {
            return;
        }

        if (getenv($name) !== false || isset($_ENV[$name]) || isset($_SERVER[$name])) {
            return;
        }

        $value = load_env_normalize_value(substr($line, $separatorPosition + 1));

        // Auto-migrate: SRP_REPORT_DIR is no longer used — click log path is
        // hardcoded to statistics/temp/. Skip any domain-style value (e.g.
        // "report.hrhgrhg.cyou") so it is never set in the environment.
        if ($name === 'SRP_REPORT_DIR' && str_contains($value, '.')) {
            return;
        }

        putenv($name . '=' . $value);
        $_ENV[$name] = $value;
        $_SERVER[$name] = $value;
    }
}

if (!function_exists('load_env_normalize_value')) {
    function load_env_normalize_value(string $value): string
    {
        $value = trim($value);
        $length = strlen($value);

        if ($length >= 2) {
            $firstCharacter = $value[0];
            $lastCharacter = $value[$length - 1];

            if (
                ($firstCharacter === '"' && $lastCharacter === '"')
                || ($firstCharacter === '\'' && $lastCharacter === '\'')
            ) {
                $value = substr($value, 1, -1);

                if ($firstCharacter === '"') {
                    $value = strtr(
                        $value,
                        [
                            '\\n' => "\n",
                            '\\r' => "\r",
                            '\\t' => "\t",
                            '\\\\' => '\\',
                            '\\"' => '"',
                        ],
                    );
                }

                return $value;
            }
        }

        $commentPosition = strpos($value, ' #');

        if ($commentPosition !== false) {
            $value = rtrim(substr($value, 0, $commentPosition));
        }

        return $value;
    }
}

if (!function_exists('app_env')) {
    function app_env(string $key, ?string $default = null): ?string
    {
        $value = $_ENV[$key] ?? $_SERVER[$key] ?? getenv($key);
        if ($value === false || $value === null || $value === '') {
            return $default;
        }

        return is_string($value) ? $value : (string) $value;
    }
}

if (!function_exists('app_required_env')) {
    function app_required_env(string $key): string
    {
        $value = app_env($key);
        if ($value === null || $value === '') {
            throw new RuntimeException('Missing required environment variable: ' . $key);
        }

        return $value;
    }
}

if (!function_exists('app_normalize_cpanel_host')) {
    function app_normalize_cpanel_host(string $host): string
    {
        $host = trim($host);
        if ($host === '') {
            return '';
        }

        $host = preg_replace('#^https?://#i', '', $host) ?? $host;
        $host = explode('/', $host, 2)[0];
        $host = trim($host, " \t\n\r\0\x0B.");

        if (str_contains($host, ':') && substr_count($host, ':') === 1) {
            [$hostPart] = explode(':', $host, 2);
            $host = trim($hostPart);
        }

        if ($host === '') {
            return '';
        }

        if (preg_match('/[\/\\\\@?#\[\]]/', $host) === 1) {
            return '';
        }

        if (filter_var($host, FILTER_VALIDATE_IP) !== false) {
            return $host;
        }

        $host = strtolower($host);
        if (strlen($host) > 253) {
            return '';
        }

        $hostPattern = '/^(?=.{1,253}$)(?!-)'
            . '(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+'
            . '[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])$/';

        if (preg_match($hostPattern, $host) !== 1) {
            return '';
        }

        return $host;
    }
}

if (!function_exists('app_is_public_cpanel_host')) {
    function app_is_public_cpanel_host(string $host): bool
    {
        $host = app_normalize_cpanel_host($host);
        if ($host === '') {
            return false;
        }

        if (preg_match('/^(localhost|localdomain)$/i', $host) === 1) {
            return false;
        }

        if (filter_var($host, FILTER_VALIDATE_IP) !== false) {
            return filter_var(
                $host,
                FILTER_VALIDATE_IP,
                FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE,
            ) !== false;
        }

        return str_contains($host, '.');
    }
}

if (!function_exists('app_detect_cpanel_host')) {
    function app_detect_cpanel_host(?string $configuredHost = null, int $port = 2083): string
    {
        $configured = app_normalize_cpanel_host((string) ($configuredHost ?? app_env('CPANEL_HOST', '')));
        if (app_is_public_cpanel_host($configured)) {
            return $configured;
        }

        $candidates = [];
        foreach (
            [
                $_SERVER['SERVER_NAME'] ?? '',
                $_SERVER['HTTP_HOST'] ?? '',
                gethostname() ?: '',
                php_uname('n') ?: '',
            ] as $candidate
        ) {
            $normalized = app_normalize_cpanel_host((string) $candidate);
            if (app_is_public_cpanel_host($normalized)) {
                $candidates[] = $normalized;
            }
        }

        $serverAddress = $_SERVER['SERVER_ADDR'] ?? '';
        $serverAddressIsPublic = is_string($serverAddress)
            && filter_var(
                $serverAddress,
                FILTER_VALIDATE_IP,
                FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE,
            ) !== false;

        if ($serverAddressIsPublic) {
            $reverse = gethostbyaddr($serverAddress);
            if (is_string($reverse) && $reverse !== $serverAddress) {
                $normalized = app_normalize_cpanel_host($reverse);
                if (app_is_public_cpanel_host($normalized)) {
                    $candidates[] = $normalized;
                }
            }
        }

        foreach (array_values(array_unique($candidates)) as $candidate) {
            if (app_cpanel_host_responds($candidate, $port)) {
                return $candidate;
            }
        }

        return $candidates[0] ?? ($configured !== '' ? $configured : 'localhost');
    }
}

if (!function_exists('app_cpanel_host_responds')) {
    function app_cpanel_host_responds(string $host, int $port = 2083): bool
    {
        $host = app_normalize_cpanel_host($host);
        if (!app_is_public_cpanel_host($host)) {
            return false;
        }

        $port = $port >= 1 && $port <= 65535 ? $port : 2083;

        if (extension_loaded('curl')) {
            $ch = curl_init('https://' . $host . ':' . $port . '/');
            if ($ch === false) {
                return false;
            }

            curl_setopt_array($ch, [
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_NOBODY => true,
                CURLOPT_CONNECTTIMEOUT => 2,
                CURLOPT_TIMEOUT => 4,
                CURLOPT_SSL_VERIFYPEER => true,
                CURLOPT_SSL_VERIFYHOST => 2,
            ]);
            curl_exec($ch);
            $errno = curl_errno($ch);
            $httpCode = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
            curl_close($ch);

            return $errno === 0 && $httpCode > 0;
        }

        $socket = @fsockopen('ssl://' . $host, $port, $errno, $error, 2.0);
        if (is_resource($socket)) {
            fclose($socket);

            return true;
        }

        return false;
    }
}
