import {
  LisioBooleanParameterNames,
  LisioParameterNames,
} from "@lisio/lisio-profils";

import LisioMessageReceivedName from "../enums/lisio-message-received-name";
import { Lisio } from "../lisio";
import { lisioActiveResponseMessageHandler } from "./handlers/lisio-active-response-message-handler";
import { lisioBulkFeaturesMessageHandler } from "./handlers/lisio-bulk-features-message-handler";
import { lisioCloseMessageHandler } from "./handlers/lisio-close-widget-message-handler";
import { lisioDisableAllMessageHandler } from "./handlers/lisio-disable-all-message-handler";
import { lisioEncodeProfilesResponseMessageHandler } from "./handlers/lisio-encode-profiles-response-message-handler";
import { lisioFeatureMessageHandler } from "./handlers/lisio-feature-message-handler";
import { lisioInitFrontMessageHandler } from "./handlers/lisio-init-front-message-handler";
import { lisioNewTabMessageHandler } from "./handlers/lisio-new-tab-message-handler";
import { lisioReadingModeResponseMessageHandler } from "./handlers/lisio-reading-mode-response-message-handler";
import { lisioTransBannerPopupMessageHandler } from "./handlers/lisio-trans-banner-popup-message-handler";
import { lisioTranslationLanguageChangeMessageHandler } from "./handlers/lisio-translation-language-change-message-handler";
import { lisioDicoApiResponseMessageHandler } from "./handlers/lisio-dico-api-response-message-handler";

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

class LisioMessageManager {
  private static _current: LisioMessageManager;

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

  private constructor() {
    if (__BUILD_TARGET__ === "extension") {
      if (window.location.pathname === "/reading-mode.html") {
        const panelChannel = chrome.runtime.connect(chrome.runtime.id, {
          name: "broadcast-channel-side-panel",
        });
        // panelChannel.postMessage("Aragorn quel homme");
        this._channels.set("broadcast-channel-side-panel", panelChannel);
        panelChannel.onMessage.addListener((datas: LisioMessage) => {
          const message: LisioMessage = datas;
          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) {
              handler(message.datas);
            }
          }
        });
        panelChannel.onDisconnect.addListener(() => {
          console.log(
            "Message manager channel disconnected : " +
              chrome.runtime.lastError,
          );
        });

        const handler = (event: MessageEvent) => {
          if (event.data === "send_end_init_html") {
            this.sendEndInitHtml();
            window.removeEventListener("message", handler);
          }
        };

        window.addEventListener("message", handler);
      }
      const frontChannel = chrome.runtime.connect(chrome.runtime.id, {
        name: "channel-front",
      });
      window.addEventListener("lisio_open_channels", () => {
        const frontChannel = chrome.runtime.connect(chrome.runtime.id, {
          name: "channel-front",
        });
        this._channels.set("channel-front", frontChannel);
        // frontChannel.postMessage("Pour Frodon");
      });
      // frontChannel.postMessage("Pour Frodon");
      this._channels.set("channel-front", frontChannel);
      frontChannel.onMessage.addListener((datas: LisioMessage) => {
        const message: LisioMessage = datas;
        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) {
            handler(message.datas);
          }
        }
      });
    } else {
      this._lisioServerIframe = import.meta.env.VITE_SERVER_IFRAME;
      window.addEventListener("message", (event: MessageEvent) => {
        if (event.origin === this._lisioServerIframe && event.data.target === "full") {
          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 LisioMessageManager();
    }
    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 initMessages(lisio: Lisio) {
    this._messageHandlers.set(
      LisioMessageReceivedName.ACTIVE_RESPONSE,
      lisioActiveResponseMessageHandler.bind(lisio),
    );
    this._messageHandlers.set(
      LisioMessageReceivedName.CLOSE_WIDGET,
      lisioCloseMessageHandler.bind(lisio),
    );
    this._messageHandlers.set(
      LisioMessageReceivedName.DICO_API_RESPONSE,
      lisioDicoApiResponseMessageHandler.bind(lisio),
    );
    this._messageHandlers.set(
      LisioMessageReceivedName.DISABLE_ALL,
      lisioDisableAllMessageHandler.bind(lisio),
    );
    this._messageHandlers.set(
      LisioMessageReceivedName.ENCODE_PROFILES_RESPONSE,
      lisioEncodeProfilesResponseMessageHandler.bind(lisio),
    );
    this._messageHandlers.set(
      LisioMessageReceivedName.FEATURE,
      lisioFeatureMessageHandler.bind(lisio),
    );
    this._messageHandlers.set(
      LisioMessageReceivedName.BULK_FEATURES,
      lisioBulkFeaturesMessageHandler.bind(lisio),
    );
    this._messageHandlers.set(
      LisioMessageReceivedName.INIT_FRONT,
      lisioInitFrontMessageHandler.bind(lisio),
    );
    this._messageHandlers.set(
      LisioMessageReceivedName.NEW_TAB,
      lisioNewTabMessageHandler.bind(lisio),
    );
    this._messageHandlers.set(
      LisioMessageReceivedName.READING_MODE_RESPONSE,
      lisioReadingModeResponseMessageHandler.bind(lisio),
    );
    this._messageHandlers.set(
      LisioMessageReceivedName.TRANS_BANNER_POPUP,
      lisioTransBannerPopupMessageHandler.bind(lisio),
    );
    this._messageHandlers.set(
      LisioMessageReceivedName.TRANSLATION_LANGUAGE_CHANGE,
      lisioTranslationLanguageChangeMessageHandler.bind(lisio),
    );
  }

  public sendAllEncodedMessage() {
    this.sendMessage("all_encoded", {});
  }

  public sendCloseExtensionPopup() {
    this.sendMessage("close_extension_popup", {});
  }

  public sendCloseReadingModeMessage() {
    this.sendMessage("close_reading_mode", {});
  }

  public sendCloseWidgetMessage() {
    this.sendMessage("close_widget", {});
  }

  public sendDisableParameter(parameter: LisioParameterNames) {
    this.sendMessage("disable_parameter", { value: parameter });
  }

  public sendDisableReadingMaskMessage() {
    this.sendMessage("disable_reading_mask", {});
  }

  public sendEncodeProfilesMessage() {
    this.sendMessage("encode_profiles", {});
  }

  public sendEndInitHtml() {
    this.sendMessage("end_init_html", {});
  }

  public sendOpenSidePanel() {
    this.sendMessage("open_side", {});
  }

  public sendPopupResponse(
    value: boolean,
    parameter:
      | LisioBooleanParameterNames.BOOK_PAGE
      | LisioBooleanParameterNames.READING_MODE,
    triggererToFocus?: string,
  ) {
    if (triggererToFocus) {
      this.sendMessage("popup_response", {
        value,
        parameter,
        focus: triggererToFocus,
      });
    } else {
      this.sendMessage("popup_response", { value, parameter });
    }
  }

  public sendProcessEndMessage(value: boolean) {
    this.sendMessage("process_end", { value });
  }

  public sendTranslatorAPITranslate(
    keyHandler: string,
    originLang: string,
    destLang: string,
    texts: string[],
  ) {
    this.sendMessage("translator_api_translate", {
      keyHandler: keyHandler,
      body: {
        originLangISO: originLang,
        translateLangISO: destLang,
        originalTexts: texts,
        epochSent: Date.now(),
      },
    });
  }

  public sendDicoAPI(word: string) {
    this.sendMessage("dico_api", {
      word,
    });
  }

  private sendMessage(name: string, datas: object) {
    if (__BUILD_TARGET__ === "extension") {
      if (window.location.pathname === "/reading-mode.html") {
        const panelChannel = this._channels.get("sidepanel-channel");
        panelChannel?.postMessage({ name, datas: JSON.stringify(datas) });
      } else {
        const frontChannel = this._channels.get("channel-front");
        frontChannel?.postMessage({ name, datas: JSON.stringify(datas) });
      }
    } else {
      this._contentWindow?.postMessage(
        {
          name,
          datas: JSON.stringify(datas),
        },
        this._lisioServerIframe,
      );
    }
  }
}

export default LisioMessageManager;
