/**
 * @mergeTarget
 * @module Src/Controllers/Translations
 */

import { AssetsLoader, CoreErrorCodes } from "@lisio/lisio-engine";
import { ErrorCodes } from "../../../misc/error-codes";
import {
  TranslationLanguages,
  Translations,
} from "./translation-languages-enum-and-types";

/**
 * Class representing a translation controller.\
 * It aims to centralize the logic of transalting all texts of interfaces linked to widget.\
 * If an interface has a text to be transalted it has to use this class.\
 * To better performance and ecological conception, translation files will be laoded dynamically if it's needed.
 * To add a new language, create a json file in langs folder. It need to be named with his ISO code as follows : en.json. For more information of file's strucuture, please see {@link Src/Controllers/Translations.Translations | Translations}.
 * To execute his responsability this class does :
 *  * Load translation files
 *  * Retrieve translated texts in file
 */
class TranslationController {
  /**
   * Private attribute to store translations
   * @source
   */
  private _translations?: Translations;

  /**
   * Private attribute to store the default lang
   * @source
   */
  private _defaultLang?: TranslationLanguages;

  /**
   * @static
   * Private attribute to store instance of {@link TranslationController | TranslationController}
   * @source
   */
  private static _current: TranslationController;

  /**
   * @static
   * Getter for attribute {@link _current | _current}
   * @returns Returns _current attribute
   * @source
   */
  public static get current(): TranslationController {
    return this._current;
  }

  /**
   * Getter for attribute {@link _defaultLang | _defaultLang}
   * @returns Returns _defaultLang attribute
   * @source
   */
  public get defaultLang(): String | undefined {
    return this._defaultLang;
  }

  /**
   * @static
   * Setter for attribute {@link _defaultLang | _defaultLang}
   * @source
   */
  public set defaultLang(lang: TranslationLanguages) {
    this._defaultLang = lang;
  }

  /**
   * Public method to retrieve translation of a desired text based on an id
   * @param {string} textId - Id of desired text to be translated
   * @returns Returns translation of desired text
   * @throws {Error} If translation file is missing (see {@link Src/Utils.ErrorCodes.TRANSLATIONS_NOT_LOADED | ErrorCodes.TRANSLATIONS_NOT_LOADED}) or a text id is missing (see {@link Src/Utils.ErrorCodes.TRANSLATION_NOT_FOUND | ErrorCodes.TRANSLATION_NOT_FOUND})
   * @source
   */
  public getTranslation(textId: string): string {
    if (this._translations != undefined) {
      const translation: string | undefined = this._translations[textId];
      if (translation == undefined) {
        throw new Error(
          `Code : ${ErrorCodes.TRANSLATION_NOT_FOUND}. No translation available for text id : ${textId}`,
        );
      } else {
        return translation;
      }
    } else {
      throw new Error(
        `Code : ${ErrorCodes.TRANSLATIONS_NOT_LOADED}. Translations file not loaded`,
      );
    }
  }

  /**
   * @async
   * Public method to laod translation file
   * @param {TranslationLanguages} lang - ISO of desired language
   * @returns Returns a promise containing nothing
   * @throws If status of response is 404 see {@link Src/Utils.ErrorCodes.TRANSLATIONS_FILE_NOT_FOUND | ErrorCodes.TRANSLATIONS_FILE_NOT_FOUND}, if is 500 basic internal error
   * @source
   */
  public async loadTranslationFile(lang: TranslationLanguages): Promise<void> {
    if (lang == TranslationLanguages.DEFAULT) {
      this._translations = await AssetsLoader.current
        .loadAsset<Translations>(`./langs/${this._defaultLang}.json`)
        .catch(() => {
          throw new Error(
            `Code : ${ErrorCodes.TRANSLATIONS_FILE_NOT_FOUND}. Asset file not found : ${this._defaultLang}`,
          );
        });
    } else {
      this._translations = await AssetsLoader.current
        .loadAsset<Translations>(`./langs/${lang}.json`)
        .catch(() => {
          throw new Error(
            `Code : ${ErrorCodes.TRANSLATIONS_FILE_NOT_FOUND}. Asset file not found : ${lang}`,
          );
        });
    }
  }

  /**
   * Constructor of class {@link TranslationController | TranslationController}
   * @throws If singleton already initialize.\
   * See {@link https://env-preprod-docs.lisio.fr/lisio-engine/enums/Src_Core.CoreErrorCodes.html#SINGLETON_NOT_UNIQUE | CoreErrorCodes.SINGLETON_NOT_UNIQUE}
   * @source
   */
  constructor() {
    if (TranslationController._current == undefined) {
      TranslationController._current = this;
    } else {
      throw new Error(
        `Code : ${CoreErrorCodes.SINGLETON_NOT_UNIQUE}. Singleton already initialize`,
      );
    }
  }
}

export { TranslationController, TranslationLanguages };
