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

/**
 * Custom hook for iOS-style wheel picker scroll behavior
 *
 * Uses CSS scroll-snap for native snapping behavior and
 * detects scroll end to trigger onChange callback.
 */
function useWheelPicker({ options, value, onChange, itemHeight = 40, visibleItems = 5, }) {
    const containerRef = useRef(null);
    const scrollTimeoutRef = useRef(null);
    const isScrollingRef = useRef(false);
    const lastScrollTopRef = useRef(0);
    // Mouse drag state
    const [isDragging, setIsDragging] = useState(false);
    const isDraggingRef = useRef(false);
    const dragStartYRef = useRef(0);
    const dragStartScrollTopRef = useRef(0);
    // Calculate padding to center first/last items
    const paddingY = Math.floor((visibleItems - 1) / 2) * itemHeight;
    // Find current index based on value
    const currentIndex = options.findIndex(opt => opt === value);
    // Scroll to a specific value
    const scrollToValue = useCallback((targetValue, behavior = 'smooth') => {
        if (!containerRef.current)
            return;
        const targetIndex = options.findIndex(opt => opt === targetValue);
        if (targetIndex === -1)
            return;
        const scrollTop = targetIndex * itemHeight;
        containerRef.current.scrollTo({
            top: scrollTop,
            behavior,
        });
    }, [options, itemHeight]);
    // Handle scroll end detection with debounce
    const handleScrollEnd = useCallback(() => {
        if (!containerRef.current)
            return;
        const scrollTop = containerRef.current.scrollTop;
        const nearestIndex = Math.round(scrollTop / itemHeight);
        const clampedIndex = Math.max(0, Math.min(nearestIndex, options.length - 1));
        // Only trigger onChange if the index actually changed
        if (options[clampedIndex] !== value) {
            onChange(options[clampedIndex]);
        }
        isScrollingRef.current = false;
    }, [itemHeight, options, value, onChange]);
    // Handle scroll event with debounced end detection
    const handleScroll = useCallback(() => {
        if (!containerRef.current)
            return;
        isScrollingRef.current = true;
        lastScrollTopRef.current = containerRef.current.scrollTop;
        // Clear existing timeout
        if (scrollTimeoutRef.current) {
            clearTimeout(scrollTimeoutRef.current);
        }
        // Set new timeout for scroll end detection
        // 100ms debounce to detect when scrolling stops
        scrollTimeoutRef.current = setTimeout(() => {
            handleScrollEnd();
        }, 100);
    }, [handleScrollEnd]);
    // Attach scroll listener
    useEffect(() => {
        const container = containerRef.current;
        if (!container)
            return;
        container.addEventListener('scroll', handleScroll, { passive: true });
        return () => {
            container.removeEventListener('scroll', handleScroll);
            if (scrollTimeoutRef.current) {
                clearTimeout(scrollTimeoutRef.current);
            }
        };
    }, [handleScroll]);
    // Scroll to initial value on mount and when value changes externally
    useEffect(() => {
        if (!isScrollingRef.current && containerRef.current) {
            const targetIndex = options.findIndex(opt => opt === value);
            if (targetIndex !== -1) {
                // Use instant scroll on initial mount to avoid jarring animation
                const scrollTop = targetIndex * itemHeight;
                containerRef.current.scrollTo({
                    top: scrollTop,
                    behavior: 'instant',
                });
            }
        }
    }, [value, options, itemHeight]);
    // Mouse drag-to-scroll support (desktop)
    useEffect(() => {
        const container = containerRef.current;
        if (!container)
            return;
        const handleMouseDown = (e) => {
            isDraggingRef.current = false;
            dragStartYRef.current = e.clientY;
            dragStartScrollTopRef.current = container.scrollTop;
            const handleMouseMove = (e) => {
                const deltaY = dragStartYRef.current - e.clientY;
                // Only start dragging after a small threshold to allow clicks
                if (!isDraggingRef.current && Math.abs(deltaY) > 3) {
                    isDraggingRef.current = true;
                    setIsDragging(true);
                }
                if (isDraggingRef.current) {
                    container.scrollTop = dragStartScrollTopRef.current + deltaY;
                }
            };
            const handleMouseUp = () => {
                document.removeEventListener('mousemove', handleMouseMove);
                document.removeEventListener('mouseup', handleMouseUp);
                // Reset dragging state after a tick so click handlers can check it
                requestAnimationFrame(() => {
                    isDraggingRef.current = false;
                    setIsDragging(false);
                });
            };
            document.addEventListener('mousemove', handleMouseMove);
            document.addEventListener('mouseup', handleMouseUp);
        };
        container.addEventListener('mousedown', handleMouseDown);
        return () => {
            container.removeEventListener('mousedown', handleMouseDown);
        };
    }, []);
    return {
        containerRef,
        scrollToValue,
        currentIndex,
        paddingY,
        isDragging,
    };
}

export { useWheelPicker };
