//! Server-side shell implementation with proper routing
//!
//! This module provides the SSR shell that uses the server's routing system
//! and renders actual page components instead of just route information.

use leptos::prelude::*;
use rustelo_core_lib::routing::utils::detect_language_from_path;
use rustelo_core_lib::AssetMode;
use rustelo_core_types::rendering::RenderingProfile;

use crate::run::SiteOptions;

/// The SSR shell for Leptos/Axum integration with server-side routing.
///
/// The `profile` parameter selects between the Leptos hydration runtime
/// (default, emits `/pkg/<name>.js` + `<script type="module">`) and the HTMX
/// SSR runtime (emits `/assets/htmx/htmx.min.js` plus declared extensions, no
/// WASM tags).
///
/// `htmx_extensions` is honored only when `profile == HtmxSsr`; each entry must
/// match an `extensions[*].name` from `templates/shared/htmx/htmx.lock.toml`.
pub fn shell_with_path(
    _options: SiteOptions,
    path: Option<String>,
    profile: RenderingProfile,
    htmx_extensions: Vec<String>,
) -> impl IntoView {
    let current_path = path.unwrap_or_default();
    let language = detect_language_from_path(&current_path);

    // Package name only matters for the Leptos hydration profile.
    let package_name =
        std::env::var("LEPTOS_OUTPUT_NAME").unwrap_or_else(|_| "website".to_string());

    // Prepare i18n data for embedding in HTML - load ONLY current language for
    // efficiency
    let (i18n_data_attr, i18n_content, lang_keys) =
        match rustelo_core_lib::fluent::content_loader::load_texts_from_ftl(&language) {
            Ok(texts) => {
                let keys = texts
                    .translations
                    .get(&language)
                    .cloned()
                    .unwrap_or_default();
                match serde_json::to_string(&keys) {
                    Ok(json) => (language.clone(), json, keys),
                    Err(_) => (language.clone(), "{}".to_string(), keys),
                }
            }
            Err(_) => (
                language.clone(),
                "{}".to_string(),
                std::collections::HashMap::new(),
            ),
        };

    // Get page metadata from shared routing system
    let (mut title, description, keywords) = crate::routing::get_page_metadata(&current_path);

    if title.starts_with('[') && title.ends_with(']') {
        let key = title.trim_matches(|c| c == '[' || c == ']');
        title = lang_keys.get(key).cloned().unwrap_or_else(|| title.clone());
    }

    let description = if description.starts_with('[') && description.ends_with(']') {
        let key = description.trim_matches(|c| c == '[' || c == ']');
        lang_keys
            .get(key)
            .cloned()
            .unwrap_or_else(|| description.clone())
    } else {
        description
    };

    let keywords = if keywords.starts_with('[') && keywords.ends_with(']') {
        let key = keywords.trim_matches(|c| c == '[' || c == ']');
        lang_keys
            .get(key)
            .cloned()
            .unwrap_or_else(|| keywords.clone())
    } else {
        keywords
    };

    if title.is_empty() {
        title = crate::utils::site_name();
    }

    let asset_mode = AssetMode::default_for_environment();

    let (css1, css2, css3, css4, css5, css6, css7) = if asset_mode.is_source() {
        (
            "/assets/styles/design-system.css",
            "/assets/styles/theme-default.css",
            "/assets/styles/website.css",
            "/assets/styles/custom.css",
            "/assets/styles/overrides/contact-tailwind-overrides.css",
            "/styles/highlight-github-dark.min.css",
            "/styles/highlightjs-copy.min.css",
        )
    } else {
        (
            "/styles/site.min.css",
            "/styles/app.min.css",
            "/styles/enhancements.min.css",
            "/styles/highlightjs-copy.min.css",
            "",
            "",
            "",
        )
    };

    let css_links = view! {
        <link rel="stylesheet" href={css1} />
        <link rel="stylesheet" href={css2} />
        <link rel="stylesheet" href={css3} />
        {(!css4.is_empty()).then(|| view! { <link rel="stylesheet" href={css4} /> })}
        {(!css5.is_empty()).then(|| view! { <link rel="stylesheet" href={css5} /> })}
        {(!css6.is_empty()).then(|| view! { <link rel="stylesheet" href={css6} /> })}
        {(!css7.is_empty()).then(|| view! { <link rel="stylesheet" href={css7} /> })}
    };

    let (js1, js2, js3, js4) = if asset_mode.is_source() {
        (
            "/js/highlight-bundle.min.js",
            "/assets/scripts/theme-init.js",
            "/assets/scripts/highlight-utils.js",
            "/js/tag-filters.js",
        )
    } else {
        (
            "/js/highlight-bundle.min.js",
            "/js/theme-init.min.js",
            "/js/highlight-utils.min.js",
            "/js/tag-filters.js",
        )
    };

    let js_scripts = view! {
        <script src={js1}></script>
        <script src={js2}></script>
        <script src={js3}></script>
        <script src={js4}></script>
    };

    let is_hydration = matches!(profile, RenderingProfile::LeptosHydration);
    let is_htmx = matches!(profile, RenderingProfile::HtmxSsr);

    // Leptos hydration: WASM module preload + ESM importer.
    let hydration_modulepreload = is_hydration.then(|| {
        view! {
            <link rel="modulepreload" href={format!("/pkg/{}.js", package_name)} />
        }
    });
    let hydration_bootstrap_script = is_hydration.then(|| {
        view! {
            <script id="leptos-hydration">
                {r#"
                globalThis.__RESOLVED_RESOURCES = {};
                globalThis.__INCOMPLETE_CHUNKS = [];
                window.__RESOLVED_RESOURCES = globalThis.__RESOLVED_RESOURCES;
                window.__INCOMPLETE_CHUNKS = globalThis.__INCOMPLETE_CHUNKS;
                "#}
            </script>
        }
    });
    let hydration_module_init = is_hydration.then(|| {
        view! {
            <script type="module">
                {format!(r#"
                import init, {{ hydrate }} from '/pkg/{}.js';
                async function run() {{
                  await init({{ module_or_path: '/pkg/{}.wasm' }});
                  hydrate();
                }}
                run();
                "#, package_name, package_name)}
            </script>
        }
    });

    // HTMX runtime: vendored asset + declared extensions, no WASM at all.
    let htmx_runtime = is_htmx.then(|| {
        view! { <script src="/assets/htmx/htmx.min.js" defer></script> }
    });
    let htmx_ext_scripts = is_htmx.then(|| {
        htmx_extensions
            .iter()
            .map(|name| {
                let src = format!("/assets/htmx/ext/{}.js", name);
                view! { <script src={src} defer></script> }
            })
            .collect_view()
    });
    let htmx_ext_attr = if is_htmx && !htmx_extensions.is_empty() {
        htmx_extensions.join(",")
    } else {
        String::new()
    };
    let body_with_ext = (is_htmx && !htmx_ext_attr.is_empty()).then(|| htmx_ext_attr.clone());

    view! {
      <!DOCTYPE html>
      <html lang={language}>
        <head>
          <meta charset="utf-8"/>
          <meta name="viewport" content="width=device-width, initial-scale=1"/>
          <title inner_html={title.replace("<!>", "")}></title>
          <meta name="description" content={description} />
          <meta name="keywords" content={keywords} />
          {css_links}
          {hydration_modulepreload}
          {htmx_runtime}
          {htmx_ext_scripts}
          {js_scripts}
          <script src="/public/console-logger.js"></script>
        </head>
        <body hx-ext={body_with_ext}>
          <div id="app"></div>
          <div id="htmx-error" class="htmx-error" role="alert" hidden></div>
          <script id="i18n-data" type="application/json" data-lang={i18n_data_attr}>{i18n_content}</script>
          <script id="i18n-config">
            {r#"
            window.__I18N_API__ = "/api/i18n";
            window.__I18N_CURRENT_LANG__ = document.getElementById("i18n-data").getAttribute("data-lang");
            window.__I18N_CACHE__ = {};

            const embeddedData = document.getElementById("i18n-data").textContent;
            if (embeddedData) {
              try {
                window.__I18N_CACHE__[window.__I18N_CURRENT_LANG__] = JSON.parse(embeddedData);
              } catch (e) {
                console.error("Failed to parse embedded i18n data:", e);
              }
            }
            "#}
          </script>
          {hydration_bootstrap_script}
          {hydration_module_init}
        </body>
      </html>
    }
}

/// Legacy single-arg shell, defaults to the Leptos hydration profile.
#[allow(dead_code)]
pub fn shell(options: SiteOptions) -> impl IntoView {
    shell_with_path(options, None, RenderingProfile::LeptosHydration, Vec::new())
}
