"use strict";

import {Check} from "../Utils/Check.ecma.js";
import {Utils} from "../Utils/Utils.ecma.js";

/**
 * @typedef {import("../Application/OpoTests.ecma.js").OpoTests} OpoTests
 */

/**
 * @class I18NManager
 * @constructor
 * @param {!OpoTests} ot 
 * @returns {void}
 * @access public
 * @static
 */
export const I18NManager = (function(){

    /**
     * @callback i18n_manager_default_callback
     * @returns {void}
     */

    /**
     * @constructs I18NManager
     * @param {!OpoTests} ot 
     * @returns {void}
     * @access private
     * @static
     */
    const I18NManager = function(ot){

        /** @type {I18NManager} */
        const self = this, 
              /** @type {Object.<string, Object.<string, string|Array.<string>>} */
              sentences = {};
        /** @type {string} */
        let language_selected = "espanol", 
            /** @type {string} */
            default_language = "espanol";

        /**
         * @returns {void}
         * @access private
         */
        const constructor = () => {

            language_selected = ot.settings.get(["language_selected", "default_language"], null, language_selected);
            default_language = ot.settings.get(["default_language", "language_selected"], null, default_language);

        };

        /**
         * @param {?i18n_manager_default_callback} [callback = null] 
         * @returns {void}
         * @access public
         */
        this.start = (callback = null) => {
            Utils.execute_array([
                "default_i18n_files", "i18n_files"
            ], (key, next_callback) => {
                self.add(ot.settings.get(key), next_callback, true);
            }, callback);
        };

        /**
         * @param {!(string|Array.<string>)} texts 
         * @param {?(Object.<string, any|null>|Array.<any|null>)} [variables = null] 
         * @param {?any} [_default = null] 
         * @returns {string|null}
         * @access public
         */
        this.get = (texts, variables = null, _default = null) => {

            /** @type {string|Array.<string>|null} */
            let text = null;
            /** @type {Array.<string>} */
            const used = [], 
                  /** @type {Array.<string>} */
                  languages = [language_selected, default_language].concat(Object.keys(sentences)), 
                  /** @type {Array.<string>} */
                  keys = Utils.get_keys(texts);
                  
            if(keys.length)
                for(const language of languages){
                    if(!used.includes(language) && sentences[language])
                        for(const key of keys){
                            if(sentences[language][key] !== undefined){
                                text = sentences[language][key];
                                break;
                            };
                        };
                    if(text !== undefined)
                        break;
                    used.push(language);
                };

            text === null && (text = (
                _default !== null ? _default : 
                texts !== null ? (
                    Check.is_string(texts) ? texts : 
                    Check.is_array(texts) && texts.length ? texts[0] : 
                null) : 
            null))

            return Utils.string_variables((
                Check.is_array(text) ? text.join("") : 
            text), variables);
        };

        /**
         * @param {!(Object.<string, Object.<string, string|Array.<string>|null>>|Array.<any|null>|string)} inputs 
         * @param {?i18n_manager_default_callback} [callback = null] 
         * @param {!boolean} [overwrite = false] 
         * @returns {void}
         * @access public
         */
        this.add = (inputs, callback = null, overwrite = false) => {
            ot.load_json(inputs, (item, next_callback) => {
                for(const language in item){
                    sentences[language] || (sentences[language] = {});
                    for(const key in item[language])
                        (overwrite || Check.is_null_or_undefined(sentences[language][key])) && 
                        (sentences[language][key] = item[language][key]);
                };
                next_callback();
            }, callback, true);
        };

        constructor();

    };

    /** @type {Object.<string, any|null>} */
    I18NManager.DEFAULT_SETTINGS = {};

    return I18NManager;
})();