use dioxus::prelude::*;
use dioxus_free_icons::icons::bs_icons::*;
use dioxus_free_icons::Icon;

use crate::components::code_inspector::CodeInspector;
use crate::components::file_tree::{build_file_tree, FileTree};
use crate::components::page_header::PageHeader;
use crate::components::toast::{ToastType, Toasts};
use crate::infrastructure::graph::{fetch_graph, search_nodes, trigger_graph_build};

#[component]
pub fn GraphExplorerPage(repo_id: String) -> Element {
    rsx! {
        div { class: "back-nav",
            button {
                class: "btn btn-ghost btn-back",
                onclick: move |_| { navigator().go_back(); },
                Icon { icon: BsArrowLeft, width: 16, height: 16 }
                "Back"
            }
        }

        PageHeader {
            title: "Code Knowledge Graph",
            description: "Interactive visualization of code structure and relationships",
        }

        GraphExplorerBody { repo_id: repo_id }
    }
}

/// Inline variant without back button and page header — for embedding in other pages.
#[component]
pub fn GraphExplorerInline(repo_id: String) -> Element {
    rsx! {
        GraphExplorerBody { repo_id: repo_id }
    }
}

/// Shared graph explorer body used by both the full page and inline variants.
#[component]
fn GraphExplorerBody(repo_id: String) -> Element {
    let repo_id_clone = repo_id.clone();
    let mut graph_data = use_resource(move || {
        let rid = repo_id_clone.clone();
        async move {
            if rid.is_empty() {
                return None;
            }
            fetch_graph(rid).await.ok()
        }
    });

    let mut building = use_signal(|| false);
    let mut toasts = use_context::<Toasts>();
    let mut selected_node = use_signal(|| Option::<serde_json::Value>::None);
    let mut inspector_open = use_signal(|| false);
    let mut search_query = use_signal(String::new);
    let mut search_results = use_signal(Vec::<serde_json::Value>::new);
    let mut file_filter = use_signal(String::new);
    let mut nodes_json = use_signal(String::new);
    let mut edges_json = use_signal(String::new);
    let mut graph_ready = use_signal(|| false);

    let graph_data_read = graph_data.read();
    if let Some(Some(data)) = &*graph_data_read {
        if !data.data.nodes.is_empty() && !graph_ready() {
            let nj = serde_json::to_string(&data.data.nodes).unwrap_or_else(|_| "[]".into());
            let ej = serde_json::to_string(&data.data.edges).unwrap_or_else(|_| "[]".into());
            nodes_json.set(nj);
            edges_json.set(ej);
            graph_ready.set(true);
        }
    }

    let (node_count, edge_count, community_count, languages, file_tree_data) =
        if let Some(Some(data)) = &*graph_data_read {
            let build = data.data.build.clone().unwrap_or_default();
            let nc = build
                .get("node_count")
                .and_then(|n| n.as_u64())
                .unwrap_or(0);
            let ec = build
                .get("edge_count")
                .and_then(|n| n.as_u64())
                .unwrap_or(0);
            let cc = build
                .get("community_count")
                .and_then(|n| n.as_u64())
                .unwrap_or(0);
            let langs: Vec<String> = build
                .get("languages_parsed")
                .and_then(|v| v.as_array())
                .map(|arr| {
                    arr.iter()
                        .filter_map(|v| v.as_str().map(String::from))
                        .collect()
                })
                .unwrap_or_default();
            let tree = build_file_tree(&data.data.nodes);
            (nc, ec, cc, langs, tree)
        } else {
            (0, 0, 0, Vec::new(), Vec::new())
        };

    let has_graph_data = matches!(&*graph_data_read, Some(Some(d)) if !d.data.nodes.is_empty());
    drop(graph_data_read);

    use_effect(move || {
        let ready = graph_ready();
        if !ready {
            return;
        }
        let nj = nodes_json();
        let ej = edges_json();
        if nj.is_empty() {
            return;
        }
        spawn(async move {
            let js = format!(
                r#"
                window.__onNodeClick = function(nodeJson) {{
                    var el = document.getElementById('graph-node-click-data');
                    if (el) {{
                        el.value = nodeJson;
                        el.dispatchEvent(new Event('input', {{ bubbles: true }}));
                    }}
                }};
                setTimeout(function() {{
                    if (window.__loadGraph) {{
                        window.__loadGraph({nj}, {ej});
                    }}
                }}, 300);
                "#
            );
            let _ = document::eval(&js);
        });
    });

    let sel = selected_node();
    let sel_file = sel
        .as_ref()
        .and_then(|n| n.get("file_path").and_then(|v| v.as_str()))
        .unwrap_or("")
        .to_string();
    let sel_name = sel
        .as_ref()
        .and_then(|n| n.get("name").and_then(|v| v.as_str()))
        .unwrap_or("")
        .to_string();
    let sel_kind = sel
        .as_ref()
        .and_then(|n| n.get("kind").and_then(|v| v.as_str()))
        .unwrap_or("")
        .to_string();
    let sel_start = sel
        .as_ref()
        .and_then(|n| n.get("start_line").and_then(|v| v.as_u64()))
        .unwrap_or(0) as u32;
    let sel_end = sel
        .as_ref()
        .and_then(|n| n.get("end_line").and_then(|v| v.as_u64()))
        .unwrap_or(0) as u32;

    rsx! {
        if repo_id.is_empty() {
            div { class: "card",
                p { "Select a repository to view its code graph." }
            }
        } else {
            // Toolbar
            div { class: "graph-toolbar",
                button {
                    class: "btn btn-primary",
                    disabled: building(),
                    onclick: {
                        let rid = repo_id.clone();
                        move |_| {
                            let rid = rid.clone();
                            building.set(true);
                            graph_ready.set(false);
                            nodes_json.set(String::new());
                            edges_json.set(String::new());
                            spawn(async move {
                                match trigger_graph_build(rid).await {
                                    Ok(_) => toasts.push(ToastType::Success, "Graph build triggered"),
                                    Err(e) => toasts.push(ToastType::Error, e.to_string()),
                                }
                                building.set(false);
                                graph_data.restart();
                            });
                        }
                    },
                    if building() { "Building..." } else { "Build Graph" }
                }

                div { class: "graph-search-bar",
                    input {
                        r#type: "text",
                        placeholder: "Search nodes...",
                        value: "{search_query}",
                        oninput: {
                            let rid = repo_id.clone();
                            move |e: FormEvent| {
                                let val = e.value();
                                search_query.set(val.clone());
                                if val.len() >= 2 {
                                    let rid = rid.clone();
                                    spawn(async move {
                                        if let Ok(resp) = search_nodes(rid, val).await {
                                            search_results.set(resp.data);
                                        }
                                    });
                                } else {
                                    search_results.set(Vec::new());
                                }
                            }
                        },
                        onkeypress: {
                            let rid = repo_id.clone();
                            move |e: KeyboardEvent| {
                                if e.key() == Key::Enter {
                                    search_results.set(Vec::new());
                                    let q = search_query();
                                    let rid = rid.clone();
                                    if !q.is_empty() {
                                        spawn(async move {
                                            match search_nodes(rid, q).await {
                                                Ok(resp) => {
                                                    let names: Vec<String> = resp.data.iter()
                                                        .filter_map(|n| n.get("qualified_name").and_then(|v| v.as_str()).map(String::from))
                                                        .collect();
                                                    let names_json = serde_json::to_string(&names).unwrap_or_else(|_| "[]".into());
                                                    let js = format!("if (window.__highlightNodes) {{ window.__highlightNodes({names_json}); }}");
                                                    let _ = document::eval(&js);
                                                },
                                                Err(e) => {
                                                    toasts.push(ToastType::Error, e.to_string());
                                                }
                                            }
                                        });
                                    } else {
                                        spawn(async move {
                                            let _ = document::eval("if (window.__clearGraphSelection) { window.__clearGraphSelection(); }");
                                        });
                                    }
                                }
                            }
                        },
                    }
                    if !search_results().is_empty() {
                        div { class: "search-suggestions",
                            for node in search_results() {
                                {
                                    let name = node.get("name").and_then(|v| v.as_str()).unwrap_or("").to_string();
                                    let kind = node.get("kind").and_then(|v| v.as_str()).unwrap_or("").to_string();
                                    let file_path = node.get("file_path").and_then(|v| v.as_str()).unwrap_or("").to_string();
                                    let node_clone = node.clone();
                                    let qname = node.get("qualified_name").and_then(|v| v.as_str()).unwrap_or("").to_string();
                                    rsx! {
                                        div {
                                            class: "search-suggestion-item",
                                            onclick: move |_| {
                                                let nc = node_clone.clone();
                                                let qn = qname.clone();
                                                selected_node.set(Some(nc));
                                                inspector_open.set(true);
                                                search_results.set(Vec::new());
                                                spawn(async move {
                                                    let names_json = serde_json::to_string(&vec![&qn]).unwrap_or_else(|_| "[]".into());
                                                    let js = format!("if (window.__highlightNodes) {{ window.__highlightNodes({names_json}); }}");
                                                    let _ = document::eval(&js);
                                                });
                                            },
                                            span { class: "search-suggestion-name", "{name}" }
                                            span { class: "search-suggestion-kind", "{kind}" }
                                            span { class: "search-suggestion-path", "{file_path}" }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                button {
                    class: "btn-sm",
                    onclick: move |_| {
                        spawn(async move {
                            let _ = document::eval("if (window.__fitGraph) { window.__fitGraph(); }");
                        });
                    },
                    "Fit View"
                }
            }

            // Hidden input for JS → Rust node click communication
            input {
                id: "graph-node-click-data",
                r#type: "hidden",
                value: "",
                oninput: move |e| {
                    let val = e.value();
                    if !val.is_empty() {
                        if let Ok(node) = serde_json::from_str::<serde_json::Value>(&val) {
                            selected_node.set(Some(node));
                            inspector_open.set(true);
                        }
                    }
                },
            }

            // 3-panel layout: file-tree | [code-inspector] | graph-canvas
            div { class: if inspector_open() { "graph-explorer-layout inspector-open" } else { "graph-explorer-layout" },

                // Left: File Tree
                div { class: "file-tree-panel",
                    div { class: "file-tree-header",
                        h4 { "Files" }
                    }
                    div { class: "file-tree-search",
                        input {
                            r#type: "text",
                            placeholder: "Filter files...",
                            value: "{file_filter}",
                            oninput: move |e| file_filter.set(e.value()),
                        }
                    }
                    div { class: "file-tree-content",
                        if file_tree_data.is_empty() {
                            div { class: "file-tree-empty", "No files. Build the graph first." }
                        } else {
                            FileTree {
                                tree: file_tree_data,
                                filter: file_filter(),
                                on_file_click: move |path: String| {
                                    // Open code inspector for this file
                                    let file_node = serde_json::json!({
                                        "file_path": &path,
                                        "name": path.rsplit('/').next().unwrap_or(&path),
                                        "kind": "file",
                                        "start_line": 1,
                                        "end_line": 0,
                                    });
                                    selected_node.set(Some(file_node));
                                    inspector_open.set(true);
                                    // Also highlight in graph
                                    spawn(async move {
                                        let js = format!(
                                            "if (window.__highlightFileNodes) {{ window.__highlightFileNodes('{path}'); }}"
                                        );
                                        let _ = document::eval(&js);
                                    });
                                },
                            }
                        }
                    }
                }

                // Left-center: Code Inspector (between file tree and graph)
                if inspector_open() && selected_node().is_some() {
                    CodeInspector {
                        repo_id: repo_id.clone(),
                        file_path: sel_file,
                        node_name: sel_name,
                        node_kind: sel_kind,
                        start_line: sel_start,
                        end_line: sel_end,
                        on_close: move |_| {
                            inspector_open.set(false);
                            selected_node.set(None);
                        },
                    }
                }

                // Right: Graph Canvas
                div { class: "graph-canvas-panel",
                    if has_graph_data {
                        div {
                            id: "graph-canvas",
                            class: "graph-canvas",
                        }
                        // Stabilization overlay
                        div {
                            id: "graph-stabilization-overlay",
                            class: "graph-stab-overlay",
                            div { class: "graph-stab-content",
                                // Orbital rings
                                div { class: "graph-stab-rings",
                                    div { class: "graph-stab-ring graph-stab-ring-1" }
                                    div { class: "graph-stab-ring graph-stab-ring-2" }
                                    div { class: "graph-stab-ring graph-stab-ring-3" }
                                    div { class: "graph-stab-core" }
                                }
                                div { class: "graph-stab-text",
                                    div { class: "graph-stab-title", "Rendering Graph" }
                                    div { class: "graph-stab-subtitle",
                                        id: "graph-stab-node-info",
                                        "{node_count} nodes \u{00B7} {edge_count} edges"
                                    }
                                }
                                // Progress bar
                                div { class: "graph-stab-progress",
                                    div {
                                        class: "graph-stab-progress-fill",
                                        id: "graph-stab-progress-fill",
                                    }
                                }
                                div {
                                    class: "graph-stab-pct",
                                    id: "graph-stab-pct",
                                    "Initializing\u{2026}"
                                }
                            }
                        }
                    } else if node_count > 0 {
                        // Data exists but nodes array was empty (shouldn't happen)
                        div { class: "loading", "Loading graph visualization..." }
                    } else if (*graph_data.read()).is_none() {
                        div { class: "loading", "Loading graph data..." }
                    } else {
                        div { class: "graph-empty-state",
                            div { class: "graph-empty-icon", "\u{29BB}" }
                            h3 { "No Graph Data" }
                            p { "Click \"Build Graph\" to analyze the repository's code structure." }
                        }
                    }

                    // Stats bar
                    if node_count > 0 {
                        div { class: "graph-stats-bar",
                            span { class: "graph-stat",
                                span { class: "graph-stat-value", "{node_count}" }
                                span { class: "graph-stat-label", " nodes" }
                            }
                            span { class: "graph-stat-divider", "|" }
                            span { class: "graph-stat",
                                span { class: "graph-stat-value", "{edge_count}" }
                                span { class: "graph-stat-label", " edges" }
                            }
                            span { class: "graph-stat-divider", "|" }
                            span { class: "graph-stat",
                                span { class: "graph-stat-value", "{community_count}" }
                                span { class: "graph-stat-label", " communities" }
                            }
                            if !languages.is_empty() {
                                span { class: "graph-stat-divider", "|" }
                                span { class: "graph-stat",
                                    span { class: "graph-stat-label", "{languages.join(\", \")}" }
                                }
                            }
                        }
                    }
                }

            }
        }
    }
}
