//! Floating Pill Navigation — compact centered nav that appears on scroll-up.
//!
//! WASM-only: SSR renders nothing. The pill appears when the user scrolls down
//! past a threshold, and hides when they scroll back toward the top or have
//! been idle at the top. Navigation uses the SPA set_path context.

use leptos::prelude::*;

/// Scroll-aware floating pill navigation bar.
///
/// Appears after scrolling 80px down, hides on scroll-up past the threshold.
/// Renders nothing in SSR. Items come from the same menu registry as the
/// main nav, filtered to internal (non-external) links only.
#[component]
pub fn FloatingPill() -> impl IntoView {
    #[cfg(not(target_arch = "wasm32"))]
    {
        view! { <></> }
    }

    #[cfg(target_arch = "wasm32")]
    {
        use leptos::portal::Portal;
        use rustelo_core_lib::state::use_current_language;
        use rustelo_core_lib::utils::nav;
        use wasm_bindgen::closure::Closure;
        use wasm_bindgen::JsCast as _;

        // Visible once scrolled past SHOW_THRESHOLD px.
        let visible = RwSignal::new(false);
        let lang_signal = use_current_language();
        let set_path_ctx = use_context::<WriteSignal<String>>();
        // Palette open signal — used to render the search button inside the pill.
        let palette_open =
            use_context::<crate::navigation::command_palette::CommandPaletteOpen>().map(|c| c.0);

        // Attach scroll listener — show/hide pill based on Y position.
        // Hidden when near the bottom to avoid overlapping the footer.
        {
            const SHOW_THRESHOLD: f64 = 80.0;
            const NEAR_BOTTOM_THRESHOLD: f64 = 120.0;
            let closure = Closure::wrap(Box::new(move || {
                if let Some(w) = web_sys::window() {
                    let scroll_y = w.scroll_y().unwrap_or(0.0);
                    let near_bottom = w
                        .document()
                        .and_then(|d| d.document_element())
                        .and_then(|root| {
                            w.inner_height().ok().and_then(|vh| {
                                let doc_h = root.scroll_height() as f64;
                                let vp_h = vh.as_f64().unwrap_or(0.0);
                                Some(doc_h - scroll_y - vp_h < NEAR_BOTTOM_THRESHOLD)
                            })
                        })
                        .unwrap_or(false);
                    visible.set(scroll_y > SHOW_THRESHOLD && !near_bottom);
                }
            }) as Box<dyn Fn()>);

            if let Some(w) = web_sys::window() {
                let _ =
                    w.add_event_listener_with_callback("scroll", closure.as_ref().unchecked_ref());
            }
            closure.forget();
        }

        // Whether the nav items are expanded.
        let nav_open = RwSignal::new(false);

        // Reactive tooltip label — re-computed when language or open state changes.
        let toggle_label = Memo::new(move |_| {
            let lang = lang_signal.get();
            let key = if nav_open.get() {
                "nav-pill-hide"
            } else {
                "nav-pill-show"
            };
            ::rustelo_core_lib::i18n::UnifiedI18n::new(&lang, "/").t(key)
        });

        // Menu items — only internal, non-auth-required links.
        let items_memo = Memo::new(move |_| {
            let lang = lang_signal.get();
            let all = rustelo_core_lib::load_reactive_menu_for_language(&lang).unwrap_or_default();
            all.into_iter()
                .filter(|item| !item.is_external.unwrap_or(false) && !item.auth_required)
                .map(|item| {
                    let label = item
                        .label
                        .get_for_language(&lang)
                        .cloned()
                        .unwrap_or_else(|| item.route.clone());
                    let route = item.get_route_for_language(&lang).to_string();
                    (label, route)
                })
                .collect::<Vec<_>>()
        });

        // Portal mounts the pill into document.body outside the SSR hydration stream.
        // display:none when not visible eliminates any z-index interaction with
        // CommandPalette (z-9998/9999) while the pill is hidden.
        view! {
            <Portal>
                <nav
                    class="floating-pill"
                    style=move || if !visible.get() { "display:none;" } else { "" }
                    aria-label="Quick navigation"
                >
                    // Toggle button — always visible
                    <button
                        type="button"
                        class="pill-icon-btn"
                        on:click=move |_| nav_open.update(|v| *v = !*v)
                        aria-label=move || toggle_label.get()
                        aria-expanded=move || nav_open.get().to_string()
                        title=move || toggle_label.get()
                    >
                        {move || if nav_open.get() {
                            // X close — filled crosses
                            view! {
                                <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
                                    <path d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"/>
                                </svg>
                            }.into_any()
                        } else {
                            // Hamburger — three solid bars
                            view! {
                                <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
                                    <rect x="2" y="4" width="16" height="2.5" rx="1.25"/>
                                    <rect x="2" y="9" width="16" height="2.5" rx="1.25"/>
                                    <rect x="2" y="14" width="16" height="2.5" rx="1.25"/>
                                </svg>
                            }.into_any()
                        }}
                    </button>

                    // Command palette button — always visible
                    {palette_open.map(|sig| view! {
                        <button
                            type="button"
                            class="pill-icon-btn"
                            on:click=move |_| sig.update(|v| *v = !*v)
                            title="Cmd+K"
                            aria-label="Open command palette"
                        >
                            <svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0"/>
                            </svg>
                        </button>
                    })}

                    // Nav items — scrollable container so items never push toggle off-screen
                    <Show when=move || nav_open.get()>
                        <div class="pill-items">
                            <span class="pill-divider"></span>
                            {move || {
                                items_memo
                                    .get()
                                    .into_iter()
                                    .map(|(label, route)| {
                                        let route_nav = route.clone();
                                        let sp = set_path_ctx;
                                        view! {
                                            <button
                                                type="button"
                                                class="pill-nav-btn"
                                                on:click=move |_| {
                                                    if let Some(sp) = sp {
                                                        nav::anchor_navigate(sp, &route_nav);
                                                    }
                                                    nav_open.set(false);
                                                }
                                            >
                                                {label}
                                            </button>
                                        }
                                    })
                                    .collect_view()
                            }}
                        </div>
                    </Show>
                </nav>
            </Portal>
        }
    }
}
