import { useEffect, useLayoutEffect, useRef, useState } from "react";
import Cytoscape from "cytoscape";
import CytoscapeComponent from "react-cytoscapejs";
import popper from "cytoscape-popper";
import { Button, Box } from "@mui/material";
import { withErrorBoundary } from "react-error-boundary";
import { enqueueSnackbar } from "notistack";

import { useCurrentQuiz } from "@root/quizes/hooks";
import { updateRootContentId } from "@root/quizes/actions";
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
import { useQuestionsStore } from "@root/questions/store";
import { useUiTools } from "@root/uiTools/store";
import {
  deleteQuestion,
  updateQuestion,
  getQuestionByContentId,
  clearRuleForAll,
  createResult,
} from "@root/questions/actions";
import {
  updateModalInfoWhyCantCreate,
  updateOpenedModalSettingsId
} from "@root/uiTools/actions";
import { cleardragQuestionContentId } from "@root/uiTools/actions";
import { updateDeleteId } from "@root/uiTools/actions";

import { DeleteNodeModal } from "../DeleteNodeModal";
import { ProblemIcon } from "@ui_kit/ProblemIcon";

import { useRemoveNode } from "./hooks/useRemoveNode";
import { usePopper } from "./hooks/usePopper";

import { storeToNodes } from "./helper";
import { stylesheet } from "./style/stylesheet";
import "./style/styles.css";

import type { Core } from "cytoscape";

Cytoscape.use(popper);

interface CsComponentProps {
  modalQuestionParentContentId: string;
  modalQuestionTargetContentId: string;
  setOpenedModalQuestions: (open: boolean) => void;
  setModalQuestionParentContentId: (id: string) => void;
  setModalQuestionTargetContentId: (id: string) => void;
}

function CsComponent({
  modalQuestionParentContentId,
  modalQuestionTargetContentId,
  setOpenedModalQuestions,
  setModalQuestionParentContentId,
  setModalQuestionTargetContentId
}: CsComponentProps) {
  const quiz = useCurrentQuiz();

  const { dragQuestionContentId, desireToOpenABranchingModal, canCreatePublic } = useUiTools()
  const trashQuestions = useQuestionsStore().questions
  const questions = trashQuestions.filter((question) => question.type !== "result" && question.type !== null)
  const [startCreate, setStartCreate] = useState("");
  const [startRemove, setStartRemove] = useState("");

  const cyRef = useRef<Core | null>(null);
  const layoutsContainer = useRef<HTMLDivElement | null>(null);
  const plusesContainer = useRef<HTMLDivElement | null>(null);
  const crossesContainer = useRef<HTMLDivElement | null>(null);
  const gearsContainer = useRef<HTMLDivElement | null>(null);

  const { layoutOptions } = usePopper({
    layoutsContainer,
    plusesContainer,
    crossesContainer,
    gearsContainer,
    setModalQuestionParentContentId,
    setOpenedModalQuestions,
    setStartCreate,
    setStartRemove,
  });
  const { removeNode } = useRemoveNode({
    cyRef,
    layoutOptions,
    layoutsContainer,
    plusesContainer,
    crossesContainer,
    gearsContainer,
  });


  useEffect(() => {
    return () => {
      // if (!canCreatePublic) updateModalInfoWhyCantCreate(true)
    }
  }, []);

  useLayoutEffect(() => {
    const cy = cyRef?.current
    if (desireToOpenABranchingModal) {
      setTimeout(() => {
        cy?.getElementById(desireToOpenABranchingModal)?.data("eroticeyeblink", true)
      }, 250)
    } else {
      cy?.elements().data("eroticeyeblink", false)
    }
  }, [desireToOpenABranchingModal])
  useLayoutEffect(() => {
    updateOpenedModalSettingsId()
    //  updateRootContentId(quiz.id, "")
    //  clearRuleForAll()
  }, [])
  useEffect(() => {
    if (modalQuestionTargetContentId.length !== 0 && modalQuestionParentContentId.length !== 0) {
      addNode({ parentNodeContentId: modalQuestionParentContentId, targetNodeContentId: modalQuestionTargetContentId })
    }
    setModalQuestionParentContentId("")
    setModalQuestionTargetContentId("")
  }, [modalQuestionTargetContentId])

  const addNode = ({ parentNodeContentId, targetNodeContentId }: { parentNodeContentId: string, targetNodeContentId?: string }) => {
    if (quiz) {

      //запрещаем работу родителя-ребенка если это один и тот же вопрос
      if (parentNodeContentId === targetNodeContentId) return


      const cy = cyRef?.current
      const parentNodeChildren = cy?.$('edge[source = "' + parentNodeContentId + '"]')?.length
      //если есть инфо о выбранном вопросе из модалки - берём родителя из инфо модалки. Иначе из значения дропа
      const targetQuestion = { ...getQuestionByContentId(targetNodeContentId || dragQuestionContentId) } as AnyTypedQuizQuestion
      if (Object.keys(targetQuestion).length !== 0 && parentNodeContentId && parentNodeChildren !== undefined) {
        clearDataAfterAddNode({ parentNodeContentId, targetQuestion, parentNodeChildren })
        cy?.data('changed', true)
        createResult(quiz.backendId, targetQuestion.content.id)
        const es = cy?.add([
          {
            data: {
              id: targetQuestion.content.id,
              label: targetQuestion.title === "" || targetQuestion.title === " " ? "noname" : targetQuestion.title
            }
          },
          {
            data: {
              source: parentNodeContentId,
              target: targetQuestion.content.id
            }
          }
        ])
        cy?.layout(layoutOptions).run()
        cy?.center(es)
      } else {
        enqueueSnackbar("Добавляемый вопрос не найден")
      }

    } else {
      enqueueSnackbar("Квиз не найден")
    }
  }

  const clearDataAfterAddNode = ({ parentNodeContentId, targetQuestion, parentNodeChildren }: { parentNodeContentId: string, targetQuestion: AnyTypedQuizQuestion, parentNodeChildren: number }) => {

    const parentQuestion = { ...getQuestionByContentId(parentNodeContentId) } as AnyTypedQuizQuestion


    //смотрим не добавлен ли родителю result. Если да - делаем его неактивным. Веточкам result не нужен
    trashQuestions.forEach((targetQuestion) => {
      if (targetQuestion.type === "result" && targetQuestion.content.rule.parentId === parentQuestion.content.id) {
        updateQuestion(targetQuestion.id, (q) => q.content.usage = false);
      }
    })


    //предупреждаем добавленный вопрос о том, кто его родитель
    updateQuestion(targetQuestion.content.id, question => {
      question.content.rule.parentId = parentNodeContentId
      question.content.rule.main = []
    })
    //предупреждаем родителя о новом потомке (если он ещё не знает о нём)
    if (!parentQuestion.content.rule.children.includes(targetQuestion.content.id)) updateQuestion(parentNodeContentId, question => {
      question.content.rule.children = [...question.content.rule.children, targetQuestion.content.id]
    })


    //Если детей больше 1 - предупреждаем стор вопросов об открытии модалки ветвления
    if (parentQuestion.content.rule.children >= 1) {
      updateOpenedModalSettingsId(targetQuestion.content.id)
    }
  }


  useEffect(() => {
    if (startCreate) {
      addNode({ parentNodeContentId: startCreate });
      cleardragQuestionContentId();
      setStartCreate("");
    }
  }, [startCreate]);

  useEffect(() => {
    if (startRemove) {
      updateDeleteId(startRemove);
      setStartRemove("");
    }
  }, [startRemove]);

  useEffect(() => {
    document
      .querySelector("#root")
      ?.addEventListener("mouseup", cleardragQuestionContentId);
    const cy = cyRef.current;
    const eles = cy?.add(
      storeToNodes(
        questions.filter(
          (question) => question.type && question.type !== "result"
        ) as AnyTypedQuizQuestion[]
      )
    );
    cy?.data("changed", true);
    // cy.data('changed', true)
    const elecs = eles?.layout(layoutOptions).run();
    cy?.on("add", () => cy.data("changed", true));
    cy?.fit();
    //cy?.layout().run()

    return () => {
      document
        .querySelector("#root")
        ?.removeEventListener("mouseup", cleardragQuestionContentId);
      layoutsContainer.current?.remove();
      plusesContainer.current?.remove();
      crossesContainer.current?.remove();
      gearsContainer.current?.remove();
    };
  }, []);


  return (
    <>
      <Box
        mb="20px">
        <Button
          sx={{
            height: "27px",
            color: "#7E2AEA",
            textDecoration: "underline",
            fontSize: "16px",
          }}
          variant="text"
          onClick={() => {

            cyRef.current?.fit()

          }}
        >
          Выровнять
        </Button>
        <ProblemIcon blink={!canCreatePublic} onClick={() => updateModalInfoWhyCantCreate(true)} />
      </Box>

      <CytoscapeComponent
        wheelSensitivity={0.1}
        elements={[]}
        // elements={createGraphElements(tree, quiz)}
        style={{ height: "480px", background: "#F2F3F7" }}
        stylesheet={stylesheet}
        layout={(layoutOptions)}
        cy={(cy) => {
          cyRef.current = cy;
        }}
        autoungrabify={true}
      />
      <DeleteNodeModal removeNode={removeNode} />
    </>
  );
};

function Clear() {
  const quiz = useCurrentQuiz();
  if (quiz) {
    updateRootContentId(quiz?.id, "");
  }
  clearRuleForAll()
  return <></>
}

export default withErrorBoundary(CsComponent, {
  fallback: <Clear />,
  onError: (error, info) => {
    enqueueSnackbar("Дерево порвалось")
    console.log(info)
    console.log(error)
  },
});
