import { useCallback, useRef, type TouchEvent } from "react";

interface LongPressHandlers {
  onTouchStart: (e: TouchEvent) => void;
  onTouchMove: (e: TouchEvent) => void;
  onTouchEnd: (e: TouchEvent) => void;
  onTouchCancel: (e: TouchEvent) => void;
}

interface Options {
  ms?: number;
  // Suppress the synthetic click that follows touchend when long-press fired.
  suppressClickOnFire?: boolean;
}

// Hand-rolled long-press detector. Starts a timer on touchstart; cancels on
// touchmove or early touchend; fires the callback on timer expiry. Caller is
// expected to suppress text-selection callout via CSS (-webkit-touch-callout).
export function useLongPress(
  callback: (touch: { clientX: number; clientY: number; target: EventTarget | null }) => void,
  { ms = 500, suppressClickOnFire = true }: Options = {},
): LongPressHandlers {
  const timerRef = useRef<number | null>(null);
  const firedRef = useRef(false);

  const clear = useCallback(() => {
    if (timerRef.current !== null) {
      window.clearTimeout(timerRef.current);
      timerRef.current = null;
    }
  }, []);

  const onTouchStart = useCallback(
    (e: TouchEvent) => {
      firedRef.current = false;
      const touch = e.touches[0];
      if (!touch) return;
      const x = touch.clientX;
      const y = touch.clientY;
      const target = e.target;
      clear();
      timerRef.current = window.setTimeout(() => {
        firedRef.current = true;
        callback({ clientX: x, clientY: y, target });
      }, ms);
    },
    [callback, ms, clear],
  );

  const onTouchMove = useCallback(() => {
    clear();
  }, [clear]);

  const onTouchEnd = useCallback(
    (e: TouchEvent) => {
      clear();
      if (firedRef.current && suppressClickOnFire) {
        // Block the synthetic click that follows touchend; the long-press
        // already handled the gesture.
        e.preventDefault();
      }
    },
    [clear, suppressClickOnFire],
  );

  const onTouchCancel = useCallback(
    (_e: TouchEvent) => {
      clear();
    },
    [clear],
  );

  return { onTouchStart, onTouchMove, onTouchEnd, onTouchCancel };
}
