import { MutableRefObject, useEffect, useRef, useState } from 'react';

export type SilkeDragState = 'none' | 'dragging';
type DragData<T> = MutableRefObject<T>;
let dragData: DragData<any>;
export function getDragData<T = any>(): DragData<T> {
  return dragData;
}

export function useDrag<T>({
  data,
  disabled,
  isolated,
  ref,
}: {
  data: T;
  disabled?: boolean;
  isolated?: boolean;
  ref: MutableRefObject<HTMLElement | undefined | null>;
}): SilkeDragState {
  const [state, setState] = useState<SilkeDragState>('none');
  const dataRef = useRef<T>(data);
  dataRef.current = data;

  useEffect(() => {
    const el = ref.current;
    if (el && !disabled) {
      const dragHandle = (el.querySelector('*[data-drag-handle]') || el) as HTMLElement;
      dragHandle.setAttribute('draggable', 'true');

      const handleDragStart = (e: DragEvent) => {
        e.stopPropagation();

        setState('dragging');
        const { dataTransfer } = e;
        if (dataTransfer) {
          dataTransfer.effectAllowed = 'move';
          dataTransfer.setDragImage(el as HTMLElement, 10, el.clientHeight / 2);
          dragData = dataRef;
          dataTransfer.setData('application/json', JSON.stringify(dragData));

          // Mark as isolated dnd so generic drop zones can ignore it
          if (isolated) dataTransfer.setData('vev/isolated-dnd', 'true');
        }
      };

      const handleDragEnd = (e: DragEvent) => {
        e.stopPropagation();
        setState('none');
      };

      dragHandle.addEventListener('dragstart', handleDragStart);
      dragHandle.addEventListener('dragend', handleDragEnd);
      return () => {
        dragHandle.removeEventListener('dragstart', handleDragStart);
        dragHandle.removeEventListener('dragend', handleDragStart);
        dragHandle.removeAttribute('draggable');
      };
    }
  }, [ref, disabled]);

  return state;
}
