"use client"
import type { Children, Classname } from "@/core/types/common";
import {
  useRef,
  MouseEvent as ReactMouseEvent,
  useState,
  Fragment,
  useEffect,
  type JSX,
} from "react";

type Size = { width: number; height: number };
interface DraggableProps extends Children, Classname {
  start?: () => void;
  end?: () => void;
  dataTransfer: string;
  disabled?: boolean;
}

export default function Draggable(props: Readonly<DraggableProps>): JSX.Element {
  const element = useRef<HTMLDivElement>(null);
  const float = useRef<HTMLDivElement>(null);

  const [dragMoving, setDragMoving] = useState<boolean>(false);
  const [size, setSize] = useState<Size | null>(null);

  const onMoving = (event: MouseEvent) => {
    if (element.current && float.current) {
      setDragMoving(true);
      const x = event.clientX;
      const y = event.clientY;
      float.current.style.top = y - (element.current.offsetHeight) + "px";
      float.current.style.left = x - element.current.offsetWidth + "px";
    }
  }
  const onMovingEnd = (event: MouseEvent) => {
    event.preventDefault();
    document.removeEventListener("mousemove", onMoving);
    setDragMoving(false);
    if (element.current && float.current) {
      float.current.style.top = "auto";
      float.current.style.left = "auto";
      document.addEventListener("mouseup", onMovingEnd);
      if (props.end) props.end();
    }
  }
  const onMouseDown = (event: ReactMouseEvent) => {
    event.preventDefault();
    if (props.disabled) return;
    if (props.start) props.start();
    if (element.current && float.current) {
      document.addEventListener("mousemove", onMoving);
      document.addEventListener("mouseup", onMovingEnd);
    }
  }

  useEffect(() => {
    if (element.current) {
      setSize({ width: element.current.offsetWidth + 20, height: element.current.offsetHeight + 20 })
    }
    return () => {
      document.removeEventListener("mousemove", onMoving);
      document.removeEventListener("mouseup", onMovingEnd);
    }
    // eslint-disable-next-line
  }, []);

  return (
    <Fragment>
      <div
        ref={element}
        className={`${props.className} transition-opacity ${dragMoving ? "opacity-50" : ""}`}
        onMouseDown={onMouseDown}
      >
        {props.children}
      </div>
      <div
        ref={float}
        style={{ width: size?.width, height: size?.height }}
        className={`
          hidden ${dragMoving ? "!block shadow-card border border-grey-300 border-opacity-50" : ""} bg-opacity-90
          transition-colors bg-white p-2 flex items-center justify-center fixed top-0 left-0 z-[999] rounded-[4px]
        `}
      >
        {props.children}
      </div>
    </Fragment>
  );
}