import { FC, useCallback, useEffect, useRef, useState } from "react";
import { ISpoolCanvas } from "../../definitions/spools";
import {
  getLineLength,
  getLineArc,
  getLabelCordX,
  getLabelCordY,
} from "../../helpers/mathHelpers";
import { getCordinates } from "../Point/Point";
import { ItemPoint, PointLine, PointLabel } from "../Point/Point.styles";
import { useStoreState } from "../../store";

interface ISpoolProps {
  spool: ISpoolCanvas;
  scale: number;
  onClick?: any;
  active: boolean;
  showDetails: (spoolID: string) => void;
  saveChanges: (spool: ISpoolCanvas) => void;
  pdfHeight?: number;
  editMode: boolean;
  pdfWidth?: number;
  handleShortcut: (key: string, elementID: string, elementType: string) => void;
  focused: boolean;
}
export const Spool: FC<ISpoolProps> = ({
  spool,
  onClick,
  active,
  scale,
  showDetails,
  saveChanges,
  pdfHeight = 0,
  editMode,
  pdfWidth = 0,
  handleShortcut,
  focused,
}) => {
  const { orgRole } = useStoreState((state) => state.user.userDetails);

  interface IPointsData {
    move: boolean;
    alt: boolean;
    x: number;
    y: number;
    editMode: boolean;
    label_x: number;
    label_y: number;
    pageHeight: number;
    pageWidth: number;
    lock: boolean;
    scale: number;
  }
  const pointRef = useRef<HTMLDivElement>(null);

  const [startPos, setStartPos] = useState({ x: 0, y: 0 });
  const [pointPos, setPointPos] = useState({
    left: 0,
    top: 0,
    labelTop: 0,
    labelLeft: 0,
  });

  const [pointsData, setPointsData] = useState<IPointsData>({
    move: false,
    alt: false,
    editMode: editMode,
    x: spool.x,
    y: spool.y,
    label_x: spool.label_x,
    label_y: spool.label_y,
    pageHeight: pdfHeight,
    pageWidth: pdfWidth,
    lock: spool.lock,
    scale: scale,
  });
  const updateElements = useCallback(() => {
    saveChanges({
      ...spool,
      x: pointsData.x,
      y: pointsData.y,
      label_x: pointsData.label_x,
      label_y: pointsData.label_y,
    });
  }, [spool, pointsData, saveChanges]);

  const startMove = useCallback(
    (event: MouseEvent) => {
      event.stopPropagation();
      showDetails(spool.instanceID);

      if (pointsData.lock) return;
      if (orgRole !== "readOnly") {
        setStartPos({ x: event.clientX, y: event.clientY });
        setPointPos({
          left: pointsData.x * pointsData.scale,
          top: pointsData.y * pointsData.scale,
          labelLeft: pointsData.label_x * pointsData.scale,
          labelTop: pointsData.label_y * pointsData.scale,
        });
        setPointsData((prev) => ({
          ...prev,
          alt: event.altKey,
          move: true,
        }));
      }
    },
    [active, showDetails, spool, scale],
  );

  const move = useCallback(
    (event: MouseEvent) => {
      if (!pointsData.move || spool.lock) return;
      event.stopPropagation();
      if (orgRole !== "readOnly") {
        const newDelta = {
          left: event.clientX - startPos.x,
          top: event.clientY - startPos.y,
        };

        if (
          newDelta.left !== 0 &&
          newDelta.top !== 0 &&
          event.clientX !== 0 &&
          event.clientY !== 0
        ) {
          if (pointsData.alt) {
            setPointsData((prev) => ({
              ...prev,
              label_x: (pointPos.labelLeft + newDelta.left) / pointsData.scale,
              label_y: (pointPos.labelTop + newDelta.top) / pointsData.scale,
            }));
          } else {
            setPointsData((prev) => ({
              ...prev,
              x: (pointPos.left + newDelta.left) / pointsData.scale,
              y: (pointPos.top + newDelta.top) / pointsData.scale,
            }));
          }
        }
      }
    },
    [pointsData.move, pointsData.alt, showDetails, active, scale, pointRef],
  );

  const endMove = useCallback(
    (event: MouseEvent) => {
      if (!pointsData.move || pointsData.lock) return;
      event.stopPropagation();
      if (orgRole !== "readOnly") {
        setPointsData((prev) => ({
          ...prev,
          move: false,
          alt: false,
        }));

        updateElements();
      }
    },
    [pointsData.move, updateElements],
  );
  const shortScope = ["e", "E", "x", "X", "Backspace", "Delete"];

  useEffect(() => {
    const point = pointRef.current;
    const handleKeyDown = (e: KeyboardEvent) => {
      if (orgRole !== "readOnly") {
        if (active && !editMode) {
          if (shortScope.includes(e.key)) {
            let action = "";
            if (e.key === "e" || e.key === "E") {
              action = "edit";
            } else if (
              e.key === "x" ||
              e.key === "X" ||
              e.key === "Backspace" ||
              e.key === "Delete"
            ) {
              action = "delete";
            }
            if (action !== "") {
              handleShortcut(action, spool.instanceID, "spool");
            }
          }
        }
      }
    };
    if (!point) return;
    // if (point && active) {
    point.addEventListener("mousedown", startMove);
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseup", endMove);
    window.addEventListener("mouseleave", endMove);
    document.addEventListener("keydown", handleKeyDown);
    // }
    return () => {
      point.removeEventListener("mousedown", startMove);
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseup", endMove);
      window.removeEventListener("mouseleave", endMove);
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [startMove, move, endMove]);

  useEffect(() => {
    setPointsData((prev) => ({
      ...prev,
      x: spool.x,
      y: spool.y,
      label_x: spool.label_x,
      label_y: spool.label_y,
      pageHeight: pdfHeight,
      pageWidth: pdfWidth,
      scale: scale,
      editMode: editMode,
    }));
  }, [spool, pdfHeight, pdfWidth, scale, editMode]);

  return (
    <ItemPoint
      onClick={onClick}
      active={active || focused}
      isEditMode={pointsData.editMode}
      style={{
        left: getCordinates(pointsData.x * pointsData.scale) + "px",
        top: getCordinates(pointsData.y * pointsData.scale) + "px",
      }}
    >
      <PointLine
        active={active || focused}
        isEditMode={pointsData.editMode}
        style={{
          height:
            getLineLength(
              pointsData.label_x * pointsData.scale,
              pointsData.label_y * pointsData.scale,
            ) + "px",
          transform: `rotate(${getLineArc(
            pointsData.label_x * pointsData.scale,
            pointsData.label_y * pointsData.scale,
          )}deg)`,
        }}
      />
      <PointLabel
        ref={pointRef}
        isEditMode={pointsData.editMode}
        active={active || focused}
        label={spool.spoolName}
        move={pointsData.move}
        scale={pointsData.scale}
        // onClick={(e) => setAtcive(e)}
        isSquere={true}
        style={{
          left:
            getLabelCordX(pointsData.label_x, pointsData.scale, true) + "px",
          top: getLabelCordY(pointsData.label_y, pointsData.scale, true) + "px",
        }}
      />
    </ItemPoint>
  );
};
