import React, { FC, useCallback, useEffect, useRef, useState } from "react";
import { Icon } from "venice-ui";
import { Colors } from "../../untils/Theme";
import {
  AdditionalElementsWrapper,
  Edge,
  ElementControl,
} from "./AdditionalElements.styles";
import {
  getCordinates,
  calculateMapElementHeight,
  calculateMapElementWidth,
  calculateMapElementArc,
  checkPropInElement,
  getArc,
  getHeight,
  getWidth,
} from "./additionalHelper";
import {
  ADDITIONAL_TYPES,
  IAdditionalElements,
  IElementData,
  TAdditionalType,
} from "../../definitions/additional";

export const EdgeElement: FC<IAdditionalElements> = ({
  element,
  scale,
  active,
  editMode,
  pdfHeight = 0,
  pdfWidth = 0,
  showDetails,
  saveChanges,
  handleShortcut,
  focused,
  inputFocused
}) => {
  const pointRef = useRef<HTMLDivElement>(null);
  const edgeStartRef = useRef<HTMLDivElement>(null);
  const edgeEndRef = useRef<HTMLDivElement>(null);

  const [startPos, setStartPos] = useState({ x: 0, y: 0 });
  const [pointPos, setPointPos] = useState({
    startLeft: 0,
    startTop: 0,
    endLeft: 0,
    endTop: 0,
  });

  const [elementData, setElementData] = useState<IElementData>({
    move: false,
    editMode: editMode,
    x: element.x,
    y: element.y,
    elementMode: element.type,
    pageHeight: pdfHeight,
    pageWidth: pdfWidth,
    rotate: getArc(element),
    width: getWidth(element),
    height: getHeight(element),
    size: (checkPropInElement(element, "size", "number") as number) || 0,
    end_x: (checkPropInElement(element, "end_x", "number") as number) || 0,
    end_y: (checkPropInElement(element, "end_y", "number") as number) || 0,
    mode: "element",
    scale: scale,
    scaleAction: false,
    rotateAction: false,
  });

  const updateElement = useCallback(() => {
    saveChanges(
      {
        ...element,
        x: elementData.x,
        y: elementData.y,
        end_x: elementData.end_x,
        end_y: elementData.end_y,
        size: elementData.size,
        rotation: elementData.rotate,
        height: elementData.height,
      },
      false
    );
  }, [element, elementData, saveChanges]);

  const startMove = useCallback(
    (event: MouseEvent, mode: string) => {
      event.stopPropagation();
      if (element.lock) return;

      showDetails(element.id!, true, false);
      setStartPos({ x: event.clientX, y: event.clientY });
      setPointPos({
        startLeft: elementData.x * elementData.scale,
        startTop: elementData.y * elementData.scale,
        endLeft: elementData.end_x * elementData.scale,
        endTop: elementData.end_y * elementData.scale,
      });
      setElementData((prev) => ({
        ...prev,
        size: element.size,
        move: true,
        mode: mode,
      }));
    },
    [element, elementData, showDetails]
  );

  const move = useCallback(
    (event: MouseEvent) => {
      if (!elementData.move || element.lock) return;
      event.stopPropagation();
      const newDelta = {
        left: event.clientX - startPos.x,
        top: event.clientY - startPos.y,
      };
      if (elementData.mode === "edgeStart") {
        setElementData((prev) => ({
          ...prev,
          x: (pointPos.startLeft + newDelta.left) / elementData.scale,
          y: (pointPos.startTop + newDelta.top) / elementData.scale,
        }));
      } else if (elementData.mode === "edgeEnd") {
        setElementData((prev) => ({
          ...prev,
          end_x: (pointPos.endLeft + newDelta.left) / elementData.scale,
          end_y: (pointPos.endTop + newDelta.top) / elementData.scale,
        }));
      } else {
        setElementData((prev) => ({
          ...prev,
          x: (pointPos.startLeft + newDelta.left) / elementData.scale,
          y: (pointPos.startTop + newDelta.top) / elementData.scale,
          end_x: (pointPos.endLeft + newDelta.left) / elementData.scale,
          end_y: (pointPos.endTop + newDelta.top) / elementData.scale,
        }));
      }
    },
    [elementData.move, element.lock, element.height, startPos, pointPos]
  );

  const endMove = useCallback(
    (event: MouseEvent) => {
      if (!elementData.move) return;
      event.stopPropagation();
      setElementData((prev) => ({
        ...prev,
        move: false,
        mode: "",
      }));

      updateElement();
    },
    [elementData.move, updateElement]
  );

  const handleEdgeStartMouseDown = useCallback(
    (e: MouseEvent) => startMove(e, "edgeStart"),
    [startMove]
  );
  const handleEdgeEndMouseDown = useCallback(
    (e: MouseEvent) => startMove(e, "edgeEnd"),
    [startMove]
  );
  const handlePointMouseDown = useCallback(
    (e: MouseEvent) => startMove(e, "element"),
    [startMove]
  );
  const shortScope = ["x", "X", "Backspace", "Delete"];

  useEffect(() => {
    const point = pointRef.current;
    const edgeStart = edgeStartRef.current;
    const edgeEnd = edgeEndRef.current;
    const handleKeyDown = (e: KeyboardEvent) => {
      if (active && !inputFocused) {
        if (shortScope.includes(e.key)) {
          handleShortcut("delete", element.id, "mapElement");
        }
      }
    };

    if (point) point.addEventListener("mousedown", handlePointMouseDown);
    if (edgeStart)
      edgeStart.addEventListener("mousedown", handleEdgeStartMouseDown);
    if (edgeEnd) edgeEnd.addEventListener("mousedown", handleEdgeEndMouseDown);

    window.addEventListener("mousemove", move, { passive: true });
    window.addEventListener("mouseup", endMove);
    window.addEventListener("mouseleave", endMove);
    document.addEventListener("keydown", handleKeyDown);

    return () => {
      if (point) point.removeEventListener("mousedown", handlePointMouseDown);
      if (edgeStart)
        edgeStart.removeEventListener("mousedown", handleEdgeStartMouseDown);
      if (edgeEnd)
        edgeEnd.removeEventListener("mousedown", handleEdgeEndMouseDown);

      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseup", endMove);
      window.removeEventListener("mouseleave", endMove);
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [startMove, move, endMove]);

  useEffect(() => {
    setElementData((prev) => ({
      ...prev,
      x: element.x,
      y: element.y,
      end_x: element.end_x,
      end_y: element.end_y,
      width: getWidth(element),
      height: getHeight(element),
      pageHeight: pdfHeight,
      pageWidth: pdfWidth,
      editMode: editMode,
      rotate: element.rotation,
      scale: scale,
    }));
  }, [element, pdfHeight, pdfWidth, scale, editMode]);

  return (
    <AdditionalElementsWrapper
      isActive={false}
      isEditMode={elementData.editMode}
      origin={true}
      style={{
        left:
          getCordinates(
            elementData.x * elementData.scale,
            elementData.width * elementData.scale,
            ADDITIONAL_TYPES.edge as TAdditionalType
          ) + "px",
        top:
          getCordinates(
            elementData.y * elementData.scale,
            elementData.height * elementData.scale,
            ADDITIONAL_TYPES.edge as TAdditionalType
          ) + "px",
        height: `${
          calculateMapElementHeight(elementData) * elementData.scale
        }px`,
        width: `${calculateMapElementWidth(elementData) * elementData.scale}px`,
        transform: `rotate(${calculateMapElementArc(elementData)}deg)`,
      }}
    >
      <>
        <Edge isActive={active || focused} ref={pointRef} />
        {active && (
          <>
            <ElementControl
              ref={edgeStartRef}
              style={{
                left: "-6px",
                top: (elementData.height * elementData.scale) / 2 - 6 + "px",
              }}
            />

            <ElementControl
              ref={edgeEndRef}
              style={{
                right: "-6px",
                top: (elementData.height * elementData.scale) / 2 - 6 + "px",
              }}
            />
          </>
        )}
      </>
    </AdditionalElementsWrapper>
  );
};
