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

import styles from "../assets/css/shadowroot/lisio-list.css?raw";
import { LisioParamsController } from "../controllers/lisio-params-controller";
import LisioShadowRootController from "../controllers/lisio-shadow-root-controller";
import LisioTranslationController from "../controllers/lisio-translation-controller";
import LisioCSSProperties from "../enums/lisio-css-properties";
import LisioMessageManager from "../managers/lisio-message-manager";
import LisioTextTreeWalker from "../walkers/lisio-text-tree-walker";
import LisioAdapter from "./lisio-adapter";
import LisioDeeplTranslationAdapter from "./translations/lisio-deepl-translation-adapter";
import { LisioConfig } from "../lisio-init";

/**
 * Class representing a list adapter extending an adapter.\
 * It aims to represents the font style functionality of Lisio.\
 * A list adapter is basically a functionality of Lisio which will change the list of texts in the main page.\
 */
class LisioListAdapter extends LisioAdapter<boolean> {
  private _deeplAdapter: LisioDeeplTranslationAdapter;
  private _idPlaceholder = 0;
  private _lisioListDiv: HTMLDivElement;
  private _listLinks: HTMLUListElement;
  private _listTitles: HTMLUListElement;
  private _paramsController: LisioParamsController;
  private _sectionList: HTMLElement;

  constructor(
    lisioConfig: LisioConfig,
    paramsController: LisioParamsController,
    deeplAdapter: LisioDeeplTranslationAdapter,
  ) {
    super();
    this._paramsController = paramsController;
    this._deeplAdapter = deeplAdapter;
    this._listTitles = document.createElement("ul");
    this._listTitles.id = "lisio-list-titles";
    this._listTitles.dataset.lisioList = "titles";
    this._listLinks = document.createElement("ul");
    this._listLinks.id = "lisio-list-links";
    this._listLinks.dataset.lisioList = "links";
    this._listLinks.classList.add("lisio-hidden");
    const article = document.createElement("article");
    article.classList.add("lisio-overflow-auto");
    article.append(this._listTitles, this._listLinks);
    this._sectionList = document.createElement("section");
    this._sectionList.innerHTML = `
      <nav id="lisio-list-nav">
        <div class="lisio-nav-div lisio-list-active" data-lisio-target="titles" tabindex="0">
          <p id="lisio-list-title">${LisioTranslationController.current.getTranslation("listTitle")}</p>
        </div>
        <div class="lisio-nav-div" data-lisio-target="links" tabindex="0">
          <p id="lisio-list-link">${LisioTranslationController.current.getTranslation("listLink")}</p>
        </div>
      </nav>
    `;
    this._sectionList.append(article);
    this._sectionList.id = "lisio-list-section";
    this._lisioListDiv = document.createElement("div");
    this._lisioListDiv.id = "lisio-list-div";
    this._lisioListDiv.classList.add(
      "lisio-flex-col",
      lisioConfig.userSettings.positionX === "R" ? "lisio-right" : "lisio-left",
    );
    this._lisioListDiv.innerHTML = `
      <button id="lisio-list-button" aria-controls="lisio-list-section" aria-label="${LisioTranslationController.current.getTranslation("closeWindow")}" class="${lisioConfig.userSettings.positionX === "R" ? "lisio-right" : "lisio-left"} lisio-self-end"></button>
    `;
    this._lisioListDiv.append(this._sectionList);
    const button = this._lisioListDiv.querySelector("button#lisio-list-button");

    const disableHandler = (event: Event) => {
      if (
        event.target instanceof HTMLElement &&
        event.target.nextElementSibling != undefined
      ) {
        LisioMessageManager.current.sendDisableParameter(
          LisioBooleanParameterNames.LIST,
        );
      }
    };

    if (button instanceof HTMLElement) {
      button.addEventListener("click", disableHandler);

      // Gère la touche "Entrée" (ou "Space", en bonus)
      button.addEventListener("keydown", (event: KeyboardEvent) => {
        if (event.isComposing || event.key === "Enter") {
          event.preventDefault(); // Évite le scroll si espace
          disableHandler(event);
        }
      });
    }
    window.addEventListener("lisio-lang-change", () => {
      LisioTranslationController.current.translateList(this._sectionList);
    });
  }

  /**
   * Public method implementing abstract method adapt of Adapter
   * @param {LisioTextTreeWalker} walker - A walker to explore the DOM
   * @param {boolean} value - Value of the functionality
   * @returns Returns nothing
   * @source
   */
  public adapt(_: LisioTextTreeWalker, value: boolean): void {
    const titles =
      document.body.querySelectorAll<HTMLHeadingElement>("h1,h2,h3,h4,h5,h6"); //on sélection les hn
    const links = document.body.querySelectorAll<HTMLAnchorElement>("a");
    while (this._listTitles.firstChild != undefined) {
      this._listTitles.firstChild.remove();
    }
    while (this._listLinks.firstChild != undefined) {
      this._listLinks.firstChild.remove();
    }
    for (const element of this._sectionList.querySelectorAll(
      "div.lisio-nav-div",
    )) {
      const lists = this._sectionList?.querySelectorAll("ul");

      const changeTab = (event: Event) => {
        if (event.target instanceof HTMLElement) {
          const target = event.target.dataset.lisioTarget;
          LisioShadowRootController.current.root
            .querySelectorAll("div.lisio-nav-div.lisio-list-active")
            .forEach((element) => {
              element.classList.remove("lisio-list-active");
            });
          for (const list of lists) {
            if (list.dataset.lisioList == target) {
              list.classList.remove("lisio-hidden");
              event.target.classList.add("lisio-list-active");
            } else {
              list.classList.add("lisio-hidden");
            }
          }
        }
      };

      const htmlElement = element as HTMLElement;
      htmlElement.addEventListener("click", changeTab);
      htmlElement.addEventListener("keydown", (event: KeyboardEvent) => {
        if (event.key === "Enter" || event.key === " ") {
          changeTab(event);
        }
      });
    }
    if (value) {
      for (const tag of [...titles, ...links]) {
        if (tag.innerText?.trim() != "") {
          this.adaptFunction(tag, value);
        }
      }
      LisioShadowRootController.current.appendElement(
        this._lisioListDiv,
        styles,
      );
      if (
        this._paramsController.params.has(
          LisioStringParameterNames.DEEPL_TRANSLATION,
        )
      ) {
        const deeplValue = this._paramsController.params.get(
          LisioStringParameterNames.DEEPL_TRANSLATION,
        ) as string;
        this.prepareForDeeplTrans(deeplValue);
      }
    } else {
      //remove element;
      LisioShadowRootController.current.removeElement(
        this._lisioListDiv,
        styles,
      );
    }
  }

  public createOpenTab(aDomElement: HTMLAnchorElement) {
    // 1. Crée le <span>
    const spanOpenNewTab = document.createElement("span");
    spanOpenNewTab.className = "sr-only-list";
    spanOpenNewTab.innerHTML = `&nbsp;-&nbsp;${LisioTranslationController.current.getTranslation("popin2025_newTab")}`;

    // 2. Crée le <svg>
    const svgNS = "http://www.w3.org/2000/svg";
    const svg = document.createElementNS(svgNS, "svg");
    svg.setAttribute("xmlns", svgNS);
    svg.setAttribute("aria-hidden", "true");
    svg.setAttribute("width", "10");
    svg.setAttribute("height", "10");
    svg.setAttribute("viewBox", "0 0 10 10");
    svg.setAttribute("fill", "none");
    svg.classList.add("newtab");

    // 3. Ajoute le <path> au <svg>
    const path = document.createElementNS(svgNS, "path");
    path.setAttribute(
      "d",
      "M6.25 0a.62.62 0 1 0 0 1.25h1.62L3.93 5.18a.63.63 0 0 0 .89.89l3.93-3.94v1.62a.62.62 0 1 0 1.25 0V.62A.62.62 0 0 0 9.37 0H6.25ZM1.56.63C.7.63 0 1.32 0 2.19v6.25C0 9.3.7 10 1.56 10h6.25c.87 0 1.57-.7 1.57-1.56V6.25a.62.62 0 1 0-1.26 0v2.19c0 .17-.14.31-.3.31H1.55a.31.31 0 0 1-.31-.31V2.19c0-.17.14-.31.31-.31h2.19a.62.62 0 1 0 0-1.25H1.56Z",
    );
    path.setAttribute("fill", "currentColor");
    svg.appendChild(path);

    // 4. Ajoute <span> et <svg> dans le <a>
    aDomElement.appendChild(spanOpenNewTab);
    aDomElement.appendChild(svg);
  }

  public prepareForDeeplTrans(value: string) {
    const hTreeWalker = new LisioTextTreeWalker(this._listTitles, (n) => {
      if (n.nodeType === Node.TEXT_NODE) {
        if (
          n.nodeValue?.trim() != "" &&
          n.parentElement != undefined &&
          !["script", "noscript", "style", "title"].includes(
            n.parentElement.localName,
          )
        ) {
          return NodeFilter.FILTER_ACCEPT;
        } else {
          return NodeFilter.FILTER_REJECT;
        }
      }
      return NodeFilter.FILTER_SKIP;
    });
    const listTreeWalker = new LisioTextTreeWalker(this._listTitles, (n) => {
      if (n.nodeType === Node.TEXT_NODE) {
        if (
          n.nodeValue?.trim() != "" &&
          n.parentElement != undefined &&
          !["script", "noscript", "style", "title"].includes(
            n.parentElement.localName,
          )
        ) {
          return NodeFilter.FILTER_ACCEPT;
        } else {
          return NodeFilter.FILTER_REJECT;
        }
      }
      return NodeFilter.FILTER_SKIP;
    });
    hTreeWalker.getTextes();
    listTreeWalker.getTextes();
    this._deeplAdapter.observeTags(hTreeWalker, value);
    this._deeplAdapter.observeTags(listTreeWalker, value);
  }

  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  protected adaptFunction(element: HTMLElement, _value: boolean): void {
    if (element instanceof HTMLHeadingElement) {
      const li = document.createElement("li");
      let h = 0;
      if (element.localName == "h1") {
        h = 1;
      } else if (element.localName == "h2") {
        h = 2;
      } else if (element.localName == "h3") {
        h = 3;
      } else if (element.localName == "h4") {
        h = 4;
      } else if (element.localName == "h5") {
        h = 5;
      } else if (element.localName == "h6") {
        h = 6;
      }

      if (h > 1) {
        const styleRule = `li.lisio-list-h${h} { ${LisioCSSProperties.MARGIN_LEFT}: ${h - 1}rem; }`;
        LisioShadowRootController.current.addStyles(styleRule);
      }
      this._listTitles.appendChild(li); //on l'ajoute à la liste
      li.classList.add(`lisio-list-h${h}`); //on sélectionne son décalage
      const span = document.createElement("span");
      span.innerText = `${h}.`;
      li.appendChild(span);

      const a = document.createElement("a");
      a.innerText += element.innerText.trim(); //on récupère son texte
      a.innerText = a.innerText.split("\n")[0];
      if (element.id == "") {
        //si le titre a pas d'id on donne un id unique au titre cible
        element.id = `lisio-placeholder-id-${this._idPlaceholder}`;
        this._idPlaceholder++;
      }
      a.href = `#${element.id}`; //on crée un encre vers le titre
      li.appendChild(a); // on l'ajoute
    } else if (element instanceof HTMLAnchorElement) {
      if (element.innerText.trim() != "") {
        const li = document.createElement("li");
        li.classList.add("lisio-list-link");
        this._listLinks.appendChild(li);
        const a = document.createElement("a");
        a.innerText += element.innerText.trim(); //on récupère son contenu
        a.innerText = a.innerText.split("\n")[0];
        a.href = element.href; //on récupère le href
        this.createOpenTab(a);
        li.appendChild(a);
      }
    }
  }
}

export default LisioListAdapter;
