/**
 * useCanvasElementDrag Hook
 *
 * Handles dragging of canvas elements with percentage-based positioning.
 * Used in constructor.tsx for repositioning UI elements on the canvas.
 */

import { useRef, useEffect, useCallback, RefObject } from 'react';

interface ElementDragState {
  id: string;
  pointerOffsetX: number;
  pointerOffsetY: number;
}

interface UseCanvasElementDragOptions {
  /** Ref to the canvas container element */
  canvasRef: RefObject<HTMLElement | null>;
  /** Callback when an element's position changes */
  onPositionChange: (
    elementId: string,
    xPercent: number,
    yPercent: number,
  ) => void;
  /** Whether dragging is enabled (e.g., only in edit mode) */
  enabled?: boolean;
}

interface UseCanvasElementDragResult {
  /** Handler to attach to element's onMouseDown */
  onElementDragStart: (
    event: React.MouseEvent,
    elementId: string,
    currentXPercent: number,
    currentYPercent: number,
  ) => void;
  /** Whether currently dragging an element */
  isDragging: boolean;
  /** ID of the currently dragged element (or null) */
  draggedElementId: string | null;
  /** Cancel any active drag */
  cancelDrag: () => void;
}

/**
 * Clamp a value between min and max
 */
const clamp = (value: number, min: number, max: number): number =>
  Math.min(Math.max(value, min), max);

/**
 * Hook for dragging canvas elements with percentage-based positioning.
 * Converts pixel coordinates to percentages relative to canvas bounds.
 *
 * @example
 * const { onElementDragStart, isDragging } = useCanvasElementDrag({
 *   canvasRef,
 *   onPositionChange: (id, x, y) => {
 *     setElements(prev => prev.map(el =>
 *       el.id === id ? { ...el, xPercent: x, yPercent: y } : el
 *     ));
 *   },
 *   enabled: isEditMode,
 * });
 *
 * return (
 *   <button
 *     onMouseDown={(e) => onElementDragStart(e, element.id, element.xPercent, element.yPercent)}
 *   >
 *     {element.label}
 *   </button>
 * );
 */
export function useCanvasElementDrag({
  canvasRef,
  onPositionChange,
  enabled = true,
}: UseCanvasElementDragOptions): UseCanvasElementDragResult {
  const dragRef = useRef<ElementDragState | null>(null);

  // Handle pointer move
  useEffect(() => {
    if (!enabled) {
      dragRef.current = null;
      return;
    }

    const onPointerMove = (event: MouseEvent) => {
      if (!dragRef.current || !canvasRef.current) return;

      const rect = canvasRef.current.getBoundingClientRect();
      const rawX = event.clientX - rect.left - dragRef.current.pointerOffsetX;
      const rawY = event.clientY - rect.top - dragRef.current.pointerOffsetY;

      const nextXPercent = clamp((rawX / rect.width) * 100, 0, 100);
      const nextYPercent = clamp((rawY / rect.height) * 100, 0, 100);

      onPositionChange(dragRef.current.id, nextXPercent, nextYPercent);
    };

    const onPointerUp = () => {
      dragRef.current = null;
    };

    window.addEventListener('mousemove', onPointerMove);
    window.addEventListener('mouseup', onPointerUp);

    return () => {
      window.removeEventListener('mousemove', onPointerMove);
      window.removeEventListener('mouseup', onPointerUp);
    };
  }, [enabled, canvasRef, onPositionChange]);

  const onElementDragStart = useCallback(
    (
      event: React.MouseEvent,
      elementId: string,
      currentXPercent: number,
      currentYPercent: number,
    ) => {
      if (!enabled) return;
      event.preventDefault();
      if (!canvasRef.current) return;

      const rect = canvasRef.current.getBoundingClientRect();
      const elementLeftPx = (currentXPercent / 100) * rect.width;
      const elementTopPx = (currentYPercent / 100) * rect.height;

      dragRef.current = {
        id: elementId,
        pointerOffsetX: event.clientX - rect.left - elementLeftPx,
        pointerOffsetY: event.clientY - rect.top - elementTopPx,
      };
    },
    [enabled, canvasRef],
  );

  const cancelDrag = useCallback(() => {
    dragRef.current = null;
  }, []);

  return {
    onElementDragStart,
    isDragging: dragRef.current !== null,
    draggedElementId: dragRef.current?.id || null,
    cancelDrag,
  };
}

export default useCanvasElementDrag;
