//! Pure-Rust HTML rendering for the post sidebar — no Leptos required.
//!
//! Produces the same visual output as the Leptos GraphMini + RelatedContent +
//! OntologyContext components so the HTMX profile has full sidebar parity.
//! Compiled only for non-WASM targets; WASM uses the Leptos components directly.

#[cfg(not(target_arch = "wasm32"))]
use super::generated::{
    mini::GRAPH_MINI_SVGS,
    ontology::ONTOLOGY_CONTEXT,
    related::RELATED_NODES,
};

/// Render the full sidebar for a content post (graph mini-preview + related
/// content + ontology context) as a plain HTML string.
///
/// Returns an empty string when the node has no graph data.
#[cfg(not(target_arch = "wasm32"))]
pub fn render_sidebar(node_id: &str, lang: &str) -> String {
    let mini_html = render_graph_mini(node_id);
    let related_html = render_related(node_id, lang);
    let ontology_html = render_ontology(node_id, lang);

    if mini_html.is_empty() && related_html.is_empty() && ontology_html.is_empty() {
        return String::new();
    }

    format!(
        r#"<aside class="space-y-4 shrink-0">{}{}{}</aside>"#,
        mini_html, related_html, ontology_html
    )
}

#[cfg(not(target_arch = "wasm32"))]
fn render_graph_mini(node_id: &str) -> String {
    let Some(svg) = GRAPH_MINI_SVGS
        .iter()
        .find(|(id, _)| *id == node_id)
        .map(|(_, svg)| *svg)
    else {
        return String::new();
    };

    format!(
        r#"<div class="content-graph-mini-wrapper"><div class="content-graph-mini-preview" aria-label="Knowledge graph preview" role="img">{svg}</div></div>"#
    )
}

#[cfg(not(target_arch = "wasm32"))]
fn render_related(node_id: &str, lang: &str) -> String {
    let related = RELATED_NODES
        .iter()
        .find(|(id, _)| *id == node_id)
        .map(|(_, nodes)| *nodes)
        .unwrap_or(&[]);

    if related.is_empty() {
        return String::new();
    }

    let header = if lang == "es" { "Contenido relacionado" } else { "Related content" };
    let mut items = String::new();
    for node in related {
        let badge_css = kind_badge_css(node.kind);
        let badge_label = kind_label(node.kind);
        let content = if node.url.is_empty() {
            format!(r#"<span class="text-sm ds-text leading-snug">{}</span>"#, esc(node.title))
        } else {
            format!(r#"<a href="{}" class="text-sm ds-text leading-snug hover:underline">{}</a>"#,
                esc_attr(node.url),
                esc(node.title))
        };
        items.push_str(&format!(
            r#"<li class="flex items-start gap-2"><span class="ds-badge text-xs mt-0.5 shrink-0 {badge_css}">{badge_label}</span>{content}</li>"#,
        ));
    }

    format!(
        r#"<aside class="content-graph-related ds-card ds-bg-base-200 p-4 space-y-3"><h3 class="text-sm font-semibold ds-text uppercase tracking-wide opacity-60">{header}</h3><ul class="space-y-2">{items}</ul></aside>"#,
    )
}

#[cfg(not(target_arch = "wasm32"))]
fn render_ontology(node_id: &str, lang: &str) -> String {
    let refs = ONTOLOGY_CONTEXT
        .iter()
        .find(|(id, _)| *id == node_id)
        .map(|(_, refs)| *refs)
        .unwrap_or(&[]);

    if refs.is_empty() {
        return String::new();
    }

    let header = if lang == "es" { "Contexto ontológico" } else { "Ontology context" };
    let mut items = String::new();
    for r in refs {
        let icon = ref_icon(r.kind);
        let css = ref_css(r.kind);
        items.push_str(&format!(
            r#"<li class="flex items-center gap-1 text-xs ds-text"><span class="{css}">{icon}</span><span class="font-mono opacity-80">{}</span><span class="opacity-50">{}</span></li>"#,
            esc(r.id),
            esc(r.name),
        ));
    }

    format!(
        r#"<div class="content-graph-ontology-context mt-6 pt-4 ds-border-t space-y-2"><p class="text-xs font-semibold ds-text uppercase tracking-wide opacity-50">{header}</p><ul class="flex flex-wrap gap-2">{items}</ul></div>"#,
    )
}

#[cfg(not(target_arch = "wasm32"))]
fn kind_label(kind: &str) -> &'static str {
    match kind {
        "Implements" | "ImplementedBy" => "implements",
        "RelatedTo" | "RelatedFrom" => "related",
        "PartOf" | "ParentOf" => "part of",
        "References" | "ReferencedBy" => "references",
        "Extends" | "ExtendedBy" => "extends",
        "ManifestsIn" => "manifests in",
        "Resolves" => "resolves",
        "Complements" => "complements",
        "DependsOn" => "depends on",
        "DocumentedIn" => "documented in",
        _ => "related",
    }
}

#[cfg(not(target_arch = "wasm32"))]
fn kind_badge_css(kind: &str) -> &'static str {
    match kind {
        "Implements" | "ImplementedBy" => "ds-badge-primary",
        "RelatedTo" | "RelatedFrom" => "ds-badge-secondary",
        "PartOf" | "ParentOf" => "ds-badge-accent",
        "References" | "ReferencedBy" => "ds-badge-neutral",
        _ => "ds-badge-ghost",
    }
}

#[cfg(not(target_arch = "wasm32"))]
fn ref_icon(kind: &str) -> &'static str {
    match kind {
        "Implements" | "ImplementedBy" => "◆",
        "ManifestsIn" => "→",
        "Resolves" => "✓",
        "Complements" | "DependsOn" => "~",
        "DocumentedIn" | "References" => "↗",
        _ => "·",
    }
}

#[cfg(not(target_arch = "wasm32"))]
fn ref_css(kind: &str) -> &'static str {
    match kind {
        "Implements" | "ImplementedBy" => "text-violet-500",
        "ManifestsIn" => "text-blue-500",
        "Resolves" => "text-emerald-500",
        _ => "text-amber-500",
    }
}

#[cfg(not(target_arch = "wasm32"))]
fn esc(s: &str) -> String {
    s.replace('&', "&amp;")
        .replace('<', "&lt;")
        .replace('>', "&gt;")
}

#[cfg(not(target_arch = "wasm32"))]
fn esc_attr(s: &str) -> String {
    esc(s).replace('"', "&quot;")
}
