import { useState, useEffect, MouseEvent, useRef, Dispatch, SetStateAction } from 'react';

type Coordinates = {
  x: number;
  y: number;
}

interface DraggableBoxProps {
  position: Coordinates;
  className?: string;
  children?: React.ReactNode;
  coordSetter: Dispatch<SetStateAction<Coordinates>>;
}

const DraggableBox = ({
  position,
  className = "",
  children = "",
  coordSetter
}: DraggableBoxProps) => {
  const [isDragging, setIsDragging] = useState(false);
  const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
  const dragRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!isDragging) return;

    const handleMouseMove = (e: globalThis.MouseEvent) => {
      if (!dragRef.current?.parentElement) return;

      const parent = dragRef.current.parentElement;
      const parentRect = parent.getBoundingClientRect();

      const relativeX = e.clientX - parentRect.left - dragOffset.x;
      const relativeY = e.clientY - parentRect.top - dragOffset.y;

      const maxX = parentRect.width;
      const maxY = parentRect.height;

      let newX = (Math.max(0, Math.min(relativeX, maxX)));
      let newY = (Math.max(0, Math.min(relativeY, maxY)));

      coordSetter({
        x: newX,
        y: newY
      })
    };

    const handleMouseUp = () => setIsDragging(false);

    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseup', handleMouseUp);

    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
      window.removeEventListener('mouseup', handleMouseUp);
    };
  }, [isDragging, dragOffset, position.x, position.y]);

  const handleMouseDown = (e: MouseEvent) => {
    if (!dragRef.current?.parentElement) return;

    const parentRect = dragRef.current.parentElement.getBoundingClientRect();

    setDragOffset({
      x: e.clientX - parentRect.left - position.x,
      y: e.clientY - parentRect.top - position.y
    });
    setIsDragging(true);
  };

  return (
    <div
      ref={dragRef}
      className={`absolute cursor-pointer ${className}`}
      style={{
        transform: `translate(${position.x}px, ${position.y}px)`,
        userSelect: 'none',
      }}
      onMouseDown={handleMouseDown}
    >
      {children}
    </div>
  );
};

export default DraggableBox;
