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

/**
 * Fixed dropdown positioning hook
 * Uses position: fixed with pure viewport coordinates to properly follow scroll
 * Fixes critical issues: dropdown not following scroll & multiple dropdowns not working
 */
const useSimpleDropdown = ({ triggerRef, isOpen, placement = "bottom-start", offset = 4, estimatedWidth, autoWidth = false, onClose, stickyTracking = false, }) => {
    const contentRef = useRef(null);
    const [position, setPosition] = useState({ top: -9999, left: -9999, width: 0 });
    const [cssVariables, setCssVariables] = useState({});
    const [actualPlacement, setActualPlacement] = useState(placement);
    const [isFlipped, setIsFlipped] = useState(false);
    const [isReady, setIsReady] = useState(false);
    const isInitialRenderRef = useRef(true);
    const rafIdRef = useRef(null);
    const frozenPlacementRef = useRef(placement);
    // Enhanced measurement system - use actual DOM measurements when available
    const measureDropdownHeight = useCallback(() => {
        if (contentRef.current) {
            const rect = contentRef.current.getBoundingClientRect();
            return rect.height || estimateDropdownHeight();
        }
        return estimateDropdownHeight();
    }, []);
    // Calculate estimated height based on content structure (fallback)
    const estimateDropdownHeight = () => {
        const baseHeight = 16; // Container padding/border
        const itemHeight = 44; // Approximate height per option (padding + text)
        const maxVisibleItems = 8; // Max items before scrolling kicks in
        // Default to reasonable number if we can\'t determine actual count
        const estimatedItems = Math.min(8, maxVisibleItems);
        return baseHeight + (estimatedItems * itemHeight);
    };
    // Measure actual dropdown width from DOM
    const measureDropdownWidth = useCallback(() => {
        var _a;
        // If autoWidth is true, ONLY measure from content.
        if (autoWidth) {
            if (contentRef.current) {
                return contentRef.current.getBoundingClientRect().width;
            }
            return 0; // Return 0 initially, the rAF pass will correct it.
        }
        // If estimatedWidth is provided, ALWAYS use it (prevents width flickering during animations)
        // This ensures dropdown width stays constant and matches trigger width
        if (estimatedWidth) {
            return estimatedWidth;
        }
        // Only measure content width if estimatedWidth was NOT provided
        if (contentRef.current) {
            const rect = contentRef.current.getBoundingClientRect();
            return rect.width;
        }
        // Final fallback to trigger width
        return ((_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().width) || 0;
    }, [contentRef, triggerRef, estimatedWidth, autoWidth]);
    // Calculate position using viewport coordinates (for position: fixed)
    const calculatePosition = useCallback(() => {
        if (typeof window === "undefined")
            return;
        if (!triggerRef.current)
            return;
        const rect = triggerRef.current.getBoundingClientRect();
        const viewportWidth = window.innerWidth;
        const viewportHeight = window.innerHeight;
        const margin = 16;
        const dropdownHeight = measureDropdownHeight();
        const dropdownWidth = measureDropdownWidth();
        const spaceAbove = rect.top - margin;
        const spaceBelow = viewportHeight - rect.bottom - margin;
        const spaceLeft = rect.left - margin;
        const spaceRight = viewportWidth - rect.right - margin;
        // Improved edge detection logic using actual measurements
        const shouldFlip = (preferredPlacement) => {
            if (preferredPlacement.startsWith("bottom")) {
                // Only flip if space below is insufficient AND space above is sufficient
                return spaceBelow < dropdownHeight && spaceAbove >= dropdownHeight;
            }
            else if (preferredPlacement.startsWith("top")) {
                // Only flip if space above is insufficient AND space below is sufficient
                return spaceAbove < dropdownHeight && spaceBelow >= dropdownHeight;
            }
            else if (preferredPlacement.startsWith("right")) {
                // Only flip if space right is insufficient AND space left is sufficient
                return spaceRight < dropdownWidth && spaceLeft >= dropdownWidth;
            }
            else if (preferredPlacement.startsWith("left")) {
                // Only flip if space left is insufficient AND space right is sufficient
                return spaceLeft < dropdownWidth && spaceRight >= dropdownWidth;
            }
            return false;
        };
        // Determine optimal placement direction
        let finalPlacement = placement;
        const needsFlip = shouldFlip(placement);
        if (needsFlip) {
            // Preserve alignment when flipping
            if (placement === "bottom-start")
                finalPlacement = "top-start";
            else if (placement === "bottom-end")
                finalPlacement = "top-end";
            else if (placement === "bottom")
                finalPlacement = "top";
            else if (placement === "top-start")
                finalPlacement = "bottom-start";
            else if (placement === "top-end")
                finalPlacement = "bottom-end";
            else if (placement === "top")
                finalPlacement = "bottom";
            else if (placement === "right-start")
                finalPlacement = "left-start";
            else if (placement === "right-end")
                finalPlacement = "left-end";
            else if (placement === "right")
                finalPlacement = "left";
            else if (placement === "left-start")
                finalPlacement = "right-start";
            else if (placement === "left-end")
                finalPlacement = "right-end";
            else if (placement === "left")
                finalPlacement = "right";
        }
        setActualPlacement(finalPlacement);
        setIsFlipped(needsFlip);
        frozenPlacementRef.current = finalPlacement;
        // Calculate position based on final placement
        let top = 0;
        let left = 0;
        // Handle positioning based on placement direction
        if (finalPlacement.startsWith("top") || finalPlacement.startsWith("bottom")) {
            // TOP/BOTTOM PLACEMENTS: Handle horizontal alignment
            if (finalPlacement.includes("start")) {
                left = rect.left;
            }
            else if (finalPlacement.includes("end")) {
                left = rect.right - dropdownWidth;
            }
            else {
                // Center alignment
                left = rect.left + (rect.width / 2) - (dropdownWidth / 2);
            }
            // Handle vertical positioning
            if (finalPlacement.startsWith("top")) {
                top = rect.top - dropdownHeight - offset;
            }
            else {
                top = rect.bottom + offset;
            }
        }
        else if (finalPlacement.startsWith("left") || finalPlacement.startsWith("right")) {
            // LEFT/RIGHT PLACEMENTS: Handle vertical alignment
            if (finalPlacement.includes("start")) {
                top = rect.top;
            }
            else if (finalPlacement.includes("end")) {
                top = rect.bottom - dropdownHeight;
            }
            else {
                // Center alignment
                top = rect.top + (rect.height / 2) - (dropdownHeight / 2);
            }
            // Handle horizontal positioning
            if (finalPlacement.startsWith("left")) {
                left = rect.left - dropdownWidth - offset;
            }
            else {
                left = rect.right + offset;
            }
        }
        // Collision detection - handle both horizontal and vertical overflow
        // Skip clamping for stickyTracking so the dropdown follows the trigger past viewport edges
        if (!stickyTracking) {
            // Horizontal bounds checking
            const rightEdge = left + dropdownWidth;
            const overflow = rightEdge - (viewportWidth - margin);
            if (overflow > 0) {
                // Shift left just enough to fit
                const shiftedLeft = left - overflow;
                if (shiftedLeft >= margin) {
                    left = shiftedLeft;
                }
                else {
                    // Clamp to viewport margin
                    left = margin;
                }
            }
            // Handle left edge overflow
            if (left < margin) {
                left = margin;
            }
            // Vertical bounds checking
            const bottomEdge = top + dropdownHeight;
            const verticalOverflow = bottomEdge - (viewportHeight - margin);
            if (verticalOverflow > 0) {
                // Shift up just enough to fit
                const shiftedTop = top - verticalOverflow;
                if (shiftedTop >= margin) {
                    top = shiftedTop;
                }
                else {
                    // Clamp to viewport margin
                    top = margin;
                }
            }
            // Handle top edge overflow
            if (top < margin) {
                top = margin;
            }
        }
        setPosition({ top, left, width: dropdownWidth });
        // Calculate available space based on placement direction
        let availableSpace = 0;
        if (finalPlacement.startsWith("top")) {
            availableSpace = spaceAbove - offset;
        }
        else if (finalPlacement.startsWith("bottom")) {
            availableSpace = spaceBelow - offset;
        }
        else if (finalPlacement.startsWith("left")) {
            availableSpace = spaceLeft - offset;
        }
        else if (finalPlacement.startsWith("right")) {
            availableSpace = spaceRight - offset;
        }
        const resolvedAvailableSpace = Math.max(0, availableSpace);
        const cssVars = {
            "--select-content-available-width": `${rect.width}px`,
        };
        if (resolvedAvailableSpace > 0) {
            cssVars["--select-content-available-height"] = `${resolvedAvailableSpace}px`;
        }
        else {
            delete cssVars["--select-content-available-height"];
        }
        if (isInitialRenderRef.current) {
            cssVars.visibility = "hidden";
            cssVars.pointerEvents = "none";
        }
        setCssVariables(cssVars);
        // Mark initial render as complete after first calculation
    }, [measureDropdownHeight, measureDropdownWidth, offset, placement, triggerRef, stickyTracking]);
    // Direct DOM mutation for stickyTracking — bypasses React state for zero-lag scroll tracking
    const updatePositionInDOM = useCallback(() => {
        if (!triggerRef.current || !contentRef.current)
            return;
        const rect = triggerRef.current.getBoundingClientRect();
        const frozen = frozenPlacementRef.current;
        const dropdownHeight = measureDropdownHeight();
        const dropdownWidth = measureDropdownWidth();
        let top = 0;
        let left = 0;
        if (frozen.startsWith("top") || frozen.startsWith("bottom")) {
            if (frozen.includes("start")) {
                left = rect.left;
            }
            else if (frozen.includes("end")) {
                left = rect.right - dropdownWidth;
            }
            else {
                left = rect.left + (rect.width / 2) - (dropdownWidth / 2);
            }
            if (frozen.startsWith("top")) {
                top = rect.top - dropdownHeight - offset;
            }
            else {
                top = rect.bottom + offset;
            }
        }
        else if (frozen.startsWith("left") || frozen.startsWith("right")) {
            if (frozen.includes("start")) {
                top = rect.top;
            }
            else if (frozen.includes("end")) {
                top = rect.bottom - dropdownHeight;
            }
            else {
                top = rect.top + (rect.height / 2) - (dropdownHeight / 2);
            }
            if (frozen.startsWith("left")) {
                left = rect.left - dropdownWidth - offset;
            }
            else {
                left = rect.right + offset;
            }
        }
        contentRef.current.style.top = `${top}px`;
        contentRef.current.style.left = `${left}px`;
    }, [triggerRef, measureDropdownHeight, measureDropdownWidth, offset]);
    // Reset initial render flag when dropdown opens
    useLayoutEffect(() => {
        if (!isOpen) {
            if (rafIdRef.current !== null) {
                cancelAnimationFrame(rafIdRef.current);
                rafIdRef.current = null;
            }
            setIsReady(false);
            return;
        }
        isInitialRenderRef.current = true;
        setIsReady(false);
        // Perform an initial measurement (hidden) immediately
        calculatePosition();
        // Recalculate on next animation frame to allow layout to settle
        if (rafIdRef.current !== null) {
            cancelAnimationFrame(rafIdRef.current);
        }
        rafIdRef.current = window.requestAnimationFrame(() => {
            rafIdRef.current = null;
            isInitialRenderRef.current = false;
            calculatePosition();
            setIsReady(true);
        });
        return () => {
            if (rafIdRef.current !== null) {
                cancelAnimationFrame(rafIdRef.current);
                rafIdRef.current = null;
            }
        };
    }, [isOpen, calculatePosition]);
    // Initial position calculation
    useLayoutEffect(() => {
        if (!isOpen)
            return;
        calculatePosition();
    }, [isOpen, calculatePosition]);
    // rAF-synced scroll handler: skips internal scrolls, detects off-screen trigger
    const scrollRafRef = useRef(null);
    const handleScroll = useCallback((e) => {
        // Skip if scroll originated inside the popover content
        if (contentRef.current && contentRef.current.contains(e.target)) {
            return;
        }
        // Close if trigger has scrolled off-screen (skip for stickyTracking)
        if (!stickyTracking && triggerRef.current) {
            const rect = triggerRef.current.getBoundingClientRect();
            const isOffScreen = rect.bottom < 0 || rect.top > window.innerHeight
                || rect.right < 0 || rect.left > window.innerWidth;
            if (isOffScreen && onClose) {
                onClose();
                return;
            }
        }
        if (stickyTracking) {
            // Direct DOM mutation — zero-lag tracking, bypasses React state entirely
            updatePositionInDOM();
        }
        else {
            if (scrollRafRef.current)
                cancelAnimationFrame(scrollRafRef.current);
            scrollRafRef.current = requestAnimationFrame(() => {
                scrollRafRef.current = null;
                calculatePosition();
            });
        }
    }, [calculatePosition, onClose, triggerRef, stickyTracking, updatePositionInDOM]);
    const handleResize = useCallback(() => {
        if (scrollRafRef.current)
            cancelAnimationFrame(scrollRafRef.current);
        scrollRafRef.current = requestAnimationFrame(() => {
            scrollRafRef.current = null;
            calculatePosition();
        });
    }, [calculatePosition]);
    // Update position on scroll and resize - rAF-synced for smooth tracking
    useLayoutEffect(() => {
        if (!isOpen)
            return;
        window.addEventListener("scroll", handleScroll, { passive: true, capture: true });
        window.addEventListener("resize", handleResize, { passive: true });
        return () => {
            window.removeEventListener("scroll", handleScroll, true);
            window.removeEventListener("resize", handleResize);
            if (scrollRafRef.current) {
                cancelAnimationFrame(scrollRafRef.current);
                scrollRafRef.current = null;
            }
        };
    }, [isOpen, handleScroll, handleResize]);
    // Recalculate when dropdown content resizes (e.g. search filtering)
    useLayoutEffect(() => {
        if (!isOpen)
            return;
        if (!contentRef.current)
            return;
        if (typeof ResizeObserver === "undefined")
            return;
        const observer = new ResizeObserver(() => {
            if (stickyTracking) {
                updatePositionInDOM();
            }
            else {
                calculatePosition();
            }
        });
        observer.observe(contentRef.current);
        return () => {
            observer.disconnect();
        };
    }, [isOpen, calculatePosition, stickyTracking, updatePositionInDOM]);
    return {
        position,
        cssVariables,
        contentRef,
        actualPlacement,
        isFlipped,
        isReady,
    };
};
// Export with original name for backward compatibility
const useSelectPortal = useSimpleDropdown;

export { useSelectPortal, useSimpleDropdown };
