const counterpart = require('counterpart');

const DEFAULT_LOCALE = "en";

function _td(text) {
    return _t(text);
}

function _t(text, variables = {}) {
    const args = Object.assign({ interpolate: false }, variables);

    const { count } = args;

    // Horrible hack to avoid https://github.com/vector-im/element-web/issues/4191
    // The interpolation library that counterpart uses does not support undefined/null
    // values and instead will throw an error. This is a problem since everywhere else
    // in JS land passing undefined/null will simply stringify instead, and when converting
    // valid ES6 template strings to i18n strings it's extremely easy to pass undefined/null
    // if there are no existing null guards. To avoid this making the app completely inoperable,
    // we'll check all the values for undefined/null and stringify them here.
    Object.keys(args).forEach((key) => {
        if (args[key] === undefined) {
            console.warn("safeCounterpartTranslate called with undefined interpolation name: " + key);
            args[key] = 'undefined';
        }
        if (args[key] === null) {
            console.warn("safeCounterpartTranslate called with null interpolation name: " + key);
            args[key] = 'null';
        }
    });
    let translated = counterpart.translate(text, args);
    if (translated === undefined && count !== undefined) {
        // counterpart does not do fallback if no pluralisation exists
        // in the preferred language, so do it here
        translated = counterpart.translate(text, Object.assign({}, args, {locale: DEFAULT_LOCALE}));
    }

    // The translation returns text so there's no XSS vector here (no unsafe HTML, no code execution)
    return translated;
}

class AppLocalization {
    static STORE_KEY = "locale"
    #store = null

    constructor({ store, components = [] }) {
        counterpart.registerTranslations("en", this.fetchTranslationJson("en_EN"));
        counterpart.setFallbackLocale('en');
        counterpart.setSeparator('|');

        if (Array.isArray(components)) {
            this.localizedComponents = new Set(components);
        }

        this.#store = store;
        if (this.#store.has(AppLocalization.STORE_KEY)) {
            const locales = this.#store.get(AppLocalization.STORE_KEY);
            this.setAppLocale(locales);
        }

        this.resetLocalizedUI();
    }

    fetchTranslationJson(locale) {
        try {
            console.log("Fetching translation json for locale: " + locale);
            return require(`./i18n/strings/${locale}.json`);
        } catch (e) {
            console.log(`Could not fetch translation json for locale: '${locale}'`, e);
            return null;
        }
    }

    get languageTranslationJson() {
        return this.translationJsonMap.get(this.language);
    }

    setAppLocale(locales) {
        console.log(`Changing application language to ${locales}`);

        if (!Array.isArray(locales)) {
            locales = [locales];
        }

        locales.forEach(locale => {
            const translations = this.fetchTranslationJson(locale);
            if (translations !== null) {
                counterpart.registerTranslations(locale, translations);
            }
        });

        counterpart.setLocale(locales);
        this.#store.set(AppLocalization.STORE_KEY, locales);

        this.resetLocalizedUI();
    }

    resetLocalizedUI() {
        console.log("Resetting the UI components after locale change");
        this.localizedComponents.forEach(componentSetup => {
            if (typeof componentSetup === "function") {
                componentSetup();
            }
        });
    }
}


module.exports = {
    AppLocalization,
    _t,
    _td,
};