"""Master composer for card stack JavaScript. Combines viewport height,"""

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

# %% auto #0
__all__ = ['global_callback_name', 'generate_card_stack_js']

# %% ../../nbs/js/core.ipynb #jc000003
from typing import Any, Optional, Tuple

from fasthtml.common import Script

from ..core.config import CardStackConfig
from ..core.html_ids import CardStackHtmlIds
from ..core.button_ids import CardStackButtonIds
from ..core.models import CardStackUrls, CardStackState
from cjm_fasthtml_card_stack.core.constants import (
    width_storage_key, scale_storage_key, card_count_storage_key,
    auto_count_storage_key,
    DEFAULT_CARD_WIDTH, DEFAULT_CARD_SCALE, DEFAULT_VISIBLE_COUNT,
)
from .viewport import generate_viewport_height_js
from .scroll import generate_scroll_nav_js
from .touch import generate_touch_nav_js
from .navigation import generate_page_nav_js
from cjm_fasthtml_card_stack.js.controls import (
    _generate_width_mgmt_js, _generate_scale_mgmt_js, _generate_card_count_mgmt_js,
)
from .auto_adjust import _generate_auto_adjust_js

# %% ../../nbs/js/core.ipynb #jc000009
def _generate_coordinator_js(
    ids: CardStackHtmlIds,  # HTML IDs for this instance
    config: CardStackConfig,  # Config for prefix-unique listener guards
    focus_position: Optional[int] = None,  # Focus slot offset (None=center, -1=bottom, 0=top)
) -> str:  # JS code fragment for master coordinator
    """Generate JS for the master coordinator and HTMX listener."""
    handler_key = f"_csHandlers_{config.prefix.replace('-', '_')}"
    js_focus_pos = "null" if focus_position is None else str(focus_position)
    return f"""
        // === Grid Template Management ===
        ns.applyGridTemplate = function() {{
            const inner = document.getElementById('{ids.card_stack_inner}');
            if (!inner) return;
            const focusPosRaw = {js_focus_pos};
            let tmpl;
            if (focusPosRaw === null) {{
                tmpl = '1fr auto 1fr';
            }} else if (focusPosRaw === 0) {{
                tmpl = 'auto 1fr';
            }} else if (focusPosRaw < 0) {{
                tmpl = '1fr auto';
            }} else {{
                tmpl = '1fr auto 1fr';
            }}
            inner.style.gridTemplateRows = tmpl;
        }};

        // === Master Coordinator ===
        ns.applyAllViewportSettings = function() {{
            requestAnimationFrame(function() {{
                if (ns.applyWidth) ns.applyWidth();
                if (ns.applyScale) ns.applyScale();
                if (ns.applyGridTemplate) ns.applyGridTemplate();
                if (ns.recalculateHeight) ns.recalculateHeight();

                if (ns._setupScrollNav) ns._setupScrollNav();
                if (ns._setupTouchNav) ns._setupTouchNav();

                requestAnimationFrame(function() {{
                    const cs2 = document.getElementById('{ids.card_stack}');
                    if (cs2) cs2.style.opacity = '1';

                    // Continue auto-adjust loop if an adjustment is in flight
                    if (typeof _autoAdjusting !== 'undefined' && _autoAdjusting) {{
                        _autoAdjusting = false;
                        requestAnimationFrame(function() {{
                            if (ns._runAutoAdjust) ns._runAutoAdjust();
                        }});
                    }}
                }});
            }});
        }};

        // === HTMX Event Listeners ===
        // Remove old listeners from previous IIFE (handles HTMX page navigation
        // that re-executes this script without a full page reload).
        if (window.{handler_key}) {{
            document.body.removeEventListener('htmx:afterSwap', window.{handler_key}.swap);
            document.body.removeEventListener('htmx:afterSettle', window.{handler_key}.settle);
        }}

        function _afterSwapHandler(evt) {{
            const target = evt.detail.target;
            if (!target) return;
            const cs = document.getElementById('{ids.card_stack}');
            const isCSSwap = (
                target.id === '{ids.card_stack}' ||
                target.id === '{ids.card_stack_inner}' ||
                (cs && cs.contains(target))
            );
            if (isCSSwap && typeof _autoGrowing !== 'undefined' && _autoGrowing) {{
                _hideNewItems();
            }}
        }}

        function _afterSettleHandler(evt) {{
            const target = evt.detail.target;
            if (!target) return;
            const cs = document.getElementById('{ids.card_stack}');
            const isCSSwap = (
                target.id === '{ids.card_stack}' ||
                target.id === '{ids.card_stack_inner}' ||
                (cs && cs.contains(target))
            );
            if (isCSSwap) {{
                _syncCountDropdown();
                ns.applyAllViewportSettings();
            }}
        }}

        window.{handler_key} = {{ swap: _afterSwapHandler, settle: _afterSettleHandler }};
        document.body.addEventListener('htmx:afterSwap', _afterSwapHandler);
        document.body.addEventListener('htmx:afterSettle', _afterSettleHandler);

        // === Initialize ===
        requestAnimationFrame(function() {{
            _syncCountDropdown();
            setTimeout(function() {{
                // Scroll to top before height calculation to ensure consistent
                // viewport-relative measurements. HTMX navigation may preserve
                // scroll position from the previous page, causing incorrect height.
                window.scrollTo(0, 0);
                ns.applyAllViewportSettings();
                // Trigger auto-adjust after initial layout settles
                if (ns.triggerAutoAdjust) ns.triggerAutoAdjust();
            }}, 50);
        }});
    """

# %% ../../nbs/js/core.ipynb #jhgisn5noqk
# Callback name constants — must match what create_card_stack_nav_actions uses
_GLOBAL_CALLBACKS = (
    "jumpPageUp",
    "jumpPageDown",
    "jumpToFirstItem",
    "jumpToLastItem",
    "decreaseWidth",
    "increaseWidth",
    "decreaseScale",
    "increaseScale",
)

def global_callback_name(
    prefix: str,  # Card stack instance prefix
    callback: str,  # Base callback name (e.g., "jumpPageUp")
) -> str:  # Global function name (e.g., "cs0_jumpPageUp")
    """Generate a prefix-unique global callback name for keyboard navigation."""
    return f"{prefix}_{callback}"

def _generate_global_callbacks_js(
    config: CardStackConfig,  # Config with prefix
) -> str:  # JS code fragment registering global wrappers
    """Register global wrappers for keyboard navigation system."""
    lines = ["        // === Global Keyboard Callbacks ==="]
    for cb in _GLOBAL_CALLBACKS:
        global_name = global_callback_name(config.prefix, cb)
        lines.append(f"        window['{global_name}'] = function() {{ if (ns.{cb}) ns.{cb}(); }};")
    return "\n".join(lines)

# %% ../../nbs/js/core.ipynb #jc000011
def generate_card_stack_js(
    ids: CardStackHtmlIds,  # HTML IDs for this instance
    button_ids: CardStackButtonIds,  # Button IDs for keyboard triggers
    config: CardStackConfig,  # Card stack configuration
    urls: CardStackUrls,  # URL bundle for routing
    container_id: str = "",  # Consumer's parent container ID (for height calc)
    extra_scripts: Tuple[str, ...] = (),  # Additional JS to include in the IIFE
    focus_position: Optional[int] = None,  # Focus slot offset (None=center, -1=bottom, 0=top)
) -> Any:  # Script element with all card stack JavaScript
    """Compose all card stack JS into a single namespaced IIFE."""
    prefix = config.prefix
    extra_js = "\n".join(extra_scripts)

    # Collect all fragments
    viewport_js = generate_viewport_height_js(ids, container_id)
    scroll_js = generate_scroll_nav_js(ids, button_ids, config.disable_scroll_in_modes)
    touch_js = generate_touch_nav_js(ids, button_ids, config.disable_scroll_in_modes)
    page_nav_js = generate_page_nav_js(button_ids)
    width_js = _generate_width_mgmt_js(ids, config, urls)
    scale_js = _generate_scale_mgmt_js(ids, config, urls)
    count_js = _generate_card_count_mgmt_js(ids, config, urls)
    auto_js = _generate_auto_adjust_js(ids, config, urls, focus_position) if config.auto_visible_count else ""
    global_cbs_js = _generate_global_callbacks_js(config)
    coordinator_js = _generate_coordinator_js(ids, config, focus_position)

    return Script(f"""(function() {{
        window.cardStacks = window.cardStacks || {{}};
        const ns = window.cardStacks['{prefix}'] = {{}};

        {viewport_js}
        {scroll_js}
        {touch_js}
        {page_nav_js}
        {width_js}
        {scale_js}
        {count_js}
        {auto_js}
        {global_cbs_js}
        {coordinator_js}
        {extra_js}
    }})();""")
