import LisioWalker from "./lisio-walker";

class LisioTextTreeWalker extends LisioWalker {
  private _tags: Map<number, HTMLElement> = new Map<number, HTMLElement>();
  private _texts: Map<number, string> = new Map<number, string>();

  // public recursive(
  //   parent: HTMLElement,
  //   id: number,
  // ) {
  //   if (
  //     parent.localName == "span" ||
  //     parent.localName == "i" ||
  //     parent.localName == "strong" ||
  //     /h[123456]/.test(parent.tagName)
  //   ) {
  //     this._tags.delete(id);
  //     this._tags.set(id, parent);
  //     // this.texts[i] = this.tags[i].innerText;
  //     parent.dataset.lisioIndex = id.toString();
  //     for (const child of parent.children) {
  //       delete (child as HTMLElement).dataset.lisioIndex;
  //     }
  //     if (parent.parentElement != undefined) {
  //       this.recursive(parent.parentElement, id);
  //     }
  //   }
  // }

  /**
   * Constructor of class {@link TextTreeWalker | TextTreeWalker}
   * @param {NodeFilter | undefined} filter - Custom filter for tree walker
   */
  constructor(root: HTMLElement, filter: NodeFilter | undefined) {
    super(NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, root, filter);
  }

  public get tags() {
    return this._tags;
  }

  public get texts(): Map<number, string> {
    return this._texts;
  }

  public getTextes() {
    if (this._texts.size <= 0) {
      this.explore(this.getTextesExploreCallback.bind(this));
    }
    for (const tag of Array.from(this._tags.values())) {
      const uselessLisioIndexes =
        tag.querySelectorAll<HTMLElement>("[data-lisio-index]");
      for (const uselessLisioIndex of uselessLisioIndexes) {
        this._tags.delete(
          Number.parseInt(uselessLisioIndex.dataset.lisioIndex as string),
        );
        delete uselessLisioIndex.dataset.lisioIndex;
      }
    }
  }

  public resetWalker(): void {
    super.resetWalker();
    this._texts.clear();
    this._tags.clear();
  }

  public setDefault() {
    if (this._tags.size <= 0) {
      this.explore(this.setDefaultWalkerCallback);
    }
  }

  private getTextesExploreCallback(node: Node) {
    const parent = node.parentElement;
    if (
      !parent ||
      ["script", "noscript", "style", "title"].includes(parent.localName) ||
      node.nodeValue === undefined
    ) {
      return;
    }

    const trimmedValue =
      node.nodeType === Node.TEXT_NODE
        ? node.nodeValue?.trim()
        : (node as HTMLElement).getAttribute("placeholder");

    if (!trimmedValue || !/[\p{L}\p{N}]/u.test(trimmedValue)) {
      return;
    }

    let targetElement: HTMLElement | null = null;

    if (node.nodeType === Node.TEXT_NODE) {
      if (
        parent.localName === "font" &&
        parent.dataset.lisioLetter === undefined &&
        parent.parentElement?.parentElement
      ) {
        targetElement = parent.closest<HTMLElement>(":not(font)");
      } else {
        targetElement = parent;
      }
    }
    if (node.nodeType === Node.ELEMENT_NODE) {
      if ((node as HTMLElement).getAttribute("placeholder")) {
        targetElement = node as HTMLElement;
      }
    }

    if (!targetElement) return;

    const textContent =
      node.nodeType === Node.TEXT_NODE
        ? targetElement.innerText?.trim() || targetElement.textContent?.trim()
        : (node as HTMLElement).getAttribute("placeholder");
    if (!textContent) return;
    const index = this._tags.size;
    this._texts.set(index, textContent);
    this._tags.set(index, targetElement);
    targetElement.dataset.lisioIndex = index.toString();
  }

  private setDefaultWalkerCallback(node: Node) {
    const element: HTMLElement = node as HTMLElement;
    const prefix = "lisio-";
    const classes = element.className
      ? element.className.split(" ").filter((c) => !c.startsWith(prefix))
      : [];
    element.className = classes.join(" ").trim();
    if (element.classList.contains("start-synth")) {
      element.classList.add("lisio-hidden");
    }
    delete element.dataset.lisioFontSize;
    delete element.dataset.lisioLineHeight;
    delete element.dataset.lisioWordSpacing;
    delete element.dataset.lisioLetterSpacing;
    delete element.dataset.lisioBigger;
    delete element.dataset.lisioTransition;
    delete element.dataset.lisioAnimation;
    if (
      element.hasAttribute("lisio-already-trans-in") &&
      element.dataset.lisioOriginalText != undefined
    ) {
      delete element.dataset.lisioAlreadyTransIn;
      element.innerHTML = element.dataset.lisioOriginalText;
      delete element.dataset.lisioOriginalText;
      element.removeAttribute("lang");
      element.removeAttribute("xml:lang");
      element.removeAttribute("dir");
    }
    delete element.dataset.lisioAlreadyMin;
  }
}

export default LisioTextTreeWalker;
