use dioxus::prelude::*;

use crate::components::page_header::PageHeader;
use crate::components::pagination::Pagination;
use crate::infrastructure::sbom::*;

#[component]
pub fn SbomPage() -> Element {
    // ── Filter signals ──
    let mut page = use_signal(|| 1u64);
    let mut repo_filter = use_signal(String::new);
    let mut pm_filter = use_signal(String::new);
    let mut search_q = use_signal(String::new);
    let mut vuln_toggle = use_signal(|| Option::<bool>::None);
    let mut license_filter = use_signal(String::new);

    // ── Active tab: "packages" | "licenses" | "diff" ──
    let mut active_tab = use_signal(|| "packages".to_string());

    // ── Vuln drill-down: track expanded row by (name, version) ──
    let mut expanded_row = use_signal(|| Option::<String>::None);

    // ── Export state ──
    let mut show_export = use_signal(|| false);
    let mut export_format = use_signal(|| "cyclonedx".to_string());

    // ── Diff state ──
    let mut diff_repo_a = use_signal(String::new);
    let mut diff_repo_b = use_signal(String::new);

    // ── Targets for dropdowns ──
    let repos = use_resource(|| async {
        crate::infrastructure::onboarding::fetch_targets()
            .await
            .ok()
    });

    // ── Dynamic filter options (package managers + licenses from DB) ──
    let sbom_filters = use_resource(|| async { fetch_sbom_filters().await.ok() });

    // ── SBOM list (filtered) ──
    let sbom = use_resource(move || {
        let p = page();
        let repo = repo_filter();
        let pm = pm_filter();
        let q = search_q();
        let hv = vuln_toggle();
        let lic = license_filter();
        async move {
            fetch_sbom_filtered(
                if repo.is_empty() { None } else { Some(repo) },
                if pm.is_empty() { None } else { Some(pm) },
                if q.is_empty() { None } else { Some(q) },
                hv,
                if lic.is_empty() { None } else { Some(lic) },
                p,
            )
            .await
            .ok()
        }
    });

    // ── License summary ──
    let license_data = use_resource(move || {
        let repo = repo_filter();
        async move {
            fetch_license_summary(if repo.is_empty() { None } else { Some(repo) })
                .await
                .ok()
        }
    });

    // ── Diff data ──
    let diff_data = use_resource(move || {
        let a = diff_repo_a();
        let b = diff_repo_b();
        async move {
            if a.is_empty() || b.is_empty() {
                return None;
            }
            fetch_sbom_diff(a, b).await.ok()
        }
    });

    rsx! {
        PageHeader {
            title: "SBOM",
            description: "Software Bill of Materials — dependency inventory, license compliance, and vulnerability analysis",
        }

        // ── Tab bar ──
        div { class: "sbom-tab-bar",
            button {
                class: if active_tab() == "packages" { "sbom-tab active" } else { "sbom-tab" },
                onclick: move |_| active_tab.set("packages".to_string()),
                "Packages"
            }
            button {
                class: if active_tab() == "licenses" { "sbom-tab active" } else { "sbom-tab" },
                onclick: move |_| active_tab.set("licenses".to_string()),
                "License Compliance"
            }
            button {
                class: if active_tab() == "diff" { "sbom-tab active" } else { "sbom-tab" },
                onclick: move |_| active_tab.set("diff".to_string()),
                "Compare"
            }
        }

        // ═══════════════ PACKAGES TAB ═══════════════
        if active_tab() == "packages" {
            // ── Filter bar ──
            div { class: "sbom-filter-bar",
                select {
                    class: "sbom-filter-select",
                    onchange: move |e| { repo_filter.set(e.value()); page.set(1); },
                    option { value: "", "All Targets" }
                    {
                        match &*repos.read() {
                            Some(Some(resp)) => rsx! {
                                for repo in &resp.data {
                                    {
                                        let id = repo.get("_id").and_then(|o| o.get("$oid")).and_then(|s| s.as_str()).unwrap_or_default().to_string();
                                        let name = repo.get("name").and_then(|n| n.as_str()).unwrap_or_default().to_string();
                                        rsx! { option { value: "{id}", "{name}" } }
                                    }
                                }
                            },
                            _ => rsx! {},
                        }
                    }
                }
                select {
                    class: "sbom-filter-select",
                    onchange: move |e| { pm_filter.set(e.value()); page.set(1); },
                    option { value: "", "All Managers" }
                    {
                        match &*sbom_filters.read() {
                            Some(Some(f)) => rsx! {
                                for pm in &f.package_managers {
                                    {
                                        let val = pm.clone();
                                        let label = pm_display_name(&val);
                                        rsx! { option { value: "{val}", "{label}" } }
                                    }
                                }
                            },
                            _ => rsx! {},
                        }
                    }
                }
                input {
                    class: "sbom-filter-input",
                    r#type: "text",
                    placeholder: "Search packages...",
                    oninput: move |e| { search_q.set(e.value()); page.set(1); },
                }
                select {
                    class: "sbom-filter-select",
                    onchange: move |e| {
                        let val = e.value();
                        vuln_toggle.set(match val.as_str() {
                            "true" => Some(true),
                            "false" => Some(false),
                            _ => None,
                        });
                        page.set(1);
                    },
                    option { value: "", "All Packages" }
                    option { value: "true", "With Vulnerabilities" }
                    option { value: "false", "No Vulnerabilities" }
                }
                select {
                    class: "sbom-filter-select",
                    onchange: move |e| { license_filter.set(e.value()); page.set(1); },
                    option { value: "", "All Licenses" }
                    {
                        match &*sbom_filters.read() {
                            Some(Some(f)) => rsx! {
                                for lic in &f.licenses {
                                    {
                                        let val = lic.clone();
                                        rsx! { option { value: "{val}", "{val}" } }
                                    }
                                }
                            },
                            _ => rsx! {},
                        }
                    }
                }

                // ── Export button ──
                div { class: "sbom-export-wrapper",
                    button {
                        class: "btn btn-secondary sbom-export-btn",
                        onclick: move |_| show_export.toggle(),
                        "Export"
                    }
                    if show_export() {
                        div { class: "sbom-export-dropdown",
                            select {
                                class: "sbom-filter-select",
                                value: "{export_format}",
                                onchange: move |e| export_format.set(e.value()),
                                option { value: "cyclonedx", "CycloneDX 1.5" }
                                option { value: "spdx", "SPDX 2.3" }
                            }
                            button {
                                class: "btn btn-primary",
                                disabled: repo_filter().is_empty(),
                                onclick: move |_| {
                                    let repo = repo_filter();
                                    let fmt = export_format();
                                    spawn(async move {
                                        match fetch_sbom_export(repo.clone(), fmt.clone()).await {
                                            Ok(json) => {
                                                let filename = if fmt == "spdx" {
                                                    format!("sbom-{repo}-spdx.json")
                                                } else {
                                                    format!("sbom-{repo}-cyclonedx.json")
                                                };
                                                trigger_download(&json, &filename);
                                            }
                                            Err(e) => tracing::error!("Export failed: {e}"),
                                        }
                                    });
                                },
                                "Download"
                            }
                            if repo_filter().is_empty() {
                                span { class: "sbom-export-hint", "Select a repo first" }
                            }
                        }
                    }
                }
            }

            // ── SBOM table ──
            match &*sbom.read() {
                Some(Some(resp)) => {
                    let total_pages = resp.total.unwrap_or(0).div_ceil(50).max(1);
                    rsx! {
                        if let Some(total) = resp.total {
                            div { class: "sbom-result-count",
                                "{total} package(s) found"
                            }
                        }
                        div { class: "card",
                            div { class: "table-wrapper",
                                table {
                                    thead {
                                        tr {
                                            th { "Package" }
                                            th { "Version" }
                                            th { "Manager" }
                                            th { "License" }
                                            th { "Vulnerabilities" }
                                        }
                                    }
                                    tbody {
                                        for entry in &resp.data {
                                            {
                                                let row_key = format!("{}@{}", entry.name, entry.version);
                                                let is_expanded = expanded_row() == Some(row_key.clone());
                                                let has_vulns = !entry.known_vulnerabilities.is_empty();
                                                let license_class = license_css_class(entry.license.as_deref());
                                                let row_key_click = row_key.clone();
                                                rsx! {
                                                    tr {
                                                        td {
                                                            style: "font-weight: 500;",
                                                            "{entry.name}"
                                                        }
                                                        td {
                                                            style: "font-family: var(--font-mono, monospace); font-size: 13px;",
                                                            "{entry.version}"
                                                        }
                                                        td { "{entry.package_manager}" }
                                                        td {
                                                            span { class: "sbom-license-badge {license_class}",
                                                                "{entry.license.as_deref().unwrap_or(\"-\")}"
                                                            }
                                                        }
                                                        td {
                                                            if has_vulns {
                                                                span {
                                                                    class: "badge badge-high sbom-vuln-toggle",
                                                                    onclick: move |_| {
                                                                        let key = row_key_click.clone();
                                                                        if expanded_row() == Some(key.clone()) {
                                                                            expanded_row.set(None);
                                                                        } else {
                                                                            expanded_row.set(Some(key));
                                                                        }
                                                                    },
                                                                    "{entry.known_vulnerabilities.len()} vuln(s) ▾"
                                                                }
                                                            } else {
                                                                span {
                                                                    style: "color: var(--success);",
                                                                    "None"
                                                                }
                                                            }
                                                        }
                                                    }
                                                    // ── Vulnerability drill-down row ──
                                                    if is_expanded && has_vulns {
                                                        tr { class: "sbom-vuln-detail-row",
                                                            td { colspan: "5",
                                                                div { class: "sbom-vuln-detail",
                                                                    for vuln in &entry.known_vulnerabilities {
                                                                        div { class: "sbom-vuln-card",
                                                                            div { class: "sbom-vuln-card-header",
                                                                                span { class: "sbom-vuln-id", "{vuln.id}" }
                                                                                span { class: "sbom-vuln-source", "{vuln.source}" }
                                                                                if let Some(sev) = &vuln.severity {
                                                                                    span {
                                                                                        class: "badge badge-{sev}",
                                                                                        "{sev}"
                                                                                    }
                                                                                }
                                                                            }
                                                                            if let Some(url) = &vuln.url {
                                                                                a {
                                                                                    href: "{url}",
                                                                                    target: "_blank",
                                                                                    class: "sbom-vuln-link",
                                                                                    "View Advisory →"
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            Pagination {
                                current_page: page(),
                                total_pages: total_pages,
                                on_page_change: move |p| page.set(p),
                            }
                        }
                    }
                },
                Some(None) => rsx! {
                    div { class: "card", p { "Failed to load SBOM." } }
                },
                None => rsx! {
                    div { class: "loading", "Loading SBOM..." }
                },
            }
        }

        // ═══════════════ LICENSE COMPLIANCE TAB ═══════════════
        if active_tab() == "licenses" {
            match &*license_data.read() {
                Some(Some(resp)) => {
                    let total_pkgs: u64 = resp.data.iter().map(|l| l.count).sum();
                    let has_copyleft = resp.data.iter().any(|l| l.is_copyleft);
                    let copyleft_items: Vec<_> = resp.data.iter().filter(|l| l.is_copyleft).collect();

                    rsx! {
                        if has_copyleft {
                            div { class: "license-copyleft-warning",
                                strong { "⚠ Copyleft Licenses Detected" }
                                p { "The following copyleft-licensed packages may impose distribution requirements on your software." }
                                for item in &copyleft_items {
                                    div { class: "license-copyleft-item",
                                        span { class: "sbom-license-badge license-copyleft", "{item.license}" }
                                        span { " — {item.count} package(s): " }
                                        span { class: "license-pkg-list",
                                            "{item.packages.join(\", \")}"
                                        }
                                    }
                                }
                            }
                        }

                        div { class: "card",
                            h3 { style: "margin-bottom: 16px;", "License Distribution" }
                            if total_pkgs > 0 {
                                div { class: "license-bar-chart",
                                    for item in &resp.data {
                                        {
                                            let pct = (item.count as f64 / total_pkgs as f64 * 100.0).max(2.0);
                                            let bar_class = if item.is_copyleft { "license-bar license-copyleft" } else { "license-bar license-permissive" };
                                            rsx! {
                                                div { class: "license-bar-row",
                                                    span { class: "license-bar-label", "{item.license}" }
                                                    div { class: "license-bar-track",
                                                        div {
                                                            class: "{bar_class}",
                                                            style: "width: {pct}%;",
                                                        }
                                                    }
                                                    span { class: "license-bar-count", "{item.count}" }
                                                }
                                            }
                                        }
                                    }
                                }
                            } else {
                                p { "No license data available." }
                            }
                        }

                        div { class: "card",
                            h3 { style: "margin-bottom: 16px;", "All Licenses" }
                            div { class: "table-wrapper",
                                table {
                                    thead {
                                        tr {
                                            th { "License" }
                                            th { "Type" }
                                            th { "Packages" }
                                            th { "Count" }
                                        }
                                    }
                                    tbody {
                                        for item in &resp.data {
                                            tr {
                                                td {
                                                    span {
                                                        class: "sbom-license-badge {license_type_class(item.is_copyleft)}",
                                                        "{item.license}"
                                                    }
                                                }
                                                td {
                                                    if item.is_copyleft {
                                                        span { class: "badge badge-high", "Copyleft" }
                                                    } else {
                                                        span { class: "badge badge-info", "Permissive" }
                                                    }
                                                }
                                                td {
                                                    style: "max-width: 400px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;",
                                                    "{item.packages.join(\", \")}"
                                                }
                                                td { "{item.count}" }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                Some(None) => rsx! {
                    div { class: "card", p { "Failed to load license summary." } }
                },
                None => rsx! {
                    div { class: "loading", "Loading license data..." }
                },
            }
        }

        // ═══════════════ DIFF TAB ═══════════════
        if active_tab() == "diff" {
            div { class: "card",
                h3 { style: "margin-bottom: 16px;", "Compare SBOMs Between Repositories" }
                div { class: "sbom-diff-controls",
                    div { class: "sbom-diff-select-group",
                        label { "Repository A" }
                        select {
                            class: "sbom-filter-select",
                            onchange: move |e| diff_repo_a.set(e.value()),
                            option { value: "", "Select repository..." }
                            {
                                match &*repos.read() {
                                    Some(Some(resp)) => rsx! {
                                        for repo in &resp.data {
                                            {
                                                let id = repo.get("_id").and_then(|o| o.get("$oid")).and_then(|s| s.as_str()).unwrap_or_default().to_string();
                                                let name = repo.get("name").and_then(|n| n.as_str()).unwrap_or_default().to_string();
                                                rsx! { option { value: "{id}", "{name}" } }
                                            }
                                        }
                                    },
                                    _ => rsx! {},
                                }
                            }
                        }
                    }
                    div { class: "sbom-diff-select-group",
                        label { "Repository B" }
                        select {
                            class: "sbom-filter-select",
                            onchange: move |e| diff_repo_b.set(e.value()),
                            option { value: "", "Select repository..." }
                            {
                                match &*repos.read() {
                                    Some(Some(resp)) => rsx! {
                                        for repo in &resp.data {
                                            {
                                                let id = repo.get("_id").and_then(|o| o.get("$oid")).and_then(|s| s.as_str()).unwrap_or_default().to_string();
                                                let name = repo.get("name").and_then(|n| n.as_str()).unwrap_or_default().to_string();
                                                rsx! { option { value: "{id}", "{name}" } }
                                            }
                                        }
                                    },
                                    _ => rsx! {},
                                }
                            }
                        }
                    }
                }
            }

            if !diff_repo_a().is_empty() && !diff_repo_b().is_empty() {
                match &*diff_data.read() {
                    Some(Some(resp)) => {
                        let d = &resp.data;
                        rsx! {
                            div { class: "sbom-diff-summary",
                                div { class: "sbom-diff-stat sbom-diff-added",
                                    span { class: "sbom-diff-stat-num", "{d.only_in_a.len()}" }
                                    span { "Only in A" }
                                }
                                div { class: "sbom-diff-stat sbom-diff-removed",
                                    span { class: "sbom-diff-stat-num", "{d.only_in_b.len()}" }
                                    span { "Only in B" }
                                }
                                div { class: "sbom-diff-stat sbom-diff-changed",
                                    span { class: "sbom-diff-stat-num", "{d.version_changed.len()}" }
                                    span { "Version Diffs" }
                                }
                                div { class: "sbom-diff-stat",
                                    span { class: "sbom-diff-stat-num", "{d.common_count}" }
                                    span { "Common" }
                                }
                            }

                            if !d.only_in_a.is_empty() {
                                div { class: "card",
                                    h4 { style: "margin-bottom: 12px; color: var(--success);", "Only in Repository A" }
                                    div { class: "table-wrapper",
                                        table {
                                            thead {
                                                tr {
                                                    th { "Package" }
                                                    th { "Version" }
                                                    th { "Manager" }
                                                }
                                            }
                                            tbody {
                                                for e in &d.only_in_a {
                                                    tr { class: "sbom-diff-row-added",
                                                        td { "{e.name}" }
                                                        td { "{e.version}" }
                                                        td { "{e.package_manager}" }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }

                            if !d.only_in_b.is_empty() {
                                div { class: "card",
                                    h4 { style: "margin-bottom: 12px; color: var(--danger);", "Only in Repository B" }
                                    div { class: "table-wrapper",
                                        table {
                                            thead {
                                                tr {
                                                    th { "Package" }
                                                    th { "Version" }
                                                    th { "Manager" }
                                                }
                                            }
                                            tbody {
                                                for e in &d.only_in_b {
                                                    tr { class: "sbom-diff-row-removed",
                                                        td { "{e.name}" }
                                                        td { "{e.version}" }
                                                        td { "{e.package_manager}" }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }

                            if !d.version_changed.is_empty() {
                                div { class: "card",
                                    h4 { style: "margin-bottom: 12px; color: var(--warning);", "Version Differences" }
                                    div { class: "table-wrapper",
                                        table {
                                            thead {
                                                tr {
                                                    th { "Package" }
                                                    th { "Manager" }
                                                    th { "Version A" }
                                                    th { "Version B" }
                                                }
                                            }
                                            tbody {
                                                for e in &d.version_changed {
                                                    tr { class: "sbom-diff-row-changed",
                                                        td { "{e.name}" }
                                                        td { "{e.package_manager}" }
                                                        td { "{e.version_a}" }
                                                        td { "{e.version_b}" }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }

                            if d.only_in_a.is_empty() && d.only_in_b.is_empty() && d.version_changed.is_empty() {
                                div { class: "card",
                                    p { "Both repositories have identical SBOM entries." }
                                }
                            }
                        }
                    },
                    Some(None) => rsx! {
                        div { class: "card", p { "Failed to load diff." } }
                    },
                    None => rsx! {
                        div { class: "loading", "Computing diff..." }
                    },
                }
            }
        }
    }
}

fn pm_display_name(pm: &str) -> &str {
    match pm {
        "npm" => "npm",
        "cargo" => "Cargo",
        "pip" => "pip",
        "go" | "golang" => "Go",
        "maven" => "Maven",
        "nuget" => "NuGet",
        "composer" => "Composer",
        "gem" => "RubyGems",
        "github" => "GitHub Actions",
        other => other,
    }
}

fn license_css_class(license: Option<&str>) -> &'static str {
    match license {
        Some(l) => {
            let upper = l.to_uppercase();
            if upper.contains("GPL") || upper.contains("AGPL") {
                "license-copyleft"
            } else if upper.contains("LGPL") || upper.contains("MPL") {
                "license-weak-copyleft"
            } else {
                "license-permissive"
            }
        }
        None => "",
    }
}

fn license_type_class(is_copyleft: bool) -> &'static str {
    if is_copyleft {
        "license-copyleft"
    } else {
        "license-permissive"
    }
}

#[cfg(feature = "web")]
fn trigger_download(content: &str, filename: &str) {
    use wasm_bindgen::JsCast;
    let Some(window) = web_sys::window() else {
        return;
    };
    let Some(document) = window.document() else {
        return;
    };

    let blob_parts = js_sys::Array::new();
    blob_parts.push(&wasm_bindgen::JsValue::from_str(content));

    let opts = web_sys::BlobPropertyBag::new();
    opts.set_type("application/json");
    let Ok(blob) = web_sys::Blob::new_with_str_sequence_and_options(&blob_parts, &opts) else {
        return;
    };

    let Ok(url) = web_sys::Url::create_object_url_with_blob(&blob) else {
        return;
    };

    let Ok(el) = document.create_element("a") else {
        return;
    };
    let Ok(a) = el.dyn_into::<web_sys::HtmlAnchorElement>() else {
        return;
    };
    a.set_href(&url);
    a.set_download(filename);
    a.click();

    let _ = web_sys::Url::revoke_object_url(&url);
}

#[cfg(not(feature = "web"))]
fn trigger_download(_content: &str, _filename: &str) {
    // Server-side: no-op (downloads only happen in the browser)
}
