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

const EXIT_MS = 380;
const SETTLE_MS = 280;

export default function useBidirectionalNotificationSwipe({
  threshold = 92,
  onExitComplete,
  rightAction = 'remind',
  leftAction = 'dismiss',
} = {}) {
  const pointerId = useRef(null);
  const start = useRef({ x: 0, y: 0 });
  const translateRef = useRef(0);
  const pendingAction = useRef(null);
  const onExitCompleteRef = useRef(onExitComplete);
  const suppressClick = useRef(false);
  const settleTimer = useRef(null);
  const exitTimer = useRef(null);

  const [phase, setPhase] = useState('idle');
  const [translateX, setTranslateX] = useState(0);

  useEffect(() => {
    onExitCompleteRef.current = onExitComplete;
  }, [onExitComplete]);

  const moveTo = (value) => {
    translateRef.current = value;
    setTranslateX(value);
  };

  const clearTimers = () => {
    window.clearTimeout(settleTimer.current);
    window.clearTimeout(exitTimer.current);
  };

  const reset = () => {
    clearTimers();
    pointerId.current = null;
    pendingAction.current = null;
    moveTo(0);
    setPhase('idle');
  };

  const settleBack = () => {
    setPhase('settling');
    moveTo(0);
    settleTimer.current = window.setTimeout(() => {
      setPhase('idle');
      suppressClick.current = false;
    }, SETTLE_MS);
  };

  const getDragValue = (dx) => {
    const viewport = window.innerWidth || 420;
    const softLimit = Math.max(220, viewport * 0.72);

    if (Math.abs(dx) <= softLimit) return dx;

    const overflow = Math.abs(dx) - softLimit;
    const resisted = softLimit + overflow * 0.28;
    return Math.sign(dx) * resisted;
  };

  const finishExit = (event) => {
    const action = pendingAction.current;
    if (!action) return null;

    if (event?.propertyName && event.propertyName !== 'transform') return null;

    clearTimers();
    pendingAction.current = null;
    moveTo(0);
    setPhase('idle');
    suppressClick.current = false;
    onExitCompleteRef.current?.(action);
    return action;
  };

  const onPointerDown = (event) => {
    if (event.pointerType === 'mouse' && event.button !== 0) return;
    if (phase === 'exiting-left' || phase === 'exiting-right') return;

    clearTimers();
    pointerId.current = event.pointerId;
    start.current = { x: event.clientX, y: event.clientY };
    pendingAction.current = null;
    suppressClick.current = false;
    setPhase('idle');
  };

  const onPointerMove = (event) => {
    if (pointerId.current !== event.pointerId) return;

    const dx = event.clientX - start.current.x;
    const dy = event.clientY - start.current.y;

    if (phase !== 'dragging') {
      if (Math.abs(dx) < 10) return;
      if (Math.abs(dx) < Math.abs(dy) * 1.15) return;
      event.currentTarget.setPointerCapture?.(event.pointerId);
      setPhase('dragging');
    }

    event.preventDefault();
    suppressClick.current = true;
    moveTo(getDragValue(dx));
  };

  const onPointerUp = (event) => {
    if (pointerId.current !== event.pointerId) return null;

    event.currentTarget.releasePointerCapture?.(event.pointerId);
    pointerId.current = null;

    const current = translateRef.current;
    if (Math.abs(current) < threshold) {
      settleBack();
      return null;
    }

    const rect = event.currentTarget.getBoundingClientRect();
    const viewport = window.innerWidth || 420;
    const distance = viewport + rect.width + 48;
    const action = current > 0 ? rightAction : leftAction;

    pendingAction.current = action;
    setPhase(current > 0 ? 'exiting-right' : 'exiting-left');
    moveTo(current > 0 ? distance : -distance);

    exitTimer.current = window.setTimeout(() => {
      const fallbackAction = pendingAction.current;
      if (!fallbackAction) return;
      pendingAction.current = null;
      moveTo(0);
      setPhase('idle');
      suppressClick.current = false;
      onExitCompleteRef.current?.(fallbackAction);
    }, EXIT_MS + 90);

    return null;
  };

  const onPointerCancel = () => {
    if (phase === 'dragging') settleBack();
    else reset();
  };

  const direction = translateX > 0 ? rightAction : translateX < 0 ? leftAction : null;
  const exiting = phase === 'exiting-left' || phase === 'exiting-right';

  return {
    translateX,
    phase,
    dragging: phase === 'dragging',
    exiting,
    direction,
    progress: Math.min(1, Math.abs(translateX) / threshold),
    swipeHandlers: {
      onPointerDown,
      onPointerMove,
      onPointerUp,
      onPointerCancel,
      onTransitionEnd: finishExit,
      onClickCapture: (event) => {
        if (!suppressClick.current) return;
        event.preventDefault();
        event.stopPropagation();
        suppressClick.current = false;
      },
    },
  };
}
