import { useCallback, DragEventHandler, RefObject, useState, useEffect, useRef } from 'react';
import { collectDroppedFiles } from '../utils/fileEntries';

export const useFileDropHandler = (onDrop: (file: File[]) => void): DragEventHandler =>
  useCallback(
    (evt) => {
      // `collectDroppedFiles` synchronously captures the entry list from the
      // DataTransfer before traversing folders asynchronously.
      collectDroppedFiles(evt.dataTransfer)
        .then((files) => {
          if (files) onDrop(files);
        })
        .catch(() => undefined);
    },
    [onDrop],
  );

export const useFileDropZone = (
  zoneRef: RefObject<HTMLElement>,
  onDrop: (file: File[]) => void,
): boolean => {
  const dragCounterRef = useRef(0);
  const [active, setActive] = useState(false);

  useEffect(() => {
    const target = zoneRef.current;
    const handleDrop = (evt: DragEvent) => {
      evt.preventDefault();
      dragCounterRef.current = 0;
      setActive(false);
      if (!evt.dataTransfer) return;
      // Capture entries synchronously (inside the event) then traverse any
      // dropped folders asynchronously — the DataTransferItemList is emptied
      // once this handler returns.
      collectDroppedFiles(evt.dataTransfer)
        .then((files) => {
          if (files) onDrop(files);
        })
        .catch(() => undefined);
    };

    target?.addEventListener('drop', handleDrop);
    return () => {
      target?.removeEventListener('drop', handleDrop);
    };
  }, [zoneRef, onDrop]);

  useEffect(() => {
    const target = zoneRef.current;
    const handleDragEnter = (evt: DragEvent) => {
      if (evt.dataTransfer?.types.includes('Files')) {
        dragCounterRef.current += 1;
        setActive(true);
      }
    };
    const handleDragLeave = (evt: DragEvent) => {
      if (evt.relatedTarget === null) {
        // Mouse left the browser window — reset unconditionally
        dragCounterRef.current = 0;
        setActive(false);
        return;
      }
      dragCounterRef.current -= 1;
      if (dragCounterRef.current <= 0) {
        dragCounterRef.current = 0;
        setActive(false);
      }
    };
    const handleDragOver = (evt: DragEvent) => {
      evt.preventDefault();
    };

    target?.addEventListener('dragenter', handleDragEnter);
    target?.addEventListener('dragleave', handleDragLeave);
    target?.addEventListener('dragover', handleDragOver);
    return () => {
      target?.removeEventListener('dragenter', handleDragEnter);
      target?.removeEventListener('dragleave', handleDragLeave);
      target?.removeEventListener('dragover', handleDragOver);
    };
  }, [zoneRef]);

  return active;
};
