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

export const CloudElement: FC<IAdditionalElements> = ({
  element,
  scale,
  active,
  editMode,
  pdfHeight = 0,
  pdfWidth = 0,
  showDetails,
  saveChanges,
  handleShortcut,
  focused,
  inputFocused
}) => {
  const pointRef = useRef<HTMLDivElement>(null);
  const nwRef = useRef<HTMLDivElement>(null);
  const neRef = useRef<HTMLDivElement>(null);
  const seRef = useRef<HTMLDivElement>(null);
  const swRef = useRef<HTMLDivElement>(null);

  const [startPos, setStartPos] = useState({ x: 0, y: 0 });
  const [pointPos, setPointPos] = useState({
    startX: 0,
    startY: 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: 0, // not use in this object
    end_x: 0, // not use in this object
    end_y: 0, // not use in this object
    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.width,
        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({
        startX: elementData.x * elementData.scale,
        startY: elementData.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,
      };

      const alphaRad = (elementData.rotate * Math.PI) / 180;

      const newWidth =
        (elementData.width * elementData.scale + newDelta.left) /
        elementData.scale;
      const newHeight =
        (elementData.height * elementData.scale + newDelta.top) /
        elementData.scale;
      const inverseWidth =
        (elementData.width * elementData.scale - newDelta.left) /
        elementData.scale;
      const inverseHeight =
        (elementData.height * elementData.scale - newDelta.top) /
        elementData.scale;
      const inversePositionX =
        (pointPos.startX + newDelta.left + -newDelta.left / 2) /
        elementData.scale;
      const inversePositionY =
        (pointPos.startY + newDelta.top + -newDelta.top / 2) /
        elementData.scale;
      const positionX =
        (pointPos.startX + newDelta.left / 2) / elementData.scale;
      const positionY =
        (pointPos.startY + newDelta.top / 2) / elementData.scale;

      if (elementData.mode === "nwPoint") {
        // const rotatedX =   inversePositionX * Math.cos(alphaRad) - (inversePositionY * Math.sin(alphaRad));
        // const rotatedY = inversePositionX * Math.sin(alphaRad) + inversePositionY * Math.cos(alphaRad);
        setElementData((prev) => ({
          ...prev,
          x: inverseWidth > 20 ? inversePositionX : prev.x,
          y: inverseHeight > 20 ? inversePositionY : prev.y,
          // x: inverseWidth > 20 ? rotatedX : prev.x,
          // y: inverseHeight > 20 ? rotatedY : prev.y,
          width: inverseWidth > 20 ? inverseWidth : prev.width,
          height: inverseHeight > 20 ? inverseHeight : prev.height,
        }));
      } else if (elementData.mode === "nePoint") {
        setElementData((prev) => ({
          ...prev,
          x: newWidth > 20 ? positionX : prev.x,
          y: inverseHeight > 20 ? inversePositionY : prev.y,
          width: newWidth > 20 ? newWidth : prev.x,
          height: inverseHeight > 20 ? inverseHeight : prev.height,
        }));
      } else if (elementData.mode === "sePoint") {
        setElementData((prev) => ({
          ...prev,
          x: newWidth > 20 ? positionX : prev.x,
          y: newHeight > 20 ? positionY : prev.y,
          width: newWidth > 20 ? newWidth : prev.x,
          height: newHeight > 20 ? newHeight : prev.height,
        }));
      } else if (elementData.mode === "swPoint") {
        setElementData((prev) => ({
          ...prev,
          x: inverseWidth > 20 ? inversePositionX : prev.x,
          y: newHeight > 20 ? positionY : prev.y,
          width: inverseWidth > 20 ? inverseWidth : prev.width,
          height: newHeight > 20 ? newHeight : prev.height,
        }));
      } else {
        setElementData((prev) => ({
          ...prev,
          x: (pointPos.startX + newDelta.left) / elementData.scale,
          y: (pointPos.startY + 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 handlePointDown = useCallback(
    (e: MouseEvent) => startMove(e, "element"),
    [startMove]
  );
  const handleNWDown = useCallback(
    (e: MouseEvent) => startMove(e, "nwPoint"),
    [startMove]
  );
  const handleNEDown = useCallback(
    (e: MouseEvent) => startMove(e, "nePoint"),
    [startMove]
  );
  const handleSEDown = useCallback(
    (e: MouseEvent) => startMove(e, "sePoint"),
    [startMove]
  );
  const handleSWDown = useCallback(
    (e: MouseEvent) => startMove(e, "swPoint"),
    [startMove]
  );

  const shortScope = ["x", "X", "Backspace", "Delete"];

  useEffect(() => {
    const point = pointRef.current;
    const nwPoint = nwRef.current;
    const nePoint = neRef.current;
    const sePoint = seRef.current;
    const swPoint = swRef.current;
    const handleKeyDown = (e: KeyboardEvent) => {
      if (active && !inputFocused) {
        if (shortScope.includes(e.key)) {
          handleShortcut("delete", element.id, "mapElement");
        }
      }
    };

    if (point) {
      point.addEventListener("mousedown", handlePointDown);
    }
    if (nwPoint) {
      nwPoint.addEventListener("mousedown", handleNWDown);
    }
    if (nePoint) {
      nePoint.addEventListener("mousedown", handleNEDown);
    }
    if (sePoint) {
      sePoint.addEventListener("mousedown", handleSEDown);
    }
    if (swPoint) {
      swPoint.addEventListener("mousedown", handleSWDown);
    }
    window.addEventListener("mousemove", move, { passive: true });
    window.addEventListener("mouseup", endMove);
    window.addEventListener("mouseleave", endMove);
    document.addEventListener("keydown", handleKeyDown);
    return () => {
      if (point) {
        point.removeEventListener("mousedown", handlePointDown);
      }
      if (nwPoint) {
        nwPoint.removeEventListener("mousedown", handleNWDown);
      }
      if (nePoint) {
        nePoint.removeEventListener("mousedown", handleNEDown);
      }
      if (sePoint) {
        sePoint.removeEventListener("mousedown", handleSEDown);
      }
      if (swPoint) {
        swPoint.removeEventListener("mousedown", handleSWDown);
      }
      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={element.type === "edge"}
      style={{
        left:
          getCordinates(
            elementData.x * elementData.scale,
            elementData.width * elementData.scale,
            ADDITIONAL_TYPES.cloud as TAdditionalType
          ) + "px",
        top:
          getCordinates(
            elementData.y * elementData.scale,
            elementData.height * elementData.scale,
            ADDITIONAL_TYPES.cloud as TAdditionalType
          ) + "px",
        height: `${elementData.height * elementData.scale}px`,
        width: `${elementData.width * elementData.scale}px`,
        transform: `rotate(${calculateMapElementArc(elementData)}deg)`,
      }}
    >
      <>
        <Cloud isActive={active || focused} factor={scale} ref={pointRef} />
        {active && (
          <>
            <ElementControl
              ref={nwRef}
              style={{
                left: "-6px",
                top: "-6px",
              }}
            />
            <ElementControl
              ref={neRef}
              style={{
                right: "-6px",
                top: "-6px",
              }}
            />
            <ElementControl
              ref={seRef}
              style={{
                right: "-6px",
                bottom: "-6px",
              }}
            />
            <ElementControl
              ref={swRef}
              style={{
                left: "-6px",
                bottom: "-6px",
              }}
            />
          </>
        )}
      </>
    </AdditionalElementsWrapper>
  );
};
