/**
 * @mergeTarget
 * @module Src/Messages/Received/Handlers
 */

import {
  LisioBooleanParameterNames,
  LisioCategoryNames,
  // LisioParameterFactory,
  LisioStringParameterNames,
} from "@lisio/lisio-profils";
import {
  LisioWidgetVersionNames,
  WidgetVersion,
  numberToVersion,
} from "../../versions/widget-version";
import { LisioWidgetVersionFactory } from "../../versions/widget-version-factory";
import { MessageManager } from "../../managers/message-manager";
import { ScreenManager } from "../../managers/screen-manager";
import {
  TranslationController,
  TranslationLanguages,
} from "../../controllers/translation/translation-controller";
import {
  fetchWithTimeout,
  trapKeyDown,
} from "../../../misc/functions";
import { StatisticsController } from "../../controllers/statistics-controller";
import { InitMessageDatas } from "../message-types";
import { CustomNav } from "../../render/components/custom-nav/custom-nav";
import { UserController } from "../../controllers/user-controller";
import { InputManager } from "../../managers/input-manager";
import { CustomHeader } from "../../render/components/custom-header/custom-header";
import { LisioComponentStyles, Engine } from "@lisio/lisio-engine";
import { getDirection } from "../../controllers/translation/translation-languages-enum-and-types";
import { ScreenNames } from "../../render/screens/screen-types";

let alreadyReceived: boolean = false;

/**
 * Handler for received message {@link Src/Messages/Received.ReceivedMessageNames.INIT_BACK | INIT_BACK}.\
 * This function initialize the widget with all his necessary components.\
 * To go into details :
 *  * Initialize {@link Src/Controllers/Translations.TranslationController | TranslationController} in the desired lang
 *  * Use method {@link Src/Managers.MessageManager | MessageManager} for send to client script all needed translations
 *  * If is needed, widget synchronize his cookies and local storage from those (if exists) passed in url by book page
 *  * Initialize {@link Src/Controllers.StatisticsController | StatisticsController}
 *  * Determine if client use google or deepl translation
 *  * Initialize CSS and HTML renderer
 *  * Determine and initialize which {@link Src/Versions.WidgetVersion | WidgetVersion} is used
 *  * Initialize {@link Src/Managers.ScreenManager | ScreenManager}
 * @async
 * @param {MessageManager} this - Context of {@link Src/Managers.MessageManager | MessageManager}
 * @param {string} datas - Additional datas sent by client script.\
 *  Datas contains : {@link Src/Messages/Types.InitMessageDatas | InitMessageDatas}
 * @returns Returns a promise containing nothing
 * @source
 */
async function initMessageHandler(
  this: MessageManager,
  datas: string,
): Promise<void> {
  if (!alreadyReceived) {
    alreadyReceived = true;
    const parsedDatas: InitMessageDatas = JSON.parse(datas);
    const convertedVersion: LisioWidgetVersionNames | undefined =
      numberToVersion.get(parsedDatas.widgetVersion);
    if (convertedVersion == undefined) {
      throw new Error("Version doesn't exist");
    }
    const version: WidgetVersion =
      LisioWidgetVersionFactory.current.buildLisioWidgetVersion(
        convertedVersion,
      );
    if (convertedVersion === LisioWidgetVersionNames.WELCOME) {
      parsedDatas.translationMode = LisioCategoryNames.DEEPL_TRANSLATION;
    }

    const authorizedLanguagesISOs: string[] = [];

    if (parsedDatas.bookPageUrlQueries.length > 0) {
      await UserController.current.synchronizeFromUrlQuery(
        parsedDatas.bookPageUrlQueries,
      );
    }

    const hasGoogle = UserController.current.currentUser?.customParameters.has(
      LisioStringParameterNames.GOOGLE_TRANSLATION,
    );
    const hasDeepl = UserController.current.currentUser?.customParameters.has(
      LisioStringParameterNames.DEEPL_TRANSLATION,
    );

    const [red, blue, green] = LisioComponentStyles.convertHexToRGB(
      parsedDatas.colors.primary.slice(1),
    );

    Engine.current.initRoot({
      ":root": {
        "--lisio-background-color-primary": "#EDEDED",
        // "--lisio-background-color-primary": "#EEEEEE",
        "--lisio-color-primary": parsedDatas.colors.primary,
        "--lisio-color-logo":
          parsedDatas.colors.primary === "#005282"
            ? parsedDatas.colors.primary
            : "#646464",
        "--lisio-color-green": parsedDatas.colors.eco,
        "--lisio-color-active": `rgb(${red * 0.5 + 255 * 0.5}, ${
          blue * 0.5 + 255 * 0.5
        }, ${green * 0.5 + 255 * 0.5})`,
        "--lisio-color-primary-hover": `rgba(${red}, ${blue}, ${green}, 0.5)`,
        "--lisio-color-primary-black-hover": `rgba(${red / 1.5}, ${
          blue / 1.5
        }, ${green / 1.5})`,
        "--lisio-switch-track-primary": `rgba(${red}, ${blue}, ${green}, 0.5)`,
      },
    });

    new StatisticsController(parsedDatas.statisticsAPIURL, parsedDatas.origin);
    if (
      parsedDatas.translationMode === LisioCategoryNames.DEEPL_TRANSLATION &&
      parsedDatas.originDomain != ""
    ) {
      try {
        const response = await fetchWithTimeout(
          `${
            import.meta.env.VITE_URL_TRANSLATOR_API
          }/api/languages/checkIfAuthorized?domainName=${
            parsedDatas.originDomain
          }`,
          {
            method: "GET",
            headers: {
              Authorization: `Bearer ${
                import.meta.env.VITE_SECRET_TRANSLATOR_API
              }`,
              "Content-Type": "application/json",
            },
            timeout: 5000,
          },
        )
          .then((datas) => {
            if (datas.status === 200) {
              return datas.json();
            } else {
              throw { code: datas.status, message: datas.statusText };
            }
          })
          .catch((err) => {
            throw err;
          });
        if (response.datas == undefined) {
          throw { code: 500 };
        } else {
          for (const language of JSON.parse(response.datas)) {
            const languageISO =
              parsedDatas.translationMode ===
              LisioCategoryNames.DEEPL_TRANSLATION
                ? language.languageDTO.languageISO.replace("-", "_")
                : language.languageDTO.languageISO;
            authorizedLanguagesISOs.push(languageISO);
          }
        }
      } catch (error: any) {
        parsedDatas.translationMode = undefined;
      }
    }

    let widgetLang = parsedDatas.widgetLang;
    if (
      hasDeepl &&
      UserController.current.currentUser?.customParameters.has(
        LisioBooleanParameterNames.IS_ACTIVE,
      ) &&
      parsedDatas.translationMode === LisioCategoryNames.DEEPL_TRANSLATION
    ) {
      const tmplang =
        TranslationLanguages[
          (
            UserController.current.currentUser?.customParameters.get(
              LisioStringParameterNames.DEEPL_TRANSLATION,
            )?.value as string
          ).toUpperCase() as keyof typeof TranslationLanguages
          // .split("_")[0] as keyof typeof TranslationLanguages
        ];
      const isDeeplLangAuthorized = authorizedLanguagesISOs.includes(tmplang);
      if (tmplang && isDeeplLangAuthorized) {
        widgetLang = tmplang;
      }
    } else if (
      hasGoogle &&
      UserController.current.currentUser?.customParameters.has(
        LisioBooleanParameterNames.IS_ACTIVE,
      ) &&
      parsedDatas.translationMode === LisioCategoryNames.GOOGLE_TRANSLATION
    ) {
      const tmplang =
        TranslationLanguages[
          (
            UserController.current.currentUser?.customParameters.get(
              LisioStringParameterNames.GOOGLE_TRANSLATION,
            )?.value as string
          ).toUpperCase() as keyof typeof TranslationLanguages
          // .split("_")[0] as keyof typeof TranslationLanguages
        ];
      if (tmplang) {
        widgetLang = tmplang;
      }
    }
    new TranslationController();
    TranslationController.current.defaultLang = parsedDatas.widgetLang;
    await TranslationController.current
      .loadTranslationFile(widgetLang)
      .catch((error: Error) => {
        console.log(error);
        return;
      });
    MessageManager.current.langIso = widgetLang;
    MessageManager.current.flagIso = widgetLang;
    MessageManager.current.defaultFlagIso = widgetLang;
    MessageManager.current.sendTranslationLanguageChangeMessage();
    document
      .querySelector("html")
      ?.setAttribute("dir", getDirection(widgetLang));
    document
      .querySelector("html")
      ?.setAttribute("lang", widgetLang.replace("_", "-"));
    document.title =
      TranslationController.current.getTranslation("iframeTitle");
    this.originOfMessages = parsedDatas.origin;
    this.originDomain = parsedDatas.originDomain;

    // document.body.addEventListener("keydown", trapInto);
    document.addEventListener("keydown", trapKeyDown, true)

    const header: CustomHeader = new CustomHeader(parsedDatas.topBarImg);
    await Engine.current.renderComponent(header, true, "append");

    new ScreenManager(version, header);
    await version.initialize(
      {
        categoriesToHide:
          parsedDatas.categoriesToHide == undefined
            ? []
            : parsedDatas.categoriesToHide,
        profilesToHide:
          parsedDatas.profilesToHide == undefined
            ? []
            : parsedDatas.profilesToHide,
        parametersToHide:
          parsedDatas.parametersToHide == undefined
            ? []
            : parsedDatas.parametersToHide,
      },
      parsedDatas.translationMode === "none"
        ? undefined
        : parsedDatas.translationMode,
      parsedDatas.priorizedLanguages,
      authorizedLanguagesISOs,
      parsedDatas.compensation,
      parsedDatas.popinUsed === "popin2025",
    );

    let nav: CustomNav | undefined = undefined;
    nav = new CustomNav(
      Array.from(version.screens.keys()).filter(
        (screen) => !version.screensToIgnoreInNav.includes(screen),
      ),
      parsedDatas.popinUsed === "popin2025",
      convertedVersion == "complete" ? "ecological" : "light_ecological",
    );
    await Engine.current.renderComponent(nav, true, "append");
    ScreenManager.current.nav = nav;

    if (
      version.mainScreen != undefined &&
      version.mainScreen.componentName != "home-screen"
    ) {
      nav?.toggleNav(true);
      nav?.selectTab(version.mainScreen.componentName);
      header.toggleHomeButton(true);
    }

    if (version.mainScreen != undefined) {
      await Engine.current.renderComponent(
        version.mainScreen,
        true,
        "append",
        undefined,
        false,
        true,
      );
    }

    if (
      parsedDatas.shortcutTo != undefined &&
      Object.values(ScreenNames).includes(parsedDatas.shortcutTo)
    ) {
      ScreenManager.current.changeScreen(
        parsedDatas.shortcutTo,
        parsedDatas.eventShortcutTo,
      );
    }

    InputManager.current.initInputs();
    /**
     * On garde toujours l'histoire de la bannière et de la réduction CO2 ? Oui
     */
    /**
     * Logo du widget changeable ? Oui
     */
    this.sendActiveResponseMessage();
  }
}

export { initMessageHandler };
