use leptos::prelude::*;

use super::generated::mini::GRAPH_MINI_SVGS;

/// Inline ego-network SVG thumbnail with click-to-expand overlay.
///
/// Preview renders via SSR. On click (WASM), a fullscreen overlay is created
/// directly on `document.body` — the same DOM-injection pattern used by
/// `ImageModal` — bypassing CSS stacking-context traps in ancestor containers.
#[component]
pub fn GraphMini(
    node_id: String,
    #[prop(optional)] class: Option<String>,
) -> impl IntoView {
    let svg: Option<&'static str> = GRAPH_MINI_SVGS
        .iter()
        .find(|(id, _)| *id == node_id.as_str())
        .map(|(_, svg)| *svg);

    let wrapper_class = format!(
        "content-graph-mini-wrapper {}",
        class.unwrap_or_default()
    );

    svg.map(|svg| view! {
        <div class=wrapper_class>
            <div
                class="content-graph-mini-preview"
                on:click=move |_| {
                    #[cfg(target_arch = "wasm32")]
                    open_graph_overlay(svg);
                }
                on:keydown=move |e: leptos::ev::KeyboardEvent| {
                    if e.key() == "Enter" || e.key() == " " {
                        #[cfg(target_arch = "wasm32")]
                        open_graph_overlay(svg);
                    }
                }
                role="button"
                tabindex="0"
                aria-label="Expand knowledge graph"
            >
                <div aria-hidden="true" inner_html=svg />
            </div>
        </div>
    })
}

/// Creates a fullscreen overlay on `document.body` with the ego SVG.
/// Completely bypasses any CSS stacking context from ancestor containers.
/// Detects current `data-theme` to set correct label/background colors.
#[cfg(target_arch = "wasm32")]
fn open_graph_overlay(svg: &'static str) {
    use wasm_bindgen::JsCast;
    use wasm_bindgen::closure::Closure;

    let Some(document) = web_sys::window().and_then(|w| w.document()) else {
        return;
    };
    let Some(body) = document.body() else { return };

    let is_dark = document
        .document_element()
        .and_then(|el| el.get_attribute("data-theme"))
        .is_some_and(|t| t == "dark");

    let (bg, label_color, edge_color, close_bg) = if is_dark {
        ("#1d232a", "#d1d5db", "#4b5563", "rgba(255,255,255,0.12)")
    } else {
        ("#ffffff", "#374151", "#d1d5db", "rgba(0,0,0,0.08)")
    };

    let overlay = document.create_element("div").expect("create overlay");
    overlay
        .set_attribute(
            "style",
            "position:fixed;inset:0;z-index:9999;display:flex;align-items:center;\
             justify-content:center;background:rgba(0,0,0,0.72);padding:1rem;\
             cursor:zoom-out",
        )
        .ok();
    overlay.set_attribute("role", "dialog").ok();
    overlay.set_attribute("aria-modal", "true").ok();

    let card = document.create_element("div").expect("create card");
    card.set_attribute(
        "style",
        &format!(
            "position:relative;background:{bg};border-radius:0.75rem;padding:1.5rem;\
             width:min(90vw,480px);max-height:90vh;overflow-y:auto;\
             box-shadow:0 20px 60px rgba(0,0,0,0.4);cursor:default;\
             --cg-label:{label_color};--cg-edge:{edge_color}"
        ),
    )
    .ok();

    // SVG container — fills card width for readability
    let svg_div = document.create_element("div").expect("create svg_div");
    svg_div.set_inner_html(svg);
    if let Some(svg_el) = svg_div.first_element_child() {
        svg_el
            .set_attribute("style", "width:100%;height:auto;display:block")
            .ok();
    }

    let close_btn = document.create_element("button").expect("create close btn");
    close_btn
        .set_attribute(
            "style",
            &format!(
                "position:absolute;top:0.75rem;right:0.75rem;width:2rem;height:2rem;\
                 border-radius:9999px;display:flex;align-items:center;justify-content:center;\
                 background:{close_bg};border:none;cursor:pointer;font-size:1.1rem;line-height:1"
            ),
        )
        .ok();
    close_btn.set_attribute("aria-label", "Close graph").ok();
    close_btn.set_inner_html("&times;");

    card.append_child(&svg_div).ok();
    card.append_child(&close_btn).ok();
    overlay.append_child(&card).ok();
    body.append_child(&overlay).ok();

    // Prevent body scroll while overlay is open.
    body.style().set_property("overflow", "hidden").ok();

    // Close: click overlay backdrop or close button.
    let overlay_for_close = overlay.clone();
    let on_backdrop: Closure<dyn Fn(web_sys::MouseEvent)> = Closure::new(move |_: web_sys::MouseEvent| {
        overlay_for_close.remove();
        if let Some(b) = web_sys::window()
            .and_then(|w| w.document())
            .and_then(|d| d.body())
        {
            b.style().remove_property("overflow").ok();
        }
    });
    overlay
        .add_event_listener_with_callback("click", on_backdrop.as_ref().unchecked_ref())
        .ok();
    on_backdrop.forget();

    // Prevent backdrop close when clicking inside the card.
    let stop_prop: Closure<dyn Fn(web_sys::MouseEvent)> = Closure::new(|e: web_sys::MouseEvent| {
        e.stop_propagation();
    });
    card.add_event_listener_with_callback("click", stop_prop.as_ref().unchecked_ref())
        .ok();
    stop_prop.forget();

    // Close button: forwards click to overlay (bypassing stop_propagation on card).
    let overlay_for_btn = overlay.clone();
    let on_btn: Closure<dyn Fn(web_sys::MouseEvent)> = Closure::new(move |e: web_sys::MouseEvent| {
        e.stop_propagation();
        overlay_for_btn.remove();
        if let Some(b) = web_sys::window()
            .and_then(|w| w.document())
            .and_then(|d| d.body())
        {
            b.style().remove_property("overflow").ok();
        }
    });
    close_btn
        .add_event_listener_with_callback("click", on_btn.as_ref().unchecked_ref())
        .ok();
    on_btn.forget();
}
