//! Theme toggle button. Posts to `/api/htmx/theme/toggle`.

/// Theme value, kept lowercase to match `<html class>` conventions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Theme {
    Light,
    Dark,
}

impl Theme {
    pub fn as_str(self) -> &'static str {
        match self {
            Theme::Light => "light",
            Theme::Dark => "dark",
        }
    }
}

/// Render the theme toggle button. `current` controls which icon shows.
pub fn render_theme_toggle(current: Theme) -> String {
    let label = match current {
        Theme::Light => "Switch to dark theme",
        Theme::Dark => "Switch to light theme",
    };
    let ctx = minijinja::context! {
        theme => current.as_str(),
        label => label,
    };
    rustelo_pages_htmx::fragment_env()
        .and_then(|env| {
            env.get_template("partials/nav/theme_toggle.j2")
                .and_then(|t| t.render(ctx))
                .ok()
        })
        .unwrap_or_else(|| fallback_theme_button(current, label))
}

fn fallback_theme_button(current: Theme, label: &str) -> String {
    format!(
        r##"<button type="button" class="ds-btn-ghost-sm" hx-post="/api/htmx/theme/toggle" hx-swap="outerHTML" hx-target="this" hx-ext="multi-swap" data-theme="{theme}" aria-label="{label}">{icon}</button>"##,
        theme = current.as_str(),
        label = html_escape::encode_double_quoted_attribute(label),
        icon = theme_icon(current),
    )
}

fn theme_icon(theme: Theme) -> &'static str {
    match theme {
        Theme::Light => {
            r#"<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path></svg>"#
        }
        Theme::Dark => {
            r#"<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>"#
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn emits_post_to_toggle_endpoint() {
        let html = render_theme_toggle(Theme::Light);
        assert!(html.contains(r#"hx-post="/api/htmx/theme/toggle""#));
    }

    #[test]
    fn carries_current_theme_data_attribute() {
        let html = render_theme_toggle(Theme::Dark);
        assert!(html.contains(r#"data-theme="dark""#));
    }

    #[test]
    fn uses_multi_swap_extension() {
        let html = render_theme_toggle(Theme::Light);
        assert!(html.contains(r#"hx-ext="multi-swap""#));
    }
}
