"""JavaScript generator for scroll-to-nav conversion."""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/js/scroll.ipynb.

# %% auto #0
__all__ = ['generate_scroll_nav_js']

# %% ../../nbs/js/scroll.ipynb #js000003
from typing import Tuple

from ..core.html_ids import CardStackHtmlIds
from ..core.button_ids import CardStackButtonIds
from ..core.constants import SCROLL_THRESHOLD, NAVIGATION_COOLDOWN, TRACKPAD_COOLDOWN

# %% ../../nbs/js/scroll.ipynb #js000005
def generate_scroll_nav_js(
    ids: CardStackHtmlIds,  # HTML IDs for this card stack instance
    button_ids: CardStackButtonIds,  # Button IDs for navigation triggers
    disable_in_modes: Tuple[str, ...] = (),  # Mode names where scroll nav is suppressed
) -> str:  # JavaScript code fragment for scroll navigation
    """Generate JS for scroll wheel to navigation conversion."""
    # Build mode check
    if disable_in_modes:
        modes_array = ', '.join(f"'{m}'" for m in disable_in_modes)
        mode_check = f"""
        function isScrollDisabled() {{
            if (typeof window.kbNav !== 'undefined') {{
                const state = window.kbNav.getState();
                const disabledModes = [{modes_array}];
                return state && disabledModes.includes(state.currentMode);
            }}
            return false;
        }}
        """
        mode_guard = "if (isScrollDisabled()) return;"
    else:
        mode_check = ""
        mode_guard = ""

    # Threshold for classifying input as trackpad vs mouse wheel.
    # Mouse wheels typically send |deltaY| >= 50 per tick;
    # trackpads send small continuous values (1-30).
    trackpad_detect_threshold = 50

    return f"""
        // === Scroll Navigation ===
        const _scrollState = {{ accumulatedDelta: 0, lastNavTime: 0 }};
        const _SCROLL_THRESHOLD = {SCROLL_THRESHOLD};
        const _NAV_COOLDOWN = {NAVIGATION_COOLDOWN};
        const _TRACKPAD_COOLDOWN = {TRACKPAD_COOLDOWN};
        const _TRACKPAD_DETECT = {trackpad_detect_threshold};
        {mode_check}
        function setupScrollNavigation() {{
            const cardStack = document.getElementById('{ids.card_stack}');
            if (!cardStack) return;

            // Abort previous listeners (handles re-setup from afterSettle
            // and IIFE re-execution from HTMX page navigation).
            if (cardStack._scrollNavAbort) cardStack._scrollNavAbort.abort();
            const controller = new AbortController();
            cardStack._scrollNavAbort = controller;

            cardStack.addEventListener('wheel', function(evt) {{
                {mode_guard}
                evt.preventDefault();

                // Normalize deltaY based on deltaMode
                let deltaY = evt.deltaY;
                if (evt.deltaMode === 1) deltaY *= 32;      // DOM_DELTA_LINE
                else if (evt.deltaMode === 2) deltaY *= 800; // DOM_DELTA_PAGE

                // Pick cooldown based on input type: small deltas = trackpad
                const cooldown = Math.abs(deltaY) < _TRACKPAD_DETECT
                    ? _TRACKPAD_COOLDOWN : _NAV_COOLDOWN;

                // Use event creation time for cooldown (not Date.now() wall time).
                // Batched events from main-thread blockage share the same timeStamp,
                // so only the first in a batch passes cooldown.
                const eventTime = evt.timeStamp;

                if (eventTime - _scrollState.lastNavTime > cooldown * 2) {{
                    _scrollState.accumulatedDelta = 0;
                }}
                _scrollState.accumulatedDelta += deltaY;

                if (Math.abs(_scrollState.accumulatedDelta) < _SCROLL_THRESHOLD) return;

                if (eventTime - _scrollState.lastNavTime >= cooldown) {{
                    // Cooldown passed — fire navigation
                    const btnId = _scrollState.accumulatedDelta > 0
                        ? '{button_ids.nav_down}' : '{button_ids.nav_up}';
                    _scrollState.accumulatedDelta = 0;
                    _scrollState.lastNavTime = eventTime;
                    const btn = document.getElementById(btnId);
                    if (btn) btn.click();
                }} else if (eventTime === _scrollState.lastNavTime) {{
                    // Same-batch event (main-thread blockage) — discard
                    _scrollState.accumulatedDelta = 0;
                }}
                // else: real event during cooldown (e.g. trackpad) — keep
                // accumulated delta so it fires on the next cooldown-passing event
            }}, {{ passive: false, signal: controller.signal }});
        }}

        // Expose for master coordinator to re-setup after swaps
        ns._setupScrollNav = setupScrollNavigation;
    """
