/**
 * Multi-tap Gesture Hook
 *
 * Cross-input multi-tap detection (works with touch, pencil, and mouse).
 * Replaces the mouse-only onDoubleClick/onTripleClick handlers.
 *
 * Usage:
 *   const handleTap = useTapGesture({
 *     onSingleTap: () => selectNode(id),
 *     onDoubleTap: () => lockNode(id),
 *     onTripleTap: () => expandNode(id),
 *   });
 *
 *   // In your gesture handler:
 *   onPointerUp = (e) => handleTap(e);
 */

import { useRef } from 'react';

export interface UseTapGestureOptions {
    /** Called on single tap (after delay to disambiguate from double-tap) */
    onSingleTap?: (event: PointerEvent) => void;
    /** Called on double tap */
    onDoubleTap?: (event: PointerEvent) => void;
    /** Called on triple tap */
    onTripleTap?: (event: PointerEvent) => void;
    /** Max time between taps to count as multi-tap (ms). Default: 300 */
    tapDelay?: number;
    /** Max distance between taps to count as multi-tap (px). Default: 25 */
    tapDistance?: number;
}

interface TapState {
    count: number;
    timer: ReturnType<typeof setTimeout> | null;
    lastX: number;
    lastY: number;
    lastEvent: PointerEvent | null;
}

/**
 * Hook for detecting single, double, and triple taps across all input types.
 *
 * Returns a function to call from onPointerUp (or tap handler).
 * Uses a timer to disambiguate between single and multi-taps.
 */
export function useTapGesture(options: UseTapGestureOptions = {}) {
    const {
        onSingleTap,
        onDoubleTap,
        onTripleTap,
        tapDelay = 300,
        tapDistance = 25,
    } = options;

    const stateRef = useRef<TapState>({
        count: 0,
        timer: null,
        lastX: 0,
        lastY: 0,
        lastEvent: null,
    });

    const handleTap = (event: PointerEvent) => {
        const state = stateRef.current;

        // Check if this tap is close enough to the previous one
        const dx = Math.abs(event.clientX - state.lastX);
        const dy = Math.abs(event.clientY - state.lastY);
        const isSameSpot = state.count === 0 || (dx < tapDistance && dy < tapDistance);

        if (!isSameSpot) {
            // Too far from previous tap — reset and treat as new single tap
            if (state.timer) clearTimeout(state.timer);
            state.count = 0;
        }

        state.count++;
        state.lastX = event.clientX;
        state.lastY = event.clientY;
        state.lastEvent = event;

        // Clear any existing timer
        if (state.timer) clearTimeout(state.timer);

        // Triple tap: fire immediately (no need to wait)
        if (state.count >= 3) {
            onTripleTap?.(event);
            state.count = 0;
            state.timer = null;
            return;
        }

        // Double tap: fire immediately, but set a short timer
        // to reset count in case of triple tap
        if (state.count === 2) {
            onDoubleTap?.(event);
            // Keep listening briefly for triple tap
            state.timer = setTimeout(() => {
                state.count = 0;
                state.timer = null;
            }, tapDelay);
            return;
        }

        // Single tap: wait for potential double tap
        state.timer = setTimeout(() => {
            if (state.count === 1 && state.lastEvent) {
                onSingleTap?.(state.lastEvent);
            }
            state.count = 0;
            state.timer = null;
        }, tapDelay);
    };

    // Cleanup function for unmount
    const cleanup = () => {
        const state = stateRef.current;
        if (state.timer) {
            clearTimeout(state.timer);
            state.timer = null;
        }
        state.count = 0;
    };

    return { handleTap, cleanup };
}
