import LisioMessageReceivedName from "../enums/lisio-message-received-name";
import LisioPopinNames from "../enums/lisio-popin-names";
import { LisioConfig } from "../lisio-config";
import { TabsToHide, lisioGetInitLang } from "../utils";

interface LisioInitBackMessageDatas {
  bookPageUrlQueries: string[];
  categoriesToHide: string[];
  colors: {
    primary: string;
    eco: string;
  };
  compensation: boolean;
  eventShortcutTo: number;
  isReferrerBookPage: boolean;
  origin: string;
  originDomain: string;
  parametersToHide: string[];
  popinUsed: LisioPopinNames;
  priorizedLanguages: string[];
  profilesToHide: string[];
  shortcutTo: string;
  statisticsAPIURL: string;
  topBarImg: string | undefined;
  translationMode: "google_translation" | "deepl_translation" | "none";
  url: string;
  widgetLang: string;
  widgetVersion: number;
}

interface LisioMessage {
  datas: string;
  name: LisioMessageReceivedName;
  target: "light" | "full";
}

class LisioLightMessageManager {
  private static _current: LisioLightMessageManager;

  private _contentWindow?: Window;
  private _lisioServerIframe = "";
  private _messageHandlers: Map<
    LisioMessageReceivedName,
    (datas: string) => void
  > = new Map<LisioMessageReceivedName, (datas: string) => void>();

  private constructor() {
    this._lisioServerIframe = import.meta.env.VITE_SERVER_IFRAME;
    window.addEventListener("message", (event: MessageEvent) => {
      if(event.origin === this._lisioServerIframe && event.data.target === "light"){
        const message: LisioMessage = event.data;
        if (message.name == undefined) {
          throw new Error("Message name is not defined : " + JSON.stringify(message));
        } else {
          const handler = this._messageHandlers.get(message.name);
          if (handler == undefined) {
            throw new Error("Message handler is not defined");
          } else {
            handler(message.datas);
          }
        }
      }
    });
  }

  public static get current(){
    if (!this._current) {
      this._current = new LisioLightMessageManager();
    }
    return this._current;
  }

  public set contentWindow(value: Window){
    this._contentWindow = value;
  }

  public attachHandler(
    name: LisioMessageReceivedName,
    handler: (datas: string) => void,
  ) {
    this._messageHandlers.set(name, handler);
  }

  public detachHandler(name: LisioMessageReceivedName) {
    this._messageHandlers.delete(name);
  }

  public sendPopinReady(){
    this.sendMessage("popin_ready", {});
  }

  public sendInitBackMessage(
    shortcutTo: string,
    eventShortcutTo: number,
    dataHide: TabsToHide,
    originDomain: string,
    lisioConfig: LisioConfig,
    popinUsed: LisioPopinNames
  ) {
    const initMessage: { name: string; datas: LisioInitBackMessageDatas } = {
      name: "init_back",
      datas: {
        origin:
          window.location.origin == "null" ? "*" : `${window.location.origin}/`,
        widgetVersion: parseInt(lisioConfig.userSettings.display),
        widgetLang: lisioGetInitLang(),
        translationMode: dataHide.translationMode,
        priorizedLanguages: lisioConfig.userSettings.priorizedLanguages,
        statisticsAPIURL: `${import.meta.env.VITE_PHP_SERVER}/addStats.php`,
        colors: {
          primary: lisioConfig.userSettings.colorPrimary,
          eco: lisioConfig.userSettings.colorEcolo,
        },
        profilesToHide: dataHide.profilesToHide,
        categoriesToHide: dataHide.categoriesToHide,
        parametersToHide: dataHide.parametersToHide,
        compensation: dataHide.compensation,
        topBarImg:
          lisioConfig.userSettings.top_bar_img === ""
            ? undefined
            : lisioConfig.userSettings.top_bar_img,
        isReferrerBookPage: document.referrer == import.meta.env.VITE_PHP_SERVER,
        bookPageUrlQueries: [],
        url: window.location.origin + window.location.pathname,
        shortcutTo: shortcutTo,
        eventShortcutTo: eventShortcutTo,
        originDomain,
        popinUsed
      },
    };

    const navigationEntries = performance.getEntriesByType("navigation");
    if (
      navigationEntries.length > 0 &&
      (navigationEntries[0] as PerformanceNavigationTiming).type ===
        "navigate" &&
      !document.referrer.includes(window.location.origin) &&
      (document.referrer.includes(import.meta.env.VITE_PHP_SERVER) ||
        import.meta.env.VITE_PHP_SERVER.includes(window.location.origin))
    ) {
      const urlQueries = window.location.search.split("&");
      const usernamesInQuery = urlQueries.find((urlQuery) =>
        urlQuery.startsWith("lisioUsernames%3D"),
      );
      const userInQuery = urlQueries.find((urlQuery) =>
        urlQuery.startsWith("lisioUsers%3D"),
      );
      if (usernamesInQuery != undefined && userInQuery != undefined) {
        const usernamesUrlQuery = decodeURIComponent(usernamesInQuery);
        const usersUrlQuery = decodeURIComponent(userInQuery);
        if (usernamesUrlQuery != undefined && usersUrlQuery != undefined) {
          initMessage.datas.bookPageUrlQueries.push(
            usernamesUrlQuery,
            usersUrlQuery,
          );
        }
      }
    }
    this.sendMessage(initMessage.name, initMessage.datas);
  }

  public sendLisioFrontLoaded() {
    this.sendMessage("lisio_front_loaded", {});
  }

  public sendLoadWidget() {
    this.sendMessage("load_widget", {});
  }

  public sendShortcutMessageToIframe(screenName: string, eventDetail: number) {
    this.sendMessage("shortcut_to", {
      screenName,
      eventDetail,
    });
  }

  public sendDisableMessageToIframe() {
    this.sendMessage("disable", {});
  }

  private sendMessage(name: string, datas: object) {
    this._contentWindow?.postMessage(
      {
        name,
        datas: JSON.stringify(datas),
      },
      this._lisioServerIframe,
    );
  }
}

export default LisioLightMessageManager;
