/// Color theme and helpers for the Kam CLI.
///
/// Provides a global, lazily-initialized `Theme` that can be overridden
/// via environment variables (useful for global / per-user configuration).
///
/// Supported environment variables (hex `#RRGGBB` or `RRGGBB`):
/// - `KAM_COLOR_ERROR`
/// - `KAM_COLOR_WARN`
/// - `KAM_COLOR_INFO`
/// - `KAM_COLOR_SUCCESS`
///
/// Usage:
/// - Call `kam::colors::get_theme()` to obtain the global theme. Access
///   colors like `get_theme().error`.
use colored::Color;
use std::env;
use std::sync::OnceLock;

/// CLI color theme (semantic colors)
#[derive(Debug, Clone)]
pub struct Theme {
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'error' in 'Theme'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub error: Color,
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'warn' in 'Theme'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub warn: Color,
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'info' in 'Theme'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub info: Color,
    /// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public field 'success' in 'Theme'. Replace with real documentation. (2025-12-30T22:23:21Z)
    pub success: Color,
}

impl Theme {
    // Default is provided by the standard `Default` trait implementation below.

    /// Load theme values from a generic getter (useful for testing).
    /// The provided `get` closure receives an env-style key like `"KAM_COLOR_ERROR"`
    /// and returns an owned `String` when present.
    pub fn load_from_map<F>(mut get: F) -> Self
    where
        F: FnMut(&str) -> Option<String>,
    {
        let mut t = Self::default();

        if let Some(v) = get("KAM_COLOR_ERROR")
            && let Some((r, g, b)) = parse_hex_color(&v)
        {
            t.error = Color::TrueColor { r, g, b };
        }

        if let Some(v) = get("KAM_COLOR_WARN")
            && let Some((r, g, b)) = parse_hex_color(&v)
        {
            t.warn = Color::TrueColor { r, g, b };
        }

        if let Some(v) = get("KAM_COLOR_INFO")
            && let Some((r, g, b)) = parse_hex_color(&v)
        {
            t.info = Color::TrueColor { r, g, b };
        }

        if let Some(v) = get("KAM_COLOR_SUCCESS")
            && let Some((r, g, b)) = parse_hex_color(&v)
        {
            t.success = Color::TrueColor { r, g, b };
        }

        t
    }

    /// Load theme values from environment variables (non-cached).
    ///
    /// This function delegates to `load_from_map` to make testing easier.
    #[must_use]
    pub fn load_from_env() -> Self {
        Self::load_from_map(|k| env::var(k).ok())
    }
}

/// Implement Default trait so callers can use `Theme::default()` idiomatically.
impl Default for Theme {
    fn default() -> Self {
        Self {
            error: Color::TrueColor {
                r: 255,
                g: 145,
                b: 80,
            },
            warn: Color::Yellow,
            info: Color::Cyan,
            success: Color::Green,
        }
    }
}

/// Parse a hex color string like `#RRGGBB` or `RRGGBB`.
fn parse_hex_color(s: &str) -> Option<(u8, u8, u8)> {
    let s = s.trim();
    let s = s.strip_prefix('#').unwrap_or(s);

    if s.len() != 6 {
        return None;
    }

    let r = u8::from_str_radix(&s[0..2], 16).ok()?;
    let g = u8::from_str_radix(&s[2..4], 16).ok()?;
    let b = u8::from_str_radix(&s[4..6], 16).ok()?;
    Some((r, g, b))
}

static THEME: OnceLock<Theme> = OnceLock::new();

/// Obtain the global theme singleton. Environment variables are read once
/// on first access and the result is cached for the process lifetime.
pub fn get_theme() -> &'static Theme {
    THEME.get_or_init(Theme::load_from_env)
}
