/* eslint-disable @typescript-eslint/no-unused-expressions */
import { LisioVersionNames, lisioVersionConverter } from "@lisio/lisio-profils";

import styles from "../assets/css/lisio-main.css?raw";
import shadowRootStyles from "../assets/css/shadowroot/lisio-shadow-root.css?raw";
import generalPopinStyles from "../assets/css/shadowroot/popin/lisio-popin.css?raw";
import {
  LisioBlurController,
  styles as blurStyles,
} from "../controllers/lisio-blur-controller.ts";
import LisioIconController from "../controllers/lisio-icons-controller.ts";
import LisioShadowRootController from "../controllers/lisio-shadow-root-controller";
import { styles as showHideStyles } from "../controllers/lisio-show-hide-controller.ts";
import LisioStatsController from "../controllers/lisio-stats-controller.ts";
import LisioStyleSheetController from "../controllers/lisio-stylesheet-controller.ts";
import LisioTranslationController from "../controllers/lisio-translation-controller";
import {
  LisioWidgetController,
  styles as widgetStyles,
} from "../controllers/lisio-widget-controller.ts";
import { LisioIconNames } from "../enums/lisio-icon-names.ts";
import LisioMessageReceivedName from "../enums/lisio-message-received-name.ts";
import LisioPopinNames from "../enums/lisio-popin-names";
import { GlobalContext } from "../global-context.ts";
import { appendToHead, lisioGetInitLang } from "../utils.ts";
import { LisioPopin } from "./lisio-popin.ts";
import { LisioPopup, popupStyles } from "../popups/lisio-popup.ts";
import { LisioConfig } from "../lisio-init.ts";
import LisioLightMessageManager from "../managers/lisio-light-message-manager.ts";

export interface HasButtons {
  hasEcoButton: boolean;
  hasHelpButton: boolean;
  hasMainButton: boolean;
  hasTransButton: boolean;
}

class LisioPopinFactory {
  private _popinBuilders: Map<LisioPopinNames, LisioPopinBuilder> = new Map<
    LisioPopinNames,
    LisioPopinBuilder
  >();

  constructor() {
    GlobalContext.current;
    LisioTranslationController.current;
    LisioIconController.current;
    LisioBlurController.current;
    LisioShadowRootController.current;
    LisioStatsController.current;
    LisioStyleSheetController.current;
    LisioLightMessageManager.current;
    this._popinBuilders.set(LisioPopinNames.POPIN2024, this.popin2024Creator);
    this._popinBuilders.set(LisioPopinNames.POPIN2025, this.popin2025Creator);
  }

  public async createPopin(
    lisioConfig: LisioConfig,
    display: number,
    isMobile: boolean,
    isSafeTrans: boolean,
    popinName: LisioPopinNames,
    colorPrimary: string,
    colorEcolo: string,
    tabsToHide: string[],
    clientLogo?: string
  ): Promise<{ popin?: LisioPopin; popinStyles?: string }> {
    GlobalContext.current.popinName = popinName;
    GlobalContext.current.isMobile = isMobile;
    if (__BUILD_TARGET__ === "extension") {
      await LisioTranslationController.current.loadTranslationFile(
        lisioGetInitLang(),
      );
      const lisioStyles = document.createElement("style");
      lisioStyles.textContent = `
        :root{
          --theme-primary: ${lisioConfig.userSettings.colorPrimary};
          --theme-ecolo: ${lisioConfig.userSettings.colorEcolo};
        }
      `;
      lisioStyles.textContent += styles;
      appendToHead(lisioStyles);
      const popinShowHideContainer = document.createElement("div");
      popinShowHideContainer.id = "lisio-popin-container";
      LisioShadowRootController.current.appendElement(
        popinShowHideContainer,
        `${styles}`,
      );
      // const statsController = new LisioStatsController(
      //   lisioConfig.urls.addStats,
      // );
      LisioShadowRootController.current.appendElement(
        LisioBlurController.current.blur,
        blurStyles,
      );
      const widget = new LisioWidgetController();

      const loadLisio = async () => {
        const { Lisio } = await import("../lisio.ts");
        new Lisio(lisioConfig, widget, undefined);
        LisioLightMessageManager.current.detachHandler(
          LisioMessageReceivedName.LOAD_FRONT,
        );
      };

      LisioLightMessageManager.current.attachHandler(
        LisioMessageReceivedName.LOAD_FRONT,
        loadLisio,
      );

      loadLisio();

      return {};
    } else {
      await LisioTranslationController.current.loadTranslationFile(
        lisioGetInitLang(),
      );
      lisioConfig.userSettings.colorPrimary =
        contrastWhite(colorPrimary) >= 7 ? colorPrimary : "#005282";
      const truePopinName = popinName.split("_")[0].split("help")[0];
      const builder: LisioPopinBuilder | undefined = this._popinBuilders.get(
        truePopinName as LisioPopinNames,
      );
      if (builder == undefined) {
        throw new Error("No popin builder");
      }
      const mobileOrDesktop = isMobile ? "mobile" : "desktop";
      const version: LisioVersionNames = lisioVersionConverter(display);
      hasButtons.hasMainButton =
        [
          LisioVersionNames.COMPLETE,
          LisioVersionNames.ESSENTIAL,
          LisioVersionNames.FIRST,
        ].includes(version) &&
        !tabsToHide.includes(`mainBtn-${mobileOrDesktop}`) &&
        !tabsToHide.includes("main");
      hasButtons.hasTransButton =
        [
          LisioVersionNames.COMPLETE,
          LisioVersionNames.WELCOME,
          LisioVersionNames.ESSENTIAL,
        ].includes(version) &&
        !tabsToHide.includes(`tradBtn-${mobileOrDesktop}`) &&
        !tabsToHide.includes("trad");
      hasButtons.hasEcoButton =
        [LisioVersionNames.COMPLETE].includes(version) &&
        !tabsToHide.includes(`ecoBtn-${mobileOrDesktop}`) &&
        !tabsToHide.includes("eco");
      if (popinName.includes("help")) {
        hasButtons.hasHelpButton = true;
      }
      if (tabsToHide.includes(`hippo-${mobileOrDesktop}`)) {
        hasHippoLogo = false;
      }
      if (tabsToHide.includes(`popup-${mobileOrDesktop}`)) {
        hasPopup = false;
      }

      const { popin, popinStyles } = await builder(
        popinName,
        lisioConfig.userSettings.colorPrimary,
        colorEcolo,
        hasButtons,
        hasPopup,
        isMobile,
        isSafeTrans,
        clientLogo
      );

      if (popin != undefined) {
        await popin.initialize(popinName.includes("accessmobile")
        ? LisioIconNames.MAIN as string : LisioIconNames.LOGO);

        const lisioStyles = document.createElement("style");
        lisioStyles.textContent = `
        :root{
          --theme-primary: ${lisioConfig.userSettings.colorPrimary};
          --theme-ecolo: ${lisioConfig.userSettings.colorEcolo};
        }
      `;
        lisioStyles.textContent += styles;
        appendToHead(lisioStyles);

        const positionXToCalc = isMobile
          ? lisioConfig.userSettings.positionMobileX
          : lisioConfig.userSettings.positionX;
        const positionYToCalc = isMobile
          ? lisioConfig.userSettings.positionMobileY
          : lisioConfig.userSettings.positionY;
        const side = positionXToCalc === "R" ? "right" : "left";
        const popinShowHideContainer = document.createElement("div");
        popinShowHideContainer.classList.add(side);
        popinShowHideContainer.id = "lisio-popin-container";
        LisioShadowRootController.current.appendElement(
          popinShowHideContainer,
          `${shadowRootStyles} ${showHideStyles} ${generalPopinStyles} ${popinStyles} ${popin.showHideController?.colorStyle || ""}`,
        );

        LisioShadowRootController.current.appendElement(
          LisioBlurController.current.blur,
          blurStyles,
        );
        const widget = new LisioWidgetController(side);
        if (isMobile) {
          popin.popinContainer.classList.add("popin-lisio-popin-mobile");
        }

        popin.widget = widget;
        popin.attachListenerPopinButtons(document.body);
        popinShowHideContainer.append(popin.popinContainer);
        if (popin.showHideController != undefined) {
          popinShowHideContainer.append(popin.showHideController.showHideIcon);
        }
        popinShowHideContainer.style.top = `calc(${positionYToCalc})`;
        const { top, bottom, height } =
          popinShowHideContainer.getBoundingClientRect();
        if (top < 0) {
          popinShowHideContainer.style.top = `${height / 2}px`;
        } else if (bottom > window.innerHeight) {
          popinShowHideContainer.style.top = "";
          popinShowHideContainer.style.bottom = `-${height / 2}px`;
        }
        if (popin.popup != undefined && !popin.popup.hidePopup) {
          const svgs = Array.from(
            popinShowHideContainer.querySelectorAll("svg"),
          );
          const { top, height } = svgs[svgs.length - 1].getBoundingClientRect();
          const logoTop = top + height / 2;
          await popin.popup.startPopup(
            positionYToCalc,
            positionXToCalc,
            lisioConfig.userSettings.colorPrimary,
            lisioConfig.userSettings.colorEcolo,
            false,
          );
          LisioShadowRootController.current.appendElement(
            popin.popup.popupContainer,
            popin.getPopupStyles(),
          );
          popin.attachListenerPopinButtons(popin.popup?.popupContainer);
          popin.popup.topCorrection();
          const triangle = popin.popup.popupContainer.querySelector(
            "div#lisio-triangle",
          ) as HTMLElement | undefined;
          if (triangle) {
            const { top, height } = triangle.getBoundingClientRect();
            triangle.style.top = `${logoTop - (top + height / 2)}px`;
          }
        }
        if (Number.parseInt(positionYToCalc) >= 10000) {
          popin.popinContainer.classList.add("lisio-hidden");
          popin.showHideController?.showHideIcon.classList.add("lisio-hidden");
          popin.popup?.popupContainer.classList.add("lisio-hidden");
        } else {
          popin.attachListenerPopinButtons(popinShowHideContainer);
        }
        if (widget.widget != undefined) {
          LisioShadowRootController.current.appendElement(
            widget.widget,
            widgetStyles,
          );
        }

        const loadLisio = async () => {
          const { Lisio } = await import("../lisio.ts");
          new Lisio(lisioConfig, widget, popin);
          LisioLightMessageManager.current.detachHandler(
            LisioMessageReceivedName.LOAD_FRONT,
          );
          widget.isLoaded = true;
        };

        LisioLightMessageManager.current.attachHandler(
          LisioMessageReceivedName.LOAD_FRONT,
          loadLisio,
        );

        await widget.loadWidget(
          `${import.meta.env.VITE_LISIO_DOMAIN}/widget/dist-site/widget.html?v=${__BUILD_ID__}`,
        );

        if (widget.widget?.contentWindow == undefined) {
          throw new Error("Lisio widget not loaded");
        }

        LisioLightMessageManager.current.contentWindow = widget.widget.contentWindow;
        LisioLightMessageManager.current.sendPopinReady();
      }

      return { popin, popinStyles };
    }
  }


  public async popin2024Creator(
    popinName: string,
    colorPrimary: string,
    colorEcolo: string,
    hasButtons: HasButtons,
    hasPopup: boolean,
    _isMobile: boolean,
    isSafeTrans: boolean,
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    _clientLogo?: string
  ) {
    const { LisioPopin2024, styles } = await import(
      `./models/lisio-popin-2024.ts`
    );
    const popin = new LisioPopin2024(
      popinName,
      colorPrimary,
      colorEcolo,
      hasButtons,
      hasPopup,
      isSafeTrans,
    );
    return { popin, popinStyles: styles };
  }

  public async popin2025Creator(
    popinName: string,
    colorPrimary: string,
    colorEcolo: string,
    hasButtons: HasButtons,
    hasPopup: boolean,
    _isMobile: boolean,
    isSafeTrans: boolean,
    clientLogo?: string
  ) {
    const { LisioPopin2025, styles } = await import(
      `./models/lisio-popin-2025.ts`
    );
    const popin = new LisioPopin2025(
      popinName,
      colorPrimary,
      colorEcolo,
      LisioIconNames[
        lisioGetInitLang().toUpperCase() as keyof typeof LisioIconNames
      ],
      hasButtons,
      hasPopup,
      isSafeTrans,
      hasHippoLogo,
      clientLogo,
    );
    return { popin, popinStyles: styles };
  }
}

type LisioPopinBuilder = (
  popinName: string,
  colorPrimary: string,
  colorEcolo: string,
  hasButtons: HasButtons,
  hasPopup: boolean,
  isMobile: boolean,
  isSafeTrans: boolean,
  clientLogo?: string
) => Promise<{ popin: LisioPopin; popinStyles: string }>;

function contrastWhite(hex: string) {
  const lum = luminance(hex);
  return 1.05 / (lum + 0.05);
}

function luminance(hex: string) {
  if (hex.charAt(0) !== "#") {
    console.error("Le code couleur doit commencer par '#' !");
    return 1;
  }

  const RED = 0.2126;
  const GREEN = 0.7152;
  const BLUE = 0.0722;
  const GAMMA = 2.4;
  const r = parseInt(hex.substring(1, 3), 16);
  const g = parseInt(hex.substring(3, 5), 16);
  const b = parseInt(hex.substring(5, 7), 16);
  const a = [r, g, b].map((v) => {
    v /= 255;
    return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, GAMMA);
  });
  return a[0] * RED + a[1] * GREEN + a[2] * BLUE;
}

const hasButtons = {
  hasMainButton: true,
  hasTransButton: true,
  hasEcoButton: true,
  hasHelpButton: false,
} as HasButtons;
let hasHippoLogo = true;
let hasPopup = true;

if (__BUILD_TARGET__ === "extension") {
  import("../lisio-config.ts").then(async ({ lisioConfig }) => {
    const display: number = Number.parseInt(lisioConfig.userSettings.display);

    const isSafeTrans = (
      lisioConfig.userSettings.tabsToHide as string[]
    ).includes("tradGoogle");

    const isMobile = window.matchMedia(
      "screen and (min-width: 200px) and (max-width: 960px)",
    ).matches;

    const lisioPopinFactory = new LisioPopinFactory();

    const lisioPopinName =
      lisioConfig.userSettings.vPopin == "default"
        ? "popin2025"
        : lisioConfig.userSettings.vPopin;
    await lisioPopinFactory.createPopin(
      lisioConfig,
      display,
      isMobile,
      isSafeTrans,
      lisioPopinName as LisioPopinNames,
      lisioConfig.userSettings.colorPrimary,
      lisioConfig.userSettings.colorEcolo,
      lisioConfig.userSettings.tabsToHide,
      lisioConfig.userSettings.clientLogo
    );
  });
}

export { LisioPopinFactory, LisioTranslationController, LisioPopin, LisioPopup, popupStyles };
