import {
  cleardragQuestionContentId,
  setModalQuestionParentContentId,
  setOpenedModalQuestions,
  updateDeleteId,
  updateOpenedModalSettingsId,
} from "@root/uiTools/actions";
import type {
  AbstractEventObject,
  Core,
  NodeSingular,
  SingularData,
} from "cytoscape";
import { getPopperInstance } from "cytoscape-popper";
import { useCallback, type MutableRefObject, useRef } from "react";
import { addNode } from "../helper";

type PopperItem = {
  id: () => string;
};

type Modifier = {
  name: string;
  options: unknown;
};

type PopperConfig = {
  popper: {
    placement: string;
    modifiers?: Modifier[];
  };
  content: (items: PopperItem[]) => void;
};

type PopperInstance = ReturnType<getPopperInstance<SingularData>>;

type NodeSingularWithPopper = NodeSingular & {
  popper: (config: PopperConfig) => PopperInstance;
};

export const usePopper = ({
  cyRef,
}: {
  cyRef: MutableRefObject<Core | null>;
}) => {
  const popperContainerRef = useRef<HTMLDivElement | null>(null);
  const popperInstancesRef = useRef<PopperInstance[]>([]);

  const removeAllPoppers = useCallback(() => {
    cyRef.current?.removeListener("zoom render");

    popperInstancesRef.current.forEach((p) => p.destroy());
    popperInstancesRef.current = [];
    popperContainerRef.current?.remove();
    popperContainerRef.current = null;
  }, []);

  const recreatePoppers = useCallback(() => {
    removeAllPoppers();

    const cy = cyRef.current;
    if (!cy) return;

    const container = cy.container();

    if (!container) {
      console.warn("Cannot create popper container");
      return;
    }

    if (!popperContainerRef.current) {
      popperContainerRef.current = document.createElement("div");
      popperContainerRef.current.setAttribute("id", "poppers-container");
      container.append(popperContainerRef.current);
    }

    cy.nodes().forEach((item) => {
      const node = item as NodeSingularWithPopper;

      const layoutsPopper = node.popper({
        popper: {
          placement: "left",
          modifiers: [{ name: "flip", options: { boundary: node } }],
        },
        content: (items) => {
          const item = items[0];
          const itemId = item.id();
          const itemElement = popperContainerRef.current?.querySelector(
            `.popper-layout[data-id='${itemId}']`,
          );
          if (itemElement) {
            return itemElement;
          }

          const layoutElement = document.createElement("div");
          layoutElement.style.zIndex = "0";
          layoutElement.classList.add("popper-layout");
          layoutElement.setAttribute("data-id", item.id());
          layoutElement.addEventListener("pointerup", () => {
            //Узнаём грани, идущие от этой ноды
            setModalQuestionParentContentId(item.id());
            setOpenedModalQuestions(true);
          });
          popperContainerRef.current?.appendChild(layoutElement);

          return layoutElement;
        },
      });
      popperInstancesRef.current.push(layoutsPopper);

      const plusesPopper = node.popper({
        popper: {
          placement: "right",
          modifiers: [{ name: "flip", options: { boundary: node } }],
        },
        content: ([item]) => {
          const itemId = item.id();
          const itemElement = popperContainerRef.current?.querySelector(
            `.popper-plus[data-id='${itemId}']`,
          );
          if (itemElement) {
            return itemElement;
          }

          const plusElement = document.createElement("div");
          plusElement.classList.add("popper-plus");
          plusElement.setAttribute("data-id", item.id());
          plusElement.style.zIndex = "1";
          plusElement.addEventListener("pointerup", () => {
            addNode({ parentNodeContentId: node.id() });
            cleardragQuestionContentId();
          });

          popperContainerRef.current?.appendChild(plusElement);

          return plusElement;
        },
      });
      popperInstancesRef.current.push(plusesPopper);

      const crossesPopper = node.popper({
        popper: {
          placement: "top-end",
          modifiers: [{ name: "flip", options: { boundary: node } }],
        },
        content: ([item]) => {
          const itemId = item.id();
          const itemElement = popperContainerRef.current?.querySelector(
            `.popper-cross[data-id='${itemId}']`,
          );
          if (itemElement) {
            return itemElement;
          }

          const crossElement = document.createElement("div");
          crossElement.classList.add("popper-cross");
          crossElement.setAttribute("data-id", item.id());
          crossElement.style.zIndex = "2";
          popperContainerRef.current?.appendChild(crossElement);
          crossElement.addEventListener("pointerup", () => {
            updateDeleteId(node.id());
          });

          return crossElement;
        },
      });
      popperInstancesRef.current.push(crossesPopper);

      let gearsPopper: PopperInstance | null = null;
      if (node.data().root !== true) {
        gearsPopper = node.popper({
          popper: {
            placement: "left",
            modifiers: [{ name: "flip", options: { boundary: node } }],
          },
          content: ([item]) => {
            const itemId = item.id();

            const itemElement = popperContainerRef.current?.querySelector(
              `.popper-gear[data-id='${itemId}']`,
            );
            if (itemElement) {
              return itemElement;
            }

            const gearElement = document.createElement("div");
            gearElement.classList.add("popper-gear");
            gearElement.setAttribute("data-id", item.id());
            gearElement.style.zIndex = "1";
            popperContainerRef.current?.appendChild(gearElement);
            gearElement.addEventListener("pointerup", () => {
              updateOpenedModalSettingsId(item.id());
            });

            return gearElement;
          },
        });
        popperInstancesRef.current.push(gearsPopper);
      }

      const onZoom = (event: AbstractEventObject) => {
        const zoom = event.cy.zoom();

        crossesPopper.setOptions({
          modifiers: [
            { name: "flip", options: { boundary: node } },
            { name: "offset", options: { offset: [-5 * zoom, -30 * zoom] } },
          ],
        });

        layoutsPopper.setOptions({
          modifiers: [
            { name: "flip", options: { boundary: node } },
            { name: "offset", options: { offset: [0, -130 * zoom] } },
          ],
        });
        plusesPopper.setOptions({
          modifiers: [
            { name: "flip", options: { boundary: node } },
            { name: "offset", options: { offset: [0, 0] } },
          ],
        });
        gearsPopper?.setOptions({
          modifiers: [
            { name: "flip", options: { boundary: node } },
            { name: "offset", options: { offset: [0, 0] } },
          ],
        });

        popperContainerRef.current
          ?.querySelectorAll(".popper-layout")
          .forEach((item) => {
            const element = item as HTMLDivElement;
            element.style.width = `${130 * zoom}px`;
            element.style.height = `${130 * zoom}px`;
          });

        popperContainerRef.current
          ?.querySelectorAll(".popper-plus")
          .forEach((item) => {
            const element = item as HTMLDivElement;
            element.style.width = `${40 * zoom}px`;
            element.style.height = `${40 * zoom}px`;
            element.style.fontSize = `${40 * zoom}px`;
            element.style.borderRadius = `${6 * zoom}px`;
          });

        popperContainerRef.current
          ?.querySelectorAll(".popper-cross")
          .forEach((item) => {
            const element = item as HTMLDivElement;
            element.style.width = `${24 * zoom}px`;
            element.style.height = `${24 * zoom}px`;
            element.style.fontSize = `${24 * zoom}px`;
            element.style.borderRadius = `${6 * zoom}px`;
          });

        popperContainerRef?.current
          ?.querySelectorAll(".popper-gear")
          .forEach((item) => {
            const element = item as HTMLDivElement;
            element.style.width = `${60 * zoom}px`;
            element.style.height = `${40 * zoom}px`;
          });
      };

      cy.on("zoom render", onZoom);
    });
  }, []);

  return { removeAllPoppers, recreatePoppers };
};
