import {
  useCallback,
  useEffect,
  useRef,
} from 'react';
import {
  isTagTransferEvent,
  parseTagTransferPayload,
  writeTagTransferData,
} from '../../documents/tagTransfer';

const preventAll = (event) => {
  if (!event) return;
  if (typeof event.preventDefault === 'function') event.preventDefault();
  if (typeof event.stopPropagation === 'function') event.stopPropagation();
};

const createDragPreview = (node, clientX, clientY) => {
  if (!(node instanceof HTMLElement)) {
    return null;
  }
  const rect = node.getBoundingClientRect();
  const safeClientX = Number.isFinite(clientX) ? clientX : rect.left + rect.width / 2;
  const safeClientY = Number.isFinite(clientY) ? clientY : rect.top + rect.height / 2;
  const offsetX = Math.min(Math.max(safeClientX - rect.left, 0), rect.width);
  const offsetY = Math.min(Math.max(safeClientY - rect.top, 0), rect.height);
  const clone = node.cloneNode(true);
  clone.style.position = 'absolute';
  clone.style.top = '-9999px';
  clone.style.left = '-9999px';
  clone.style.pointerEvents = 'none';
  clone.style.opacity = '1';
  clone.style.transform = 'none';
  document.body.appendChild(clone);
  return { clone, offsetX, offsetY };
};

const cleanupPreview = (previewNode) => {
  if (previewNode && previewNode.parentNode) {
    previewNode.parentNode.removeChild(previewNode);
  }
};

export const useDeskTagInteractions = ({
  onAssignTagToDocument,
  onRemoveTagFromDocument,
  requestCanvasFocus,
}) => {
  const draggingTagRef = useRef(null);

  const isTagTransfer = useCallback((event) => isTagTransferEvent(event), []);

  const handleTagDragEnterDoc = useCallback(
    (event) => {
      if (!isTagTransfer(event)) return;
      preventAll(event);
      event.currentTarget.classList.add('is-tag-target');
    },
    [isTagTransfer],
  );

  const handleTagDragOverDoc = useCallback(
    (event, docId) => {
      if (!isTagTransfer(event)) return;
      preventAll(event);
      event.currentTarget.classList.add('is-tag-target');

      if (event.dataTransfer) {
        // If dragging over source, copy (no removal). Else move (removal).
        const isSource = draggingTagRef.current?.sourceDocId === docId;
        event.dataTransfer.dropEffect = isSource ? 'copy' : 'move';
      }
    },
    [isTagTransfer],
  );

  const handleTagDragLeaveDoc = useCallback(
    (event) => {
      if (!isTagTransfer(event)) return;
      // Ignore if leaving to a child element
      if (event.relatedTarget && event.currentTarget.contains(event.relatedTarget)) {
        return;
      }
      event.currentTarget.classList.remove('is-tag-target');
    },
    [isTagTransfer],
  );

  const handleCanvasDragOver = useCallback(
    (event) => {
      if (event.dataTransfer) {
        event.dataTransfer.dropEffect = 'move';
      }
    },
    [],
  );

  const handleCanvasDrop = useCallback(
    (event) => {
      // Implicit removal via dragend (dropEffect='move')
      if (event.dataTransfer) {
        event.dataTransfer.dropEffect = 'move';
      }
      preventAll(event);
    },
    [],
  );

  const handleTagDropOnDoc = useCallback(
    (event, doc) => {
      if (!doc) {
        return;
      }
      if (!isTagTransfer(event)) {
        return;
      }
      preventAll(event);
      event.currentTarget.classList.remove('is-tag-target');

      // Add to target
      const payload = parseTagTransferPayload(event);

      setTimeout(() => {
        if (!payload || !payload.id) {
          return;
        }

        if (payload.sourceDocId === doc.id) {
          return;
        }

        requestCanvasFocus?.();

        if (onAssignTagToDocument) {
          onAssignTagToDocument(doc.id, payload.id);
        }
      }, 0);
    },
    [isTagTransfer, onAssignTagToDocument, requestCanvasFocus],
  );

  const handleDocTagDragStart = useCallback(
    (event, doc, tag) => {
      console.log('[Tag] handleDocTagDragStart', { docId: doc?.id, tagId: tag?.id });
      if (!event?.dataTransfer || !doc || !tag) {
        return;
      }
      event.dataTransfer.effectAllowed = 'copyMove';
      writeTagTransferData(event.dataTransfer, tag, doc.id);

      const pointerX = event.clientX;
      const pointerY = event.clientY;
      const { clone, offsetX, offsetY } = createDragPreview(event.currentTarget, pointerX, pointerY) || {};
      if (clone) {
        event.dataTransfer.setDragImage(clone, offsetX || 0, offsetY || 0);
      }

      const element = event.currentTarget instanceof HTMLElement ? event.currentTarget : null;
      if (element) {
        element.classList.add('is-drag-hidden');
      }

      draggingTagRef.current = {
        element,
        previewClone: clone,
        sourceDocId: doc.id,
        tagId: tag.id,
        initialX: pointerX,
        initialY: pointerY,
        distance: 0,
      };
    },
    [],
  );

  const handleDocTagDragEnd = useCallback(
    (event) => {
      console.log('[Tag] handleDocTagDragEnd', { dropEffect: event?.dataTransfer?.dropEffect });
      const dropEffect = event?.dataTransfer?.dropEffect;

      setTimeout(() => {
        const state = draggingTagRef.current;
        if (state) {
          const element = state.element;
          if (element) {
            element.classList.remove('is-drag-hidden');
          }
          cleanupPreview(state.previewClone);

          // Remove if move operation completed
          if (dropEffect === 'move') {
            if (onRemoveTagFromDocument && state.sourceDocId && state.tagId) {
              onRemoveTagFromDocument(state.sourceDocId, state.tagId);
            }
          }
        }
        draggingTagRef.current = null;
      }, 0);
    },
    [onRemoveTagFromDocument],
  );

  useEffect(() => {
    return () => {
      if (draggingTagRef.current && draggingTagRef.current.previewClone) {
        cleanupPreview(draggingTagRef.current.previewClone);
      }
      draggingTagRef.current = null;
    };
  }, []);

  return {
    handleTagDragEnterDoc,
    handleTagDragOverDoc,
    handleTagDragLeaveDoc,
    handleTagDropOnDoc,
    handleDocTagDragStart,
    handleDocTagDragEnd,
    handleCanvasDragOver,
    handleCanvasDrop,
  };
};

export default useDeskTagInteractions;
