import LisioImgToBlob from "../../../misc/lisio-img-to-blob";
import { LisioReaderAdapter, ReaderObject } from "../lisio-reader-adapter";
import ExploreCalendarHelper from "./explore-calendar-helper";

class ExploreOtherHelper {
  private _calendarHelper: ExploreCalendarHelper;
  private _sliderCache: ReaderObject[] = [];
  private _sliderPairs = new Map<string, boolean>();

  constructor(calendarHelper: ExploreCalendarHelper) {
    this._calendarHelper = calendarHelper;
  }

  public async exploreOther(
    readerAdapter: LisioReaderAdapter,
    tag: HTMLElement | SVGElement,
    mediaConverter: LisioImgToBlob,
    allBackgroundImageTags: (HTMLElement | SVGElement)[],
  ) {
    if (tag.localName === "img" && tag instanceof HTMLImageElement) {
      const datas = readerAdapter.handleImage(tag);
      datas.name = "img";
      if (
        this._sliderCache.length >= 0 &&
        !this._sliderPairs.has(datas.src || "")
      ) {
        datas.isInSlider = true;
        this._sliderCache.push(datas);
      }
    } else if (tag.localName === "svg" && tag instanceof SVGElement) {
      // avoir
      const hash = await mediaConverter.loadSVG(tag);
      const position = readerAdapter.all.indexOf(tag);
      const { visibility, opacity } = window.getComputedStyle(tag);
      if (
        tag.getAttribute("width") == undefined ||
        tag.getAttribute("height") == undefined
      ) {
        const { width, height } = tag.getBoundingClientRect();
        tag.setAttribute("width", width.toString());
        tag.setAttribute("height", height.toString());
      }
      tag.dataset.lisioPosition = position.toString();
      readerAdapter.toSend.push({
        name: "img",
        src: hash,
        width: tag.getAttribute("width") || "0",
        height: tag.getAttribute("height") || "0",
        position,
        insert: position === 0 ? "before" : "after",
        isHidden: visibility === "hidden" || parseInt(opacity) === 0,
      });
    } else if (tag.localName === "video" && tag instanceof HTMLVideoElement) {
      const src = readerAdapter.handleVideo(tag);
      const position = readerAdapter.all.indexOf(tag);
      const { visibility, opacity } = window.getComputedStyle(tag);
      readerAdapter.toSend.push({
        name: "video",
        src,
        width: tag.getAttribute("width") || "0",
        height: tag.getAttribute("height") || "0",
        position,
        insert: position === 0 ? "before" : "after",
        isHidden:
          tag.offsetParent == undefined ||
          visibility === "hidden" ||
          parseInt(opacity) === 0,
      });
    } else if (
      tag instanceof HTMLEmbedElement ||
      tag instanceof HTMLIFrameElement ||
      tag instanceof HTMLObjectElement
    ) {
      if (
        !(tag instanceof HTMLIFrameElement) ||
        tag.src?.includes("youtube") ||
        tag.src?.includes("maps")
      ) {
        const clonedTag =
          (tag.cloneNode(true) as HTMLEmbedElement | HTMLIFrameElement) ||
          tag instanceof HTMLObjectElement;
        clonedTag.dataset.lisioPosition = readerAdapter.all
          .indexOf(tag)
          .toString();
        const { width, height, visibility, opacity } =
          window.getComputedStyle(tag);
        const src =
          clonedTag instanceof HTMLObjectElement
            ? clonedTag.data
            : clonedTag.src;
        const position = readerAdapter.all.indexOf(tag);
        readerAdapter.toSend.push({
          name: clonedTag.localName,
          src,
          width,
          height,
          position,
          loading: tag.getAttribute("loading") as string | undefined,
          isHidden:
            tag.offsetParent == undefined ||
            visibility === "hidden" ||
            parseInt(opacity) === 0,
        });
      }
    } else if (allBackgroundImageTags.includes(tag)) {
      const rects = tag.getClientRects();
      if (tag.textContent?.trim() === "" && rects.length > 0) {
        const { width, height } = tag.getClientRects()[0];
        const {
          backgroundImage,
          backgroundSize,
          backgroundPosition,
          cursor,
          display,
          visibility,
          opacity,
        } = window.getComputedStyle(tag);
        const indexOfMedia = readerAdapter.all.indexOf(tag);
        const image = new Image(width, height);
        const url = backgroundImage.slice(5, backgroundImage.length - 2);
        image.src = url.startsWith("http")
          ? url.split(`${window.location.hostname}/`)[1]
          : url;
        //await this.imgToBlob(image);
        mediaConverter.base64s.set(image.src, image.src);
        readerAdapter.toSend.push({
          name: "img",
          src: image.src,
          width: width.toString(),
          height: height.toString(),
          alt: "",
          objectFit: backgroundSize,
          objectPosition: backgroundPosition,
          cursor,
          display,
          position: indexOfMedia,
          insert: indexOfMedia === 0 ? "before" : "after",
          isHidden:
            tag instanceof HTMLElement
              ? tag.offsetParent == undefined ||
                visibility === "hidden" ||
                parseInt(opacity) === 0
              : visibility === "hidden" || parseInt(opacity) === 0,
        });
      } else {
        console.log(`Text with background img : ${tag}`);
      }
    } else if (tag instanceof HTMLElement) {
      const clonedTag = tag.cloneNode(true) as HTMLElement;
      clonedTag.dataset.lisioPosition = readerAdapter.all
        .indexOf(tag)
        .toString();
      const isHidden = readerAdapter.handleStyles(
        clonedTag,
        tag as HTMLElement,
      );
      const allTagChildren = tag.querySelectorAll<HTMLElement | SVGElement>(
        "*",
      );
      if (
        clonedTag.dataset.lisioClickable == undefined &&
        (clonedTag.tagName === "A" ||
          (clonedTag.tagName === "INPUT" &&
            clonedTag.getAttribute("type") === "button") ||
          tag.onclick != undefined)
      ) {
        clonedTag.dataset.lisioClickable =
          readerAdapter.dataLisioClickable.toString();
        tag.dataset.lisioClickable =
          readerAdapter.dataLisioClickable.toString();
        readerAdapter.dataLisioClickable++;
      }
      for (const [index, child] of clonedTag
        .querySelectorAll<HTMLElement | SVGElement>("*")
        .entries()) {
        if (child.textContent?.trim() == "") {
          child.remove();
          continue;
        }
        readerAdapter.handleStyles(child, allTagChildren[index]);
        if (
          child instanceof HTMLElement &&
          child.dataset.lisioClickable == undefined &&
          (child.tagName === "A" ||
            (child.tagName === "BUTTON" &&
              readerAdapter.stylesToAdd.get("pointer-event")) ||
            (child.tagName === "INPUT" &&
              child.getAttribute("type") === "button") ||
            child.onclick != undefined) &&
          allTagChildren[index] instanceof HTMLElement
        ) {
          child.dataset.lisioClickable =
            readerAdapter.dataLisioClickable.toString();
          allTagChildren[index].dataset.lisioClickable =
            readerAdapter.dataLisioClickable.toString();
          readerAdapter.dataLisioClickable++;
        }
      }
      const position = readerAdapter.all.indexOf(tag);
      tag.dataset.lisioPosition = position.toString();
      const datas: ReaderObject = {
        name: clonedTag.localName,
        index: clonedTag.dataset.lisioIndex,
        content: clonedTag.innerHTML,
        classes: clonedTag.className,
        position,
        isHidden,
        isInSlider: false,
        clickable:
          clonedTag.dataset.lisioClickable == undefined
            ? undefined
            : Number.parseInt(clonedTag.dataset.lisioClickable),
        maybeACalendar: false,
      };
      const closestA = tag.parentElement;
      if (closestA instanceof HTMLAnchorElement) {
        datas.name = "a";
        datas.blank = `${closestA.target === "_blank"}`;
        datas.href = closestA.href === "" ? "" : new URL(closestA.href).href;
        if (closestA.dataset.lisioClickable == undefined) {
          closestA.dataset.lisioClickable =
            readerAdapter.dataLisioClickable.toString();
        }
        datas.clickable = Number.parseInt(
          closestA.dataset.lisioClickable || "-1",
        );
        readerAdapter.dataLisioClickable++;
      } else if (clonedTag instanceof HTMLAnchorElement) {
        datas.blank = `${clonedTag.target === "_blank"}`;
        datas.href = clonedTag.href === "" ? "" : new URL(clonedTag.href).href;
        if (clonedTag.dataset.lisioClickable == undefined) {
          tag.dataset.lisioClickable =
            readerAdapter.dataLisioClickable.toString();
        }
        datas.clickable = Number.parseInt(tag.dataset.lisioClickable || "-1");
        readerAdapter.dataLisioClickable++;
      }
      const textChild = Array.from(clonedTag.childNodes).filter(
        (child) => child.nodeType === 3 && child.textContent?.trim() != "",
      )[0];
      const textContent =
        (datas.name === "select" && clonedTag instanceof HTMLSelectElement
          ? clonedTag.selectedOptions[0].textContent
              ?.trim()
              .normalize("NFD")
              .replace(/[\u0300-\u036f]/gu, "")
          : textChild != undefined
            ? textChild.textContent
                ?.trim()
                .normalize("NFD")
                .replace(/[\u0300-\u036f]/gu, "")
            : clonedTag.textContent
                ?.trim()
                .normalize("NFD")
                .replace(/[\u0300-\u036f]/gu, "")) || "";
      //calendar
      if (
        !["code", "pre"].includes(clonedTag.localName) &&
        this._calendarHelper.calendarOther(textContent, tag, datas)
      ) {
        /* empty */
      } else if (
        datas.name != undefined &&
        this._sliderCache.length >= 1 &&
        this._sliderCache[this._sliderCache.length - 1].name === "img" &&
        ["figcaption", "p", "span"].includes(datas.name)
      ) {
        datas.isInSlider = true;
        this._sliderCache[this._sliderCache.length - 1].hasCaption = true;
        this._sliderCache.push(datas);
      } else if (
        this._sliderCache.length === 0 &&
        tag.closest<HTMLElement>(
          `[data-lisio-position]:not([data-lisio-position="${datas.position}"])`,
        ) == undefined
      ) {
        readerAdapter.toSend.push(datas);
      } else {
        if (this._sliderCache.length > 0 && this._sliderCache.length < 3) {
          for (const sCache of this._sliderCache) {
            sCache.isInSlider = false;
          }
        } else {
          const nSliderCache: string[] = [];
          const posCache: string[] = [];
          for (let i = 0; i < this._sliderCache.length; i++) {
            const sliderCachedObject = this._sliderCache[i];
            if (
              sliderCachedObject.name === "img" &&
              sliderCachedObject.src != undefined &&
              sliderCachedObject.objectPosition != undefined &&
              posCache.includes(sliderCachedObject.objectPosition)
            ) {
              if (nSliderCache.includes(sliderCachedObject.src || "")) {
                const offset = sliderCachedObject.hasCaption ? 2 : 1;
                this._sliderCache.splice(i, offset);
                i -= offset;
              } else {
                nSliderCache.push(sliderCachedObject.src || "");
                posCache.push(sliderCachedObject.objectPosition);
              }
            }
          }
        }
        readerAdapter.toSend.push(...this._sliderCache);
        this._sliderCache.splice(0, Infinity);
        readerAdapter.toSend.push(datas);
      }
    }
  }
}

export default ExploreOtherHelper;
