<?php

declare(strict_types=1);

class Translator
{
    private static string $locale = 'en';
    private static array $strings = [];
    private static array $fallback = [];
    private static array $overrides = [];
    private static array $available = [];
    private static array $rtlLocales = ['ar', 'fa', 'he'];
    private static bool $booted = false;
    private static array $registeredKeys = [];
    private static array $registeredSections = [];

    public static function boot(): void
    {
        if (self::$booted) {
            return;
        }
        self::$booted = true;

         
        self::loadAvailable();

         
        self::detectLocale();

         
        self::$fallback = self::loadFile('en');

         
        if (self::$locale !== 'en') {
            self::$strings = self::loadFile(self::$locale);
        }

         
        self::loadOverrides();
    }

    public static function registerKeys(string $section, array $keys): void
    {
        foreach ($keys as $k => $defaultValue) {
            self::$registeredKeys[$k] = $defaultValue;
        }
        if (!isset(self::$registeredSections[$section])) {
            self::$registeredSections[$section] = [];
        }
        self::$registeredSections[$section] = array_values(array_unique(array_merge(
            self::$registeredSections[$section],
            array_keys($keys)
        )));
    }

    public static function getRegisteredKeys(): array
    {
        return self::$registeredKeys;
    }

    public static function getRegisteredSections(): array
    {
        return self::$registeredSections;
    }

    public static function get(string $key, array $replacements = []): string
    {
        $text = self::$overrides[$key] ?? self::$strings[$key] ?? self::$fallback[$key] ?? self::$registeredKeys[$key] ?? $key;

        foreach ($replacements as $placeholder => $value) {
            $text = str_replace($placeholder, (string) $value, $text);
        }

        return $text;
    }

    

    public static function slug(string $slugKey, string $labelKey): string
    {
         
        if (isset(self::$overrides[$slugKey]) && self::$overrides[$slugKey] !== '') {
            return self::$overrides[$slugKey];
        }

         
        $localeStrings = (self::$locale === 'en') ? self::$fallback : self::$strings;
        if (isset($localeStrings[$slugKey]) && $localeStrings[$slugKey] !== '') {
            return $localeStrings[$slugKey];
        }

         
        $label = self::get($labelKey);
        if ($label !== $labelKey && $label !== '') {
            $generated = Slug::generate($label);
            if ($generated !== '') return $generated;
        }

         
        $en = self::loadFile('en');
        $fallback = $en[$slugKey] ?? Slug::generate($en[$labelKey] ?? $slugKey);
        return $fallback !== '' ? $fallback : $slugKey;
    }

    public static function locale(): string
    {
        return self::$locale;
    }

    public static function setLocale(string $code): void
    {
        if (self::isEnabled($code)) {
            self::$locale = $code;
            self::$strings = ($code !== 'en') ? self::loadFile($code) : [];
            self::loadOverrides();
        }
    }

    public static function getFileStrings(string $code): array
    {
        return self::loadFile($code);
    }

    public static function getOverrides(string $code): array
    {
        try {
            $rows = Database::fetchAll(
                'SELECT translation_key, value FROM translation_overrides WHERE lang_code = ?',
                [$code]
            );
            $map = [];
            foreach ($rows as $row) {
                $map[$row['translation_key']] = $row['value'];
            }
            return $map;
        } catch (\Throwable $e) {
            return [];
        }
    }

    public static function isRtl(): bool
    {
        return in_array(self::$locale, self::$rtlLocales, true);
    }

    public static function direction(): string
    {
        return self::isRtl() ? 'rtl' : 'ltr';
    }

    public static function available(): array
    {
        return self::$available;
    }

    

    public static function flagCode(string $langCode): string
    {
        static $map = [
            'en' => 'gb', 'fr' => 'fr', 'es' => 'es', 'pt' => 'pt', 'it' => 'it',
            'de' => 'de', 'ru' => 'ru', 'uk' => 'ua', 'sr' => 'rs', 'bg' => 'bg',
            'pl' => 'pl', 'ar' => 'sa', 'fa' => 'ir', 'he' => 'il', 'tr' => 'tr',
            'id' => 'id', 'zh' => 'cn', 'ja' => 'jp', 'ko' => 'kr', 'th' => 'th',
            'vi' => 'vn', 'hi' => 'in', 'bn' => 'bd', 'nl' => 'nl', 'ro' => 'ro',
            'cs' => 'cz', 'el' => 'gr', 'sv' => 'se', 'hu' => 'hu', 'ms' => 'my',
        ];
        return $map[$langCode] ?? $langCode;
    }

    public static function jsTranslations(): string
    {
        $jsKeys = [
            'please_wait', 'network_error', 'an_error_occurred', 'too_many_requests',
            'add_to_favorites', 'remove_from_favorites', 'show_more', 'show_less',
            'reply_to_comment', 'clear_history_confirm',
            'views_count', 'likes_count',
            'time_seconds_ago', 'time_minute_ago', 'time_minutes_ago',
            'time_hour_ago', 'time_hours_ago', 'time_day_ago', 'time_days_ago',
            'time_month_ago', 'time_months_ago', 'time_year_ago', 'time_years_ago',
            'report_submitted', 'anonymous',
        ];

        $translations = [];
        foreach ($jsKeys as $key) {
            $translations[$key] = self::get($key);
        }

        return json_encode($translations, JSON_UNESCAPED_UNICODE);
    }

    private static function isAdminRequest(): bool
    {
        $uri = strtok($_SERVER['REQUEST_URI'] ?? '/', '?');
        return str_starts_with($uri, '/admin') || str_starts_with($uri, '/install');
    }

    private static function detectLocale(): void
    {
         
        if (self::isAdminRequest()) {
            self::useDefaultLocale();
            return;
        }

         
        if (isset($_GET['_lang'])) {
            $code = preg_replace('/[^a-z]/', '', strtolower($_GET['_lang']));
            if (self::isEnabled($code)) {
                self::$locale = $code;
                setcookie('_tp_lang', $code, [
                    'expires' => time() + 365 * 86400,
                    'path' => '/',
                    'httponly' => false,
                    'secure' => !empty($_SERVER['HTTPS']),
                    'samesite' => 'Lax',
                ]);
                 
                 
                 
                $uri = parse_url(strtok($_SERVER['REQUEST_URI'], '?'), PHP_URL_PATH) ?: '/';
                $uri = '/' . ltrim($uri, '/');
                $uri = rtrim($uri, '/') ?: '/';
                 
                if (preg_match('#^/([a-z]{2})(/.*|$)#', $uri, $m) && self::isEnabled($m[1])) {
                    $uri = $m[2] ?: '/';
                    $uri = '/' . ltrim($uri, '/');
                    $uri = rtrim($uri, '/') ?: '/';
                }
                $params = $_GET;
                unset($params['_lang']);
                $qs = http_build_query($params);
                $defaultCode = self::getDefaultCode();
                $prefix = ($code === $defaultCode) ? '' : '/' . $code;
                $redirect = $prefix . $uri . ($qs ? '?' . $qs : '');
                header('Location: ' . $redirect, true, 302);
                exit;
            }
        }

         
        if (isset($_COOKIE['_tp_lang'])) {
            $code = preg_replace('/[^a-z]/', '', strtolower($_COOKIE['_tp_lang']));
            if (self::isEnabled($code)) {
                self::$locale = $code;
                return;
            }
        }

         
        if (Setting::get('auto_detect_language', '1') === '1') {
            $acceptLang = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
            if ($acceptLang !== '') {
                $langs = [];
                foreach (explode(',', $acceptLang) as $part) {
                    $part = trim($part);
                    $bits = explode(';', $part);
                    $code = strtolower(trim($bits[0]));
                     
                    $code = explode('-', $code)[0];
                    $q = 1.0;
                    if (isset($bits[1]) && str_starts_with(trim($bits[1]), 'q=')) {
                        $q = (float) substr(trim($bits[1]), 2);
                    }
                    $langs[$code] = $q;
                }
                arsort($langs);
                foreach ($langs as $code => $q) {
                    $code = preg_replace('/[^a-z]/', '', $code);
                    if (self::isEnabled($code)) {
                        self::$locale = $code;
                        return;
                    }
                }
            }
        }

         
        self::useDefaultLocale();
    }

    private static function useDefaultLocale(): void
    {
        if (!empty(self::$available)) {
            foreach (self::$available as $lang) {
                if (!empty($lang['is_default'])) {
                    self::$locale = $lang['code'];
                    return;
                }
            }
        }
        self::$locale = 'en';
    }

    private static function loadOverrides(): void
    {
        try {
            if (!App::isInstalled()) {
                return;
            }
            $rows = Database::fetchAll(
                'SELECT translation_key, value FROM translation_overrides WHERE lang_code = ?',
                [self::$locale]
            );
            self::$overrides = [];
            foreach ($rows as $row) {
                self::$overrides[$row['translation_key']] = $row['value'];
            }
        } catch (\Throwable $e) {
             
            self::$overrides = [];
        }
    }

    private static function loadFile(string $code): array
    {
        $code = preg_replace('/[^a-z]/', '', $code);
        $path = APP_ROOT . '/lang/' . $code . '.php';
        if (file_exists($path)) {
            $data = require $path;
            return is_array($data) ? $data : [];
        }
        return [];
    }

    public static function isEnabled(string $code): bool
    {
        if (empty(self::$available)) {
             
            return $code === 'en';
        }
        foreach (self::$available as $lang) {
            if ($lang['code'] === $code && !empty($lang['is_enabled'])) {
                return true;
            }
        }
        return false;
    }

    public static function getDefaultCode(): string
    {
        foreach (self::$available as $lang) {
            if (!empty($lang['is_default'])) {
                return $lang['code'];
            }
        }
        return 'en';
    }

    private static function loadAvailable(): void
    {
        try {
            if (!App::isInstalled()) {
                self::$available = [];
                return;
            }
            $rows = Database::fetchAll(
                'SELECT code, name, native_name, direction, is_enabled, is_default FROM languages ORDER BY sort_order ASC'
            );
             
            self::$available = array_values(array_filter($rows, fn($r) => (int)$r['is_enabled'] === 1));
        } catch (\Throwable $e) {
             
            self::$available = [];
        }
    }
}
