// content_graph/graph_view.rs
//
// Full-page interactive knowledge graph via Cytoscape.js.
// Follows the SSR+WASM delegation pattern used across the codebase.
//
// SSR: renders container div + embedded JSON data script tag.
// WASM: Effect::new calls window.ContentGraph.render() after mount.

use leptos::prelude::*;

use super::GRAPH_JSON;

// ── Entry point (delegating component) ───────────────────────────────────────

/// Full-page knowledge graph view.
///
/// `node_id`: when provided, the graph centers on that node (ego view).
#[component]
pub fn GraphView(
    #[prop(optional)] node_id: Option<String>,
    #[prop(default = String::from("light"))] theme: String,
) -> impl IntoView {
    #[cfg(not(target_arch = "wasm32"))]
    return view! { <GraphViewInner node_id=node_id theme=theme /> };

    #[cfg(target_arch = "wasm32")]
    return view! { <GraphViewClient node_id=node_id theme=theme /> };
}

// ── Inner (SSR) ───────────────────────────────────────────────────────────────

#[component]
fn GraphViewInner(
    node_id: Option<String>,
    theme:   String,
) -> impl IntoView {
    let focus   = node_id.unwrap_or_default();
    let graph_json_safe = GRAPH_JSON.replace("</", "\\/");

    view! {
        <div class="content-graph-page w-full">
            // Embedded graph data — read by the JS shim
            <script
                type="application/json"
                id="content-graph-data"
                inner_html=graph_json_safe
            />
            // Cytoscape container
            <div
                id="content-graph-cyto"
                data-focus=focus
                data-theme=theme
                class="w-full h-[600px] ds-bg-page ds-border ds-rounded-lg overflow-hidden"
                aria-label="Knowledge graph visualisation"
                role="img"
            >
                <noscript>
                    <p class="p-4 ds-caption text-center">
                        "Interactive graph requires JavaScript."
                    </p>
                </noscript>
            </div>
        </div>
    }
}

// ── Client (WASM) ─────────────────────────────────────────────────────────────

#[component]
fn GraphViewClient(
    node_id: Option<String>,
    theme:   String,
) -> impl IntoView {
    let focus       = node_id.unwrap_or_default();
    let focus_clone = focus.clone();
    let theme_clone = theme.clone();

    // Initialise Cytoscape after the component mounts in the browser
    Effect::new(move |_| {
        let focus = focus_clone.clone();
        let theme = theme_clone.clone();
        call_cytoscape_render("content-graph-cyto", &focus, &theme);
    });

    // On unmount, destroy the Cytoscape instance
    on_cleanup(move || {
        call_cytoscape_destroy("content-graph-cyto");
    });

    view! {
        <div class="content-graph-page w-full">
            <div
                id="content-graph-cyto"
                data-focus=focus
                data-theme=theme
                class="w-full h-[600px] ds-bg-page ds-border ds-rounded-lg overflow-hidden"
                aria-label="Knowledge graph visualisation"
                role="img"
            />
        </div>
    }
}

// ── JS interop ────────────────────────────────────────────────────────────────

#[cfg(target_arch = "wasm32")]
fn call_cytoscape_render(container_id: &str, focus: &str, theme: &str) {
    use wasm_bindgen::JsValue;

    let Some(window) = web_sys::window() else { return };
    let Ok(content_graph) = js_sys::Reflect::get(&window, &JsValue::from_str("ContentGraph")) else { return };
    let Ok(render_fn) = js_sys::Reflect::get(&content_graph, &JsValue::from_str("render")) else { return };
    let render_fn: js_sys::Function = render_fn.dyn_into().unwrap_or_else(|_| js_sys::Function::new_no_args(""));
    let _ = render_fn.call3(
        &content_graph,
        &JsValue::from_str(container_id),
        &JsValue::from_str(focus),
        &JsValue::from_str(theme),
    );
}

#[cfg(not(target_arch = "wasm32"))]
fn call_cytoscape_render(_container_id: &str, _focus: &str, _theme: &str) {}

#[cfg(target_arch = "wasm32")]
fn call_cytoscape_destroy(container_id: &str) {
    use wasm_bindgen::JsValue;

    let Some(window) = web_sys::window() else { return };
    let Ok(content_graph) = js_sys::Reflect::get(&window, &JsValue::from_str("ContentGraph")) else { return };
    let Ok(destroy_fn) = js_sys::Reflect::get(&content_graph, &JsValue::from_str("destroy")) else { return };
    let destroy_fn: js_sys::Function = destroy_fn.dyn_into().unwrap_or_else(|_| js_sys::Function::new_no_args(""));
    let _ = destroy_fn.call1(&content_graph, &JsValue::from_str(container_id));
}

#[cfg(not(target_arch = "wasm32"))]
fn call_cytoscape_destroy(_container_id: &str) {}
