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

class ExploreFormHelper {
  private _calendarHelper: ExploreCalendarHelper;
  private _forms: ReaderObject[] = [];
  private _formsCache = new Map<number, ReaderObject>();

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

  public async exploreForm(
    readerAdapter: LisioReaderAdapter,
    tag: HTMLElement | SVGElement,
    mediaConverter: LisioImgToBlob,
  ) {
    if (tag instanceof HTMLFormElement) {
      const { visibility, opacity } = window.getComputedStyle(tag);
      const formObject = {
        name: "form",
        childNodes: [],
        position: readerAdapter.all.indexOf(tag),
        isHidden:
          tag.offsetParent == undefined ||
          visibility === "hidden" ||
          parseInt(opacity) === 0,
      };
      this._formsCache.set(formObject.position, formObject);
      this._forms.push(formObject);
      tag.dataset.lisioPosition = formObject.position.toString();
      readerAdapter.toSend.push(formObject);
    } else if (tag instanceof HTMLElement) {
      let formObject: ReaderObject;
      if (
        tag instanceof HTMLInputElement ||
        tag instanceof HTMLSelectElement ||
        tag instanceof HTMLButtonElement ||
        tag instanceof HTMLTextAreaElement
      ) {
        const { visibility, opacity } = window.getComputedStyle(tag);
        const isHidden =
          tag.offsetParent == undefined ||
          visibility === "hidden" ||
          parseInt(opacity) === 0;
        if (!isHidden) {
          formObject = {
            name: tag.localName,
            id: tag.id,
            childNodes: [],
            type: tag.type,
            position: readerAdapter.all.indexOf(tag),
            value: tag.value,
            placeholder: tag.getAttribute("placeholder") as string | undefined,
            isHidden,
          };
          if (tag.localName === "textarea") {
            formObject.rows = tag.getAttribute("rows") as string | undefined;
            formObject.cols = tag.getAttribute("cols") as string | undefined;
          }
          if (tag.localName === "button") {
            formObject.childNodes?.push({
              name: "#text",
              content: tag.textContent || "",
              position: -1,
            });
          }
          if (
            tag instanceof HTMLSelectElement &&
            tag.selectedOptions.length > 0
          ) {
            formObject.selectedOptionContent =
              tag.selectedOptions[0].textContent
                ?.trim()
                .normalize("NFD")
                .replace(/[\u0300-\u036f]/gu, "");
          }
          const textContent =
            formObject.selectedOptionContent || formObject.value || "";
          this._calendarHelper.calendarForm(
            textContent,
            tag,
            formObject,
            this._formsCache,
          );
        }
      } else if (tag.localName === "img" && tag instanceof HTMLImageElement) {
        if (
          !tag.src?.includes("maps.googleapis.com") &&
          !tag.src?.includes("tile.openstreetmap.org")
        ) {
          const datas = readerAdapter.handleImage(tag);
          formObject = datas;
        }
      } else if (tag.localName === "svg" && tag instanceof SVGElement) {
        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());
        }
        if (
          tag.getAttribute("width") !== "0" &&
          tag.getAttribute("height") !== "0"
        ) {
          formObject = {
            name: "img",
            src: hash,
            position,
            width: tag.getAttribute("width") as string | undefined,
            height: tag.getAttribute("height") as string | undefined,
            insert: position === 0 ? "before" : "after",
            isHidden:
              tag.offsetParent == undefined ||
              visibility === "hidden" ||
              parseInt(opacity) === 0,
          };
        }
      } else {
        const clonedTag = tag.cloneNode(true) as HTMLElement;
        const isHidden = readerAdapter.handleStyles(clonedTag, tag);
        const allTagChildren = Array.from(tag.childNodes) as HTMLElement[];
        if (
          clonedTag.dataset.lisioClickable == undefined &&
          (clonedTag instanceof HTMLLinkElement ||
            clonedTag instanceof HTMLButtonElement ||
            (clonedTag instanceof HTMLInputElement &&
              clonedTag.getAttribute("type") === "button") ||
            tag.onclick != undefined)
        ) {
          clonedTag.dataset.lisioClickable =
            readerAdapter.dataLisioClickable.toString();
          tag.dataset.lisioClickable =
            readerAdapter.dataLisioClickable.toString();
          readerAdapter.dataLisioClickable++;
        }
        const position = readerAdapter.all.indexOf(tag);
        formObject = {
          name: clonedTag.localName,
          classes: clonedTag.className,
          childNodes: [],
          position,
          isHidden,
          clickable:
            clonedTag.dataset.lisioClickable == undefined
              ? undefined
              : Number.parseInt(clonedTag.dataset.lisioClickable),
        };
        const closestA = tag.parentElement;
        if (closestA instanceof HTMLAnchorElement) {
          formObject.name = "a";
          formObject.blank = `${closestA.target === "_blank"}`;
          formObject.href =
            closestA.href === "" ? "" : new URL(closestA.href).href;
          if (closestA.dataset.lisioClickable == undefined) {
            closestA.dataset.lisioClickable =
              readerAdapter.dataLisioClickable.toString();
          }
          formObject.clickable = Number.parseInt(
            closestA.dataset.lisioClickable || "-1",
          );
          readerAdapter.dataLisioClickable++;
        } else if (clonedTag instanceof HTMLAnchorElement) {
          formObject.blank = `${clonedTag.target === "_blank"}`;
          formObject.href =
            clonedTag.href === "" ? "" : new URL(clonedTag.href).href;
          if (clonedTag.dataset.lisioClickable == undefined) {
            tag.dataset.lisioClickable =
              readerAdapter.dataLisioClickable.toString();
          }
          formObject.clickable = Number.parseInt(
            tag.dataset.lisioClickable || "-1",
          );
          readerAdapter.dataLisioClickable++;
        }
        const textContent = tag.textContent?.trim() || "";
        if (
          this._calendarHelper.calendarForm(
            textContent,
            tag,
            formObject,
            this._formsCache,
          )
        ) {
          /* empty */
        } else {
          if (tag instanceof HTMLLabelElement) {
            formObject.for = tag.getAttribute("for") as string | undefined;
            this._formsCache.set(position, formObject);
          }
          for (const [index, child] of Array.from(
            clonedTag.childNodes,
          ).entries()) {
            if (child.textContent?.trim() == "") {
              child.remove();
              continue;
            }
            if (child.nodeType === 1 && child instanceof HTMLElement) {
              readerAdapter.handleStyles(child, allTagChildren[index]);
              if (
                child.dataset.lisioClickable == undefined &&
                (child instanceof HTMLLinkElement ||
                  child instanceof HTMLButtonElement ||
                  (child instanceof HTMLInputElement &&
                    child.getAttribute("type") === "button") ||
                  child.onclick != undefined)
              ) {
                child.dataset.lisioClickable =
                  readerAdapter.dataLisioClickable.toString();
                allTagChildren[index].dataset.lisioClickable =
                  readerAdapter.dataLisioClickable.toString();
                readerAdapter.dataLisioClickable++;
              }
              formObject.childNodes?.push({
                name: child.localName,
                index: child.dataset.lisioIndex,
                childNodes: Array.from(child.childNodes)
                  .filter((child) => child.textContent?.trim() !== "")
                  .map((child) => {
                    return {
                      name: child.nodeName,
                      content: child.textContent,
                      position: -1,
                    };
                  }) as ReaderObject[],
                classes: child.className,
                position,
                isHidden,
                clickable: Number.parseInt(
                  child.dataset.lisioClickable || "-1",
                ),
              });
            } else {
              formObject.childNodes?.push({
                name: child.nodeName,
                content: child.textContent || "",
                position: -1,
              });
            }
          }
        }
      }
    }
  }
}

export default ExploreFormHelper;
