<?php

declare(strict_types=1);

/**
 * store_public 客戶端金鑰演算法（與新手村 newbies 相同）。
 * 獨立部署 FATE、無 sibling newbies 時由 spa_store_public_client_key.php 載入。
 */

if (!function_exists('spa_store_public_client_key_version')) {
    function spa_store_public_client_key_version(): string
    {
        return '1';
    }
}

if (!function_exists('spa_normalize_site_host')) {
    function spa_normalize_site_host(string $urlOrHost): ?string
    {
        $raw = trim($urlOrHost);
        if ($raw === '') {
            return null;
        }
        if (!preg_match('#^https?://#i', $raw)) {
            $raw = 'https://' . $raw;
        }
        $parts = parse_url($raw);
        if (!is_array($parts)) {
            return null;
        }
        $host = isset($parts['host']) ? strtolower(trim((string) $parts['host'])) : '';
        if ($host === '' || strlen($host) > 253) {
            return null;
        }
        if (!preg_match('/^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$/i', $host)) {
            return null;
        }

        return $host;
    }
}

if (!function_exists('spa_store_public_client_key_local_dev_reject_message')) {
    /** 本地端／內網網址無法產生或向新手村申請金鑰時的說明。 */
    function spa_store_public_client_key_local_dev_reject_message(): string
    {
        return '目前對外網址無法用於產生 API 金鑰（須為可公開連線的正式網域，不可為 IP 或 localhost）。'
            . '請在「網站與模版」或環境變數 FATE_PUBLIC_SITE_ORIGIN 設定正式網址（例：https://fate.example.com/）。';
    }
}

if (!function_exists('spa_store_public_client_key_host_reject_reason')) {
    function spa_store_public_client_key_host_reject_reason(string $host): ?string
    {
        $host = strtolower(trim($host));
        if ($host === '') {
            return '無效的網站網址';
        }

        if ($host[0] === '[' && str_ends_with($host, ']')) {
            $host = substr($host, 1, -1);
        }

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

        if ($host === 'localhost' || str_ends_with($host, '.localhost')) {
            return spa_store_public_client_key_local_dev_reject_message();
        }

        return null;
    }
}

if (!function_exists('spa_normalize_site_url')) {
    function spa_normalize_site_url(string $url): ?string
    {
        $host = spa_normalize_site_host($url);
        if ($host === null) {
            return null;
        }
        $parts = parse_url(trim($url));
        $scheme = 'https';
        if (is_array($parts) && !empty($parts['scheme'])) {
            $s = strtolower((string) $parts['scheme']);
            if ($s === 'http' || $s === 'https') {
                $scheme = $s;
            }
        }

        return $scheme . '://' . $host . '/';
    }
}

if (!function_exists('spa_store_public_client_key_encode_host')) {
    function spa_store_public_client_key_encode_host(string $host): string
    {
        return rtrim(strtr(base64_encode($host), '+/', '-_'), '=');
    }
}

if (!function_exists('spa_store_public_client_key_decode_host')) {
    function spa_store_public_client_key_decode_host(string $apiKey): ?string
    {
        $apiKey = trim($apiKey);
        $ver = spa_store_public_client_key_version();
        $pattern = '/^spa_pk_' . preg_quote($ver, '/') . '_([A-Za-z0-9_-]+)_([a-f0-9]{32})$/';
        if (!preg_match($pattern, $apiKey, $m)) {
            return null;
        }
        $b64 = strtr($m[1], '-_', '+/');
        $pad = strlen($b64) % 4;
        if ($pad > 0) {
            $b64 .= str_repeat('=', 4 - $pad);
        }
        $host = base64_decode($b64, true);
        if (!is_string($host) || $host === '') {
            return null;
        }
        $host = strtolower(trim($host));
        if (spa_normalize_site_host('https://' . $host) !== $host) {
            return null;
        }

        return $host;
    }
}

if (!function_exists('spa_store_public_client_key_build')) {
    /**
     * @return array{ok:bool, key?:string, host?:string, error?:string}
     */
    function spa_store_public_client_key_build(string $siteUrl): array
    {
        $host = spa_normalize_site_host($siteUrl);
        if ($host === null) {
            return ['ok' => false, 'error' => '無法解析網站網址，請輸入含網域的完整 URL（例：https://fate.novice.tw/）'];
        }
        $hostReject = spa_store_public_client_key_host_reject_reason($host);
        if ($hostReject !== null) {
            return ['ok' => false, 'error' => $hostReject];
        }
        $ver = spa_store_public_client_key_version();
        $enc = spa_store_public_client_key_encode_host($host);
        $rand = bin2hex(random_bytes(16));
        $key = 'spa_pk_' . $ver . '_' . $enc . '_' . $rand;

        return ['ok' => true, 'key' => $key, 'host' => $host];
    }
}

if (!function_exists('spa_store_public_client_key_hash')) {
    function spa_store_public_client_key_hash(string $apiKey): string
    {
        return hash('sha256', trim($apiKey));
    }
}

if (!function_exists('spa_store_public_client_key_hint')) {
    function spa_store_public_client_key_hint(string $apiKey): string
    {
        $apiKey = trim($apiKey);
        $len = strlen($apiKey);
        if ($len <= 8) {
            return '••••';
        }

        return '••••' . substr($apiKey, -8);
    }
}
