'use strict';

var jsxRuntime = require('react/jsx-runtime');
var React = require('react');

const Ctx = React.createContext(undefined);
/* ── Provider ──────────────────────────────────────────────────── */
function GamepadNavigationProvider({ children }) {
    const [focusables, setFocusables] = React.useState([]);
    const [activeId, setActiveId] = React.useState(null);
    const focusablesRef = React.useRef([]);
    const activeIdRef = React.useRef(null);
    const focusTrapStackRef = React.useRef([]);
    const gameModeLockRef = React.useRef(0);
    const enterGameMode = React.useCallback(() => { gameModeLockRef.current += 1; }, []);
    const exitGameMode = React.useCallback(() => { gameModeLockRef.current = Math.max(0, gameModeLockRef.current - 1); }, []);
    const pushFocusTrap = React.useCallback((prefix, onDismiss) => {
        focusTrapStackRef.current = [...focusTrapStackRef.current, { prefix, onDismiss }];
    }, []);
    const popFocusTrap = React.useCallback(() => {
        var _a;
        const stack = focusTrapStackRef.current;
        if (stack.length === 0)
            return;
        const top = stack[stack.length - 1];
        focusTrapStackRef.current = stack.slice(0, -1);
        (_a = top.onDismiss) === null || _a === void 0 ? void 0 : _a.call(top);
    }, []);
    React.useEffect(() => { focusablesRef.current = focusables; }, [focusables]);
    React.useEffect(() => { activeIdRef.current = activeId; }, [activeId]);
    const register = React.useCallback((meta) => {
        setFocusables(prev => {
            if (prev.some(f => f.id === meta.id))
                return prev;
            return [...prev, meta];
        });
    }, []);
    const unregister = React.useCallback((id) => {
        setFocusables(prev => {
            var _a, _b;
            const filtered = prev.filter(f => f.id !== id);
            if (activeIdRef.current === id && filtered.length > 0) {
                const fallbackId = filtered[0].id;
                setActiveId(fallbackId);
                activeIdRef.current = fallbackId;
                (_b = (_a = filtered.find(f => f.id === fallbackId)) === null || _a === void 0 ? void 0 : _a.ref.current) === null || _b === void 0 ? void 0 : _b.focus();
            }
            else if (activeIdRef.current === id) {
                setActiveId(null);
                activeIdRef.current = null;
            }
            return filtered;
        });
    }, []);
    const moveFocus = React.useCallback((dx, dy) => {
        var _a, _b;
        if (gameModeLockRef.current > 0)
            return;
        const list = focusablesRef.current;
        const currentId = activeIdRef.current;
        if (!currentId && list.length > 0) {
            setActiveId(list[0].id);
            activeIdRef.current = list[0].id;
            (_a = list[0].ref.current) === null || _a === void 0 ? void 0 : _a.focus();
            return;
        }
        if (!currentId || list.length === 0)
            return;
        const current = list.find(f => f.id === currentId);
        if (!current)
            return;
        const trapStack = focusTrapStackRef.current;
        const trapPrefix = trapStack.length > 0 ? trapStack[trapStack.length - 1].prefix : null;
        const candidates = trapPrefix
            ? list.filter(f => f.id !== currentId && f.id.startsWith(trapPrefix))
            : list.filter(f => f.id !== currentId);
        if (candidates.length === 0)
            return;
        let best = null;
        let bestScore = Infinity;
        for (const c of candidates) {
            const cdx = c.x - current.x;
            const cdy = c.y - current.y;
            const dot = dx * cdx + dy * cdy;
            if (dot <= 0)
                continue;
            const dist = Math.sqrt(cdx * cdx + cdy * cdy);
            if (dist < bestScore) {
                bestScore = dist;
                best = c;
            }
        }
        if (!best)
            return;
        setActiveId(best.id);
        activeIdRef.current = best.id;
        (_b = best.ref.current) === null || _b === void 0 ? void 0 : _b.focus();
    }, []);
    const setActiveById = React.useCallback((id) => {
        setActiveId(id);
        activeIdRef.current = id;
    }, []);
    // Keyboard navigation (Arrow keys)
    React.useEffect(() => {
        const handler = (e) => {
            if (gameModeLockRef.current > 0)
                return;
            switch (e.key) {
                case "ArrowUp":
                    moveFocus(0, -1);
                    e.preventDefault();
                    break;
                case "ArrowDown":
                    moveFocus(0, 1);
                    e.preventDefault();
                    break;
                case "ArrowLeft":
                    moveFocus(-1, 0);
                    e.preventDefault();
                    break;
                case "ArrowRight":
                    moveFocus(1, 0);
                    e.preventDefault();
                    break;
                case "Escape":
                    popFocusTrap();
                    break;
            }
        };
        window.addEventListener("keydown", handler);
        return () => window.removeEventListener("keydown", handler);
    }, [moveFocus, popFocusTrap]);
    // Gamepad polling
    React.useEffect(() => {
        let raf = 0;
        let prevDx = 0, prevDy = 0;
        const poll = () => {
            var _a, _b, _c, _d, _e, _f, _g, _h, _j;
            if (gameModeLockRef.current > 0) {
                raf = requestAnimationFrame(poll);
                return;
            }
            const gps = (_b = (_a = navigator.getGamepads) === null || _a === void 0 ? void 0 : _a.call(navigator)) !== null && _b !== void 0 ? _b : [];
            for (const gp of gps) {
                if (!gp)
                    continue;
                const lx = (_c = gp.axes[0]) !== null && _c !== void 0 ? _c : 0;
                const ly = (_d = gp.axes[1]) !== null && _d !== void 0 ? _d : 0;
                const dx = Math.abs(lx) > 0.5 ? Math.sign(lx) : (((_e = gp.buttons[14]) === null || _e === void 0 ? void 0 : _e.pressed) ? -1 : ((_f = gp.buttons[15]) === null || _f === void 0 ? void 0 : _f.pressed) ? 1 : 0);
                const dy = Math.abs(ly) > 0.5 ? Math.sign(ly) : (((_g = gp.buttons[12]) === null || _g === void 0 ? void 0 : _g.pressed) ? -1 : ((_h = gp.buttons[13]) === null || _h === void 0 ? void 0 : _h.pressed) ? 1 : 0);
                if ((dx !== 0 || dy !== 0) && (dx !== prevDx || dy !== prevDy)) {
                    moveFocus(dx, dy);
                }
                prevDx = dx;
                prevDy = dy;
                if ((_j = gp.buttons[1]) === null || _j === void 0 ? void 0 : _j.pressed)
                    popFocusTrap(); // B = back
                break; // only first pad navigates UI
            }
            raf = requestAnimationFrame(poll);
        };
        raf = requestAnimationFrame(poll);
        return () => cancelAnimationFrame(raf);
    }, [moveFocus, popFocusTrap]);
    const value = {
        register, unregister, moveFocus, setActive: setActiveById,
        activeId, focusables, pushFocusTrap, popFocusTrap,
        enterGameMode, exitGameMode,
    };
    return jsxRuntime.jsx(Ctx.Provider, { value: value, children: children });
}
function useGamepadNavigation() {
    const ctx = React.useContext(Ctx);
    if (!ctx)
        throw new Error("useGamepadNavigation must be inside GamepadNavigationProvider");
    return ctx;
}

exports.GamepadNavigationProvider = GamepadNavigationProvider;
exports.useGamepadNavigation = useGamepadNavigation;
//# sourceMappingURL=GamepadNavigation.js.map
