"use strict";

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

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

/**
 * @class SettingsManager
 * @constructor
 * @param {!OpoTests} ot 
 * @param {?(Object.<string, any|null>|Array.<any|null>)} customs
 * @returns {void}
 * @access public
 * @static
 */
export const SettingsManager = (function(){

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

    /**
     * @constructs SettingsManager
     * @param {!OpoTests} ot 
     * @param {?(Object.<string, any|null>|Array.<any|null>)} customs
     * @returns {void}
     * @access private
     * @static
     */
    const SettingsManager = function(ot, customs = null){

        /** @type {SettingsManager} */
        const self = this, 
              /** @type {Object.<string, any|null>} */
              settings = {}, 
              /** @type {Object.<string, any|null>} */
              secrets = {};

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

            customs = Utils.get_dictionary(customs);

        };

        /**
         * @param {?settings_manager_default_callback} [callback = null] 
         * @returns {void}
         * @access public
         */
        this.start = (callback = null) => {
            Utils.execute_array([
                "default_settings_files", "settings_files"
            ], (key, next_callback) => {
                self.add(self.get(key), next_callback, true);
            }, () => {
                Utils.execute_array([
                    "default_secrets_files", "secrets_files"
                ], (key, next_callback) => {
                    self.add_secrets(self.get(key), next_callback, true);
                }, callback);
            });
        };

        /**
         * @param {!(string|Array.<string>)} keys 
         * @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null] 
         * @param {?any} [_default = null] 
         * @returns {any|null}
         * @access public
         */
        this.get = (keys, inputs = null, _default = null) => (
            Utils.get_value(keys, [inputs, customs, secrets, settings, SettingsManager.DEFAULT_SETTINGS], _default)
        );
        
        /**
         * @param {!(Object.<string, Object.<string, string|Array.<string>|null>>|Array.<any|null>|string)} inputs 
         * @param {?i18n_manager_default_callback} callback 
         * @param {!boolean} overwrite 
         * @returns {void}
         * @access public
         */
        this.add = (inputs, callback = null, overwrite = false) => {
            ot.load_json(inputs, (item, next_callback) => {
                for(key in item)
                    (overwrite || Check.is_null_or_undefined(settings[key])) && 
                    (settings[key] = item[key]);
                next_callback();
            }, callback, true);
        };
        
        /**
         * @param {!(Object.<string, any|null>|Array.<any|null>|string)} inputs 
         * @param {?settings_manager_default_callback} [callback = null] 
         * @param {!boolean} [overwrite = false] 
         * @returns {void}
         * @access public
         */
        this.add_secrets = (inputs, callback = null, overwrite = false) => {
            ot.load_json(inputs, (item, next_callback) => {
                for(const key in item)
                    (overwrite || Check.is_null_or_undefined(secrets[key])) && 
                    (secrets[key] = item[key]);
                next_callback();
            }, callback, true);
        };

        constructor();

    };

    /** @type {Object.<string, any|null>} */
    SettingsManager.DEFAULT_SETTINGS = {
        /** @type {Array.<string>|string|Object.<string, any|null>} */
        default_settings_files : ["/json/OpoTests.settings.json"],
        /** @type {Array.<string>|string|Object.<string, any|null>} */
        default_secrets_files : ["/json/OpoTests.secrets.json"],
        /** @type {Array.<string>|string|Object.<string, any|null>} */
        default_i18n_files : [
            "/json/i18n/OpoTests.i18n.espanol.json", 
            "/json/i18n/OpoTests.i18n.galego.json", 
            "/json/i18n/OpoTests.i18n.english.json"
        ],
        /** @type {Array.<string>|string|Object.<string, any|null>} */
        default_database_files : ["/json/database.json"],
    };

    return SettingsManager;
})();