'use strict';

var EventBus = require('../core/EventBus.js');

/* ────────────────────────────────────────────────────────────────
   I18nManager — LEGENDARY internationalization engine
   
   Features:
   • Namespace support: t('editor:tools.select')
   • Interpolation: t('hello', { name: 'Jan' })
   • Pluralization: t('items', { count: 5 })
   • Lazy loading per module
   • RTL detection
   • Date/time/number formatting
   • 20 languages supported
   • React hook: useTranslation()
──────────────────────────────────────────────────────────────── */
/** All supported locales as array */
const SUPPORTED_LOCALES = [
    'pl', 'en', 'de', 'fr', 'es',
    'it', 'pt', 'nl', 'sv', 'no',
    'da', 'fi', 'cs', 'sk', 'hu',
    'ro', 'bg', 'uk', 'ja', 'ko',
];
/** Human-readable locale names */
const LOCALE_NAMES = {
    pl: 'Polski',
    en: 'English',
    de: 'Deutsch',
    fr: 'Français',
    es: 'Español',
    it: 'Italiano',
    pt: 'Português',
    nl: 'Nederlands',
    sv: 'Svenska',
    no: 'Norsk',
    da: 'Dansk',
    fi: 'Suomi',
    cs: 'Čeština',
    sk: 'Slovenčina',
    hu: 'Magyar',
    ro: 'Română',
    bg: 'Български',
    uk: 'Українська',
    ja: '日本語',
    ko: '한국어',
};
/** RTL locales (none currently, but extensible for ar, he) */
const RTL_LOCALES = new Set([]);
/* ── Plural Rules ─────────────────────────────────────────────── */
/** CLDR-based plural rules for supported languages */
const PLURAL_RULES = {
    // Germanic / Romance (en, de, nl, sv, no, da, fi, it, pt, es, fr, hu, ro)
    oneOther: {
        select(n) {
            return n === 1 ? 'one' : 'other';
        },
    },
    // Slavic (pl, cs, sk, uk, bg)
    slavic: {
        select(n) {
            if (n === 1)
                return 'one';
            const mod10 = n % 10;
            const mod100 = n % 100;
            if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14))
                return 'few';
            if (n !== 1 && mod10 >= 0 && mod10 <= 1)
                return 'many';
            if (mod10 >= 5 && mod10 <= 9)
                return 'many';
            if (mod100 >= 12 && mod100 <= 14)
                return 'many';
            return 'other';
        },
    },
    // Japanese, Korean (no plural forms)
    eastAsian: {
        select(_n) {
            return 'other';
        },
    },
    // French (0 and 1 are singular)
    french: {
        select(n) {
            return n === 0 || n === 1 ? 'one' : 'other';
        },
    },
};
const LOCALE_PLURAL_MAP = {
    en: PLURAL_RULES.oneOther,
    de: PLURAL_RULES.oneOther,
    nl: PLURAL_RULES.oneOther,
    sv: PLURAL_RULES.oneOther,
    no: PLURAL_RULES.oneOther,
    da: PLURAL_RULES.oneOther,
    fi: PLURAL_RULES.oneOther,
    it: PLURAL_RULES.oneOther,
    pt: PLURAL_RULES.oneOther,
    es: PLURAL_RULES.oneOther,
    hu: PLURAL_RULES.oneOther,
    ro: PLURAL_RULES.oneOther,
    fr: PLURAL_RULES.french,
    pl: PLURAL_RULES.slavic,
    cs: PLURAL_RULES.slavic,
    sk: PLURAL_RULES.slavic,
    uk: PLURAL_RULES.slavic,
    bg: PLURAL_RULES.slavic,
    ja: PLURAL_RULES.eastAsian,
    ko: PLURAL_RULES.eastAsian,
};
/* ── I18nManager ──────────────────────────────────────────────── */
const DEFAULT_I18N_CONFIG = {
    defaultLocale: 'en',
    fallbackLocale: 'en',
    debug: false,
    interpolationPrefix: '{{',
    interpolationSuffix: '}}',
    pluralSeparator: '_',
    namespaceSeparator: ':',
    keySeparator: '.',
};
class I18nManager {
    constructor(config) {
        this.namespaces = new Map();
        this.loadedNamespaces = new Set();
        this.events = new EventBus.EventBus();
        this.config = { ...DEFAULT_I18N_CONFIG, ...config };
        this.locale = this.config.defaultLocale;
    }
    /* ── Locale Management ──────────────────────────────────────── */
    getLocale() {
        return this.locale;
    }
    setLocale(locale) {
        if (!SUPPORTED_LOCALES.includes(locale)) {
            if (this.config.debug) {
                // eslint-disable-next-line no-console
                console.warn(`[I18n] Unsupported locale: "${locale}". Falling back to "${this.config.fallbackLocale}".`);
            }
            return;
        }
        const prev = this.locale;
        this.locale = locale;
        this.events.emit('locale:changed', { from: prev, to: locale });
    }
    isRTL() {
        return RTL_LOCALES.has(this.locale);
    }
    /** Auto-detect locale from browser settings */
    detectLocale() {
        if (typeof navigator === 'undefined')
            return this.config.defaultLocale;
        const browserLang = navigator.language.split('-')[0].toLowerCase();
        const match = SUPPORTED_LOCALES.find(l => l === browserLang);
        return match !== null && match !== void 0 ? match : this.config.defaultLocale;
    }
    /* ── Translation Loading ────────────────────────────────────── */
    /**
     * Add translations for a namespace + locale.
     * Can be called multiple times (merges).
     */
    addTranslations(namespace, locale, translations) {
        var _a;
        let nsMap = this.namespaces.get(namespace);
        if (!nsMap) {
            nsMap = new Map();
            this.namespaces.set(namespace, nsMap);
        }
        const existing = (_a = nsMap.get(locale)) !== null && _a !== void 0 ? _a : {};
        nsMap.set(locale, deepMergeDict(existing, translations));
        this.loadedNamespaces.add(`${namespace}:${locale}`);
    }
    /** Check if translations are loaded for namespace + locale */
    isLoaded(namespace, locale) {
        return this.loadedNamespaces.has(`${namespace}:${locale !== null && locale !== void 0 ? locale : this.locale}`);
    }
    /** Load translations from async source (e.g., dynamic import) */
    async loadNamespace(namespace, locale, loader) {
        const key = `${namespace}:${locale}`;
        if (this.loadedNamespaces.has(key))
            return;
        const dict = await loader();
        this.addTranslations(namespace, locale, dict);
        this.events.emit('namespace:loaded', { namespace, locale });
    }
    /* ── Translation ────────────────────────────────────────────── */
    /**
     * Translate a key.
     *
     * @param fullKey - Key with optional namespace: 'ns:path.to.key' or just 'path.to.key'
     * @param values - Interpolation values (including `count` for pluralization)
     * @returns Translated string or fallback
     *
     * @example
     * i18n.t('editor:tools.select') // → 'Select'
     * i18n.t('game:score', { score: 100 }) // → 'Score: 100'
     * i18n.t('items', { count: 5 }) // → '5 items' (pluralized)
     */
    t(fullKey, values) {
        const { ns, key } = this.parseKey(fullKey);
        const count = values === null || values === void 0 ? void 0 : values.count;
        // Try current locale
        let result = this.resolve(ns, this.locale, key, typeof count === 'number' ? count : undefined);
        // Fallback to default locale
        if (result === undefined && this.locale !== this.config.fallbackLocale) {
            result = this.resolve(ns, this.config.fallbackLocale, key, typeof count === 'number' ? count : undefined);
        }
        // Missing key handler
        if (result === undefined) {
            if (this.config.missingKeyHandler) {
                return this.config.missingKeyHandler(this.locale, ns, key);
            }
            if (this.config.debug) {
                // eslint-disable-next-line no-console
                console.warn(`[I18n] Missing translation: "${fullKey}" (${this.locale})`);
            }
            return fullKey;
        }
        // Interpolation
        if (values) {
            return this.interpolate(result, values);
        }
        return result;
    }
    /** Get plural category for current locale */
    getPluralCategory(count) {
        const rule = LOCALE_PLURAL_MAP[this.locale];
        return rule.select(count);
    }
    /* ── Formatting ─────────────────────────────────────────────── */
    /** Format number using locale conventions */
    formatNumber(value, options) {
        return new Intl.NumberFormat(this.locale, options).format(value);
    }
    /** Format date using locale conventions */
    formatDate(date, options) {
        return new Intl.DateTimeFormat(this.locale, options).format(date);
    }
    /** Format relative time (e.g., "2 days ago") — requires ES2020+ runtime */
    formatRelativeTime(value, unit) {
        const Ctor = Intl.RelativeTimeFormat;
        if (!Ctor)
            return `${value} ${unit}`;
        return new Ctor(this.locale, { numeric: 'auto' }).format(value, unit);
    }
    /* ── Internals ──────────────────────────────────────────────── */
    parseKey(fullKey) {
        const sepIdx = fullKey.indexOf(this.config.namespaceSeparator);
        if (sepIdx > 0) {
            return {
                ns: fullKey.slice(0, sepIdx),
                key: fullKey.slice(sepIdx + 1),
            };
        }
        return { ns: 'common', key: fullKey };
    }
    resolve(ns, locale, key, count) {
        const nsMap = this.namespaces.get(ns);
        if (!nsMap)
            return undefined;
        const dict = nsMap.get(locale);
        if (!dict)
            return undefined;
        // With pluralization
        if (count !== undefined) {
            const category = LOCALE_PLURAL_MAP[locale].select(count);
            const pluralKey = `${key}${this.config.pluralSeparator}${category}`;
            const pluralResult = lookupKey(dict, pluralKey, this.config.keySeparator);
            if (typeof pluralResult === 'string')
                return pluralResult;
            // Fallback to _other
            const otherKey = `${key}${this.config.pluralSeparator}other`;
            const otherResult = lookupKey(dict, otherKey, this.config.keySeparator);
            if (typeof otherResult === 'string')
                return otherResult;
        }
        const result = lookupKey(dict, key, this.config.keySeparator);
        return typeof result === 'string' ? result : undefined;
    }
    interpolate(text, values) {
        const { interpolationPrefix: pre, interpolationSuffix: suf } = this.config;
        let result = text;
        for (const [k, v] of Object.entries(values)) {
            const placeholder = `${pre}${k}${suf}`;
            // Replace all occurrences without regex
            while (result.includes(placeholder)) {
                result = result.replace(placeholder, String(v));
            }
        }
        return result;
    }
    /* ── Export / Inspect ───────────────────────────────────────── */
    /** Get all loaded namespaces */
    getLoadedNamespaces() {
        return Array.from(this.namespaces.keys());
    }
    /** Get all translations for a namespace + locale (for debugging) */
    getTranslations(namespace, locale) {
        const nsMap = this.namespaces.get(namespace);
        return nsMap === null || nsMap === void 0 ? void 0 : nsMap.get(locale !== null && locale !== void 0 ? locale : this.locale);
    }
    /** Get count of missing translations for a locale compared to fallback */
    getMissingKeys(namespace, locale) {
        var _a, _b;
        const fallbackDict = (_a = this.namespaces.get(namespace)) === null || _a === void 0 ? void 0 : _a.get(this.config.fallbackLocale);
        const targetDict = (_b = this.namespaces.get(namespace)) === null || _b === void 0 ? void 0 : _b.get(locale);
        if (!fallbackDict)
            return [];
        const missing = [];
        collectKeys(fallbackDict, '', (key) => {
            if (!targetDict || lookupKey(targetDict, key, this.config.keySeparator) === undefined) {
                missing.push(key);
            }
        });
        return missing;
    }
    dispose() {
        this.namespaces.clear();
        this.loadedNamespaces.clear();
    }
}
/* ── Helpers ──────────────────────────────────────────────────── */
function lookupKey(dict, key, separator) {
    const parts = key.split(separator);
    let current = dict;
    for (const part of parts) {
        if (typeof current !== 'object' || current === null)
            return undefined;
        current = current[part];
    }
    return current;
}
function deepMergeDict(target, source) {
    const result = { ...target };
    for (const key of Object.keys(source)) {
        const sv = source[key];
        const tv = target[key];
        if (typeof sv === 'object' && sv !== null && typeof tv === 'object' && tv !== null) {
            result[key] = deepMergeDict(tv, sv);
        }
        else {
            result[key] = sv;
        }
    }
    return result;
}
function collectKeys(dict, prefix, callback) {
    for (const [key, value] of Object.entries(dict)) {
        const fullKey = prefix ? `${prefix}.${key}` : key;
        if (typeof value === 'string') {
            callback(fullKey);
        }
        else {
            collectKeys(value, fullKey, callback);
        }
    }
}
/* ── Singleton convenience ────────────────────────────────────── */
let _defaultManager;
/** Get or create the default I18nManager instance */
function getI18n() {
    if (!_defaultManager) {
        _defaultManager = new I18nManager();
    }
    return _defaultManager;
}
/** Initialize the default I18nManager with config */
function initI18n(config) {
    _defaultManager = new I18nManager(config);
    return _defaultManager;
}
/** Convenience shorthand for getI18n().t() */
function t(key, values) {
    return getI18n().t(key, values);
}
/* ── Built-in engine translations ─────────────────────────────── */
/** Core engine UI strings in English */
const ENGINE_TRANSLATIONS_EN = {
    editor: {
        tools: {
            select: 'Select',
            move: 'Move',
            rotate: 'Rotate',
            scale: 'Scale',
            pan: 'Pan',
        },
        panels: {
            hierarchy: 'Hierarchy',
            inspector: 'Inspector',
            assets: 'Assets',
            console: 'Console',
            viewport: 'Viewport',
        },
        actions: {
            save: 'Save',
            undo: 'Undo',
            redo: 'Redo',
            copy: 'Copy',
            paste: 'Paste',
            delete: 'Delete',
            duplicate: 'Duplicate',
            play: 'Play',
            pause: 'Pause',
            stop: 'Stop',
        },
        messages: {
            noSelection: 'No selection',
            unsavedChanges: 'You have unsaved changes. Save before closing?',
            projectSaved: 'Project saved successfully!',
            assetImported: '{{count}} asset(s) imported',
        },
    },
    game: {
        menu: {
            start: 'Start Game',
            resume: 'Resume',
            restart: 'Restart',
            quit: 'Quit',
            settings: 'Settings',
            controls: 'Controls',
        },
        hud: {
            score: 'Score: {{score}}',
            lives: 'Lives: {{lives}}',
            level: 'Level {{level}}',
            time: 'Time: {{time}}',
            wave: 'Wave {{wave}}',
        },
        items_one: '{{count}} item',
        items_other: '{{count}} items',
        players_one: '{{count}} player',
        players_other: '{{count}} players',
    },
    accessibility: {
        colorblind: {
            protanopia: 'Protanopia',
            deuteranopia: 'Deuteranopia',
            tritanopia: 'Tritanopia',
            achromatopsia: 'Achromatopsia',
        },
        difficulty: {
            easy: 'Easy',
            medium: 'Medium',
            hard: 'Hard',
            custom: 'Custom',
        },
        settings: {
            highContrast: 'High Contrast',
            screenReader: 'Screen Reader',
            subtitles: 'Subtitles',
            fontSize: 'Font Size',
        },
    },
};
/** Core engine UI strings in Polish */
const ENGINE_TRANSLATIONS_PL = {
    editor: {
        tools: {
            select: 'Zaznacz',
            move: 'Przesuń',
            rotate: 'Obróć',
            scale: 'Skaluj',
            pan: 'Przesuń widok',
        },
        panels: {
            hierarchy: 'Hierarchia',
            inspector: 'Inspektor',
            assets: 'Zasoby',
            console: 'Konsola',
            viewport: 'Widok',
        },
        actions: {
            save: 'Zapisz',
            undo: 'Cofnij',
            redo: 'Ponów',
            copy: 'Kopiuj',
            paste: 'Wklej',
            delete: 'Usuń',
            duplicate: 'Duplikuj',
            play: 'Graj',
            pause: 'Pauza',
            stop: 'Stop',
        },
        messages: {
            noSelection: 'Brak zaznaczenia',
            unsavedChanges: 'Masz niezapisane zmiany. Zapisać przed zamknięciem?',
            projectSaved: 'Projekt zapisany!',
            assetImported: 'Zaimportowano {{count}} zasób/zasobów',
        },
    },
    game: {
        menu: {
            start: 'Rozpocznij grę',
            resume: 'Wznów',
            restart: 'Od nowa',
            quit: 'Wyjdź',
            settings: 'Ustawienia',
            controls: 'Sterowanie',
        },
        hud: {
            score: 'Wynik: {{score}}',
            lives: 'Życia: {{lives}}',
            level: 'Poziom {{level}}',
            time: 'Czas: {{time}}',
            wave: 'Fala {{wave}}',
        },
        items_one: '{{count}} element',
        items_few: '{{count}} elementy',
        items_many: '{{count}} elementów',
        items_other: '{{count}} elementów',
        players_one: '{{count}} gracz',
        players_few: '{{count}} graczy',
        players_many: '{{count}} graczy',
        players_other: '{{count}} graczy',
    },
    accessibility: {
        colorblind: {
            protanopia: 'Protanopia',
            deuteranopia: 'Deuteranopia',
            tritanopia: 'Tritanopia',
            achromatopsia: 'Achromatopsja',
        },
        difficulty: {
            easy: 'Łatwy',
            medium: 'Średni',
            hard: 'Trudny',
            custom: 'Własny',
        },
        settings: {
            highContrast: 'Wysoki kontrast',
            screenReader: 'Czytnik ekranowy',
            subtitles: 'Napisy',
            fontSize: 'Rozmiar czcionki',
        },
    },
};
/** Core engine UI strings in German */
const ENGINE_TRANSLATIONS_DE = {
    editor: {
        tools: {
            select: 'Auswählen',
            move: 'Verschieben',
            rotate: 'Drehen',
            scale: 'Skalieren',
            pan: 'Schwenken',
        },
        panels: {
            hierarchy: 'Hierarchie',
            inspector: 'Inspektor',
            assets: 'Ressourcen',
            console: 'Konsole',
            viewport: 'Ansicht',
        },
        actions: {
            save: 'Speichern',
            undo: 'Rückgängig',
            redo: 'Wiederholen',
            copy: 'Kopieren',
            paste: 'Einfügen',
            delete: 'Löschen',
            duplicate: 'Duplizieren',
            play: 'Spielen',
            pause: 'Pause',
            stop: 'Stoppen',
        },
        messages: {
            noSelection: 'Keine Auswahl',
            unsavedChanges: 'Sie haben ungespeicherte Änderungen. Vor dem Schließen speichern?',
            projectSaved: 'Projekt erfolgreich gespeichert!',
            assetImported: '{{count}} Ressource(n) importiert',
        },
    },
    game: {
        menu: {
            start: 'Spiel starten',
            resume: 'Fortsetzen',
            restart: 'Neustart',
            quit: 'Beenden',
            settings: 'Einstellungen',
            controls: 'Steuerung',
        },
        hud: {
            score: 'Punkte: {{score}}',
            lives: 'Leben: {{lives}}',
            level: 'Level {{level}}',
            time: 'Zeit: {{time}}',
            wave: 'Welle {{wave}}',
        },
        items_one: '{{count}} Element',
        items_other: '{{count}} Elemente',
        players_one: '{{count}} Spieler',
        players_other: '{{count}} Spieler',
    },
    accessibility: {
        colorblind: {
            protanopia: 'Protanopie',
            deuteranopia: 'Deuteranopie',
            tritanopia: 'Tritanopie',
            achromatopsia: 'Achromatopsie',
        },
        difficulty: {
            easy: 'Leicht',
            medium: 'Mittel',
            hard: 'Schwer',
            custom: 'Benutzerdefiniert',
        },
        settings: {
            highContrast: 'Hoher Kontrast',
            screenReader: 'Bildschirmleser',
            subtitles: 'Untertitel',
            fontSize: 'Schriftgröße',
        },
    },
};
/** Register built-in translations on an I18nManager instance */
function registerEngineTranslations(i18n) {
    i18n.addTranslations('engine', 'en', ENGINE_TRANSLATIONS_EN);
    i18n.addTranslations('engine', 'pl', ENGINE_TRANSLATIONS_PL);
    i18n.addTranslations('engine', 'de', ENGINE_TRANSLATIONS_DE);
}

exports.ENGINE_TRANSLATIONS_DE = ENGINE_TRANSLATIONS_DE;
exports.ENGINE_TRANSLATIONS_EN = ENGINE_TRANSLATIONS_EN;
exports.ENGINE_TRANSLATIONS_PL = ENGINE_TRANSLATIONS_PL;
exports.I18nManager = I18nManager;
exports.LOCALE_NAMES = LOCALE_NAMES;
exports.RTL_LOCALES = RTL_LOCALES;
exports.SUPPORTED_LOCALES = SUPPORTED_LOCALES;
exports.getI18n = getI18n;
exports.initI18n = initI18n;
exports.registerEngineTranslations = registerEngineTranslations;
exports.t = t;
//# sourceMappingURL=I18n.js.map
