//! Shared theme system
//!
//! This module contains theme-related types and utilities that can be used
//! by both client and SSR systems.

use serde::{Deserialize, Serialize};

/// Theme preference types - shared between client and SSR
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub enum ThemeMode {
    Light,
    Dark,
    #[default]
    System,
}

impl ThemeMode {
    /// Convert ThemeMode to string representation
    pub fn as_str(&self) -> &'static str {
        match self {
            ThemeMode::Light => "light",
            ThemeMode::Dark => "dark",
            ThemeMode::System => "system",
        }
    }

    /// Create ThemeMode from string
    pub fn parse(s: &str) -> Self {
        match s.trim().to_lowercase().as_str() {
            "light" => ThemeMode::Light,
            "dark" => ThemeMode::Dark,
            "system" => ThemeMode::System,
            _ => ThemeMode::System, // Default to system
        }
    }

    /// Get all available theme modes
    pub fn all() -> Vec<ThemeMode> {
        vec![ThemeMode::Light, ThemeMode::Dark, ThemeMode::System]
    }

    /// Check if this theme mode requires system preference detection
    pub fn requires_system_detection(&self) -> bool {
        matches!(self, ThemeMode::System)
    }

    /// Get the effective theme mode given system preference
    pub fn resolve(&self, system_prefers_dark: bool) -> EffectiveTheme {
        match self {
            ThemeMode::Light => EffectiveTheme::Light,
            ThemeMode::Dark => EffectiveTheme::Dark,
            ThemeMode::System => {
                if system_prefers_dark {
                    EffectiveTheme::Dark
                } else {
                    EffectiveTheme::Light
                }
            }
        }
    }
}

impl std::fmt::Display for ThemeMode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

impl std::str::FromStr for ThemeMode {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(ThemeMode::parse(s))
    }
}

/// Effective theme after resolving system preference
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum EffectiveTheme {
    Light,
    Dark,
}

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

    pub fn is_dark(&self) -> bool {
        matches!(self, EffectiveTheme::Dark)
    }

    pub fn is_light(&self) -> bool {
        matches!(self, EffectiveTheme::Light)
    }
}

/// Theme configuration for components
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ThemeConfig {
    pub default_mode: ThemeMode,
    pub allow_system_detection: bool,
    pub persist_preference: bool,
    pub storage_key: String,
}

impl ThemeConfig {
    pub fn new() -> Self {
        Self {
            default_mode: ThemeMode::System,
            allow_system_detection: true,
            persist_preference: true,
            storage_key: "theme".to_string(),
        }
    }

    pub fn with_default_mode(mut self, mode: ThemeMode) -> Self {
        self.default_mode = mode;
        self
    }

    pub fn with_storage_key(mut self, key: &str) -> Self {
        self.storage_key = key.to_string();
        self
    }

    pub fn without_persistence(mut self) -> Self {
        self.persist_preference = false;
        self
    }

    pub fn without_system_detection(mut self) -> Self {
        self.allow_system_detection = false;
        self
    }
}

impl Default for ThemeConfig {
    fn default() -> Self {
        Self::new()
    }
}

/// Theme utilities for color calculations and conversions
pub struct ThemeUtils;

impl ThemeUtils {
    /// Get CSS class for theme mode
    pub fn css_class(theme: EffectiveTheme) -> &'static str {
        match theme {
            EffectiveTheme::Light => "theme-light",
            EffectiveTheme::Dark => "theme-dark",
        }
    }

    /// Get data attribute for theme
    pub fn data_attribute(theme: EffectiveTheme) -> (&'static str, &'static str) {
        ("data-theme", theme.as_str())
    }

    /// Check if theme is considered "high contrast"
    pub fn is_high_contrast(theme: EffectiveTheme) -> bool {
        // For now, only dark theme is considered high contrast
        // This could be expanded to include specific high-contrast variants
        theme.is_dark()
    }

    /// Get recommended text color for theme
    pub fn text_color(theme: EffectiveTheme) -> &'static str {
        match theme {
            EffectiveTheme::Light => "#1a1a1a",
            EffectiveTheme::Dark => "#f5f5f5",
        }
    }

    /// Get recommended background color for theme
    pub fn background_color(theme: EffectiveTheme) -> &'static str {
        match theme {
            EffectiveTheme::Light => "#ffffff",
            EffectiveTheme::Dark => "#0a0a0a",
        }
    }
}

/// Theme transition utilities for smooth theme changes
pub struct ThemeTransition {
    pub duration: String,
    pub timing_function: String,
    pub properties: Vec<String>,
}

impl ThemeTransition {
    pub fn new() -> Self {
        Self {
            duration: "0.2s".to_string(),
            timing_function: "ease-in-out".to_string(),
            properties: vec![
                "background-color".to_string(),
                "color".to_string(),
                "border-color".to_string(),
            ],
        }
    }

    pub fn fast() -> Self {
        Self {
            duration: "0.1s".to_string(),
            ..Self::new()
        }
    }

    pub fn slow() -> Self {
        Self {
            duration: "0.5s".to_string(),
            ..Self::new()
        }
    }

    pub fn to_css(&self) -> String {
        format!(
            "transition: {} {} {};",
            self.properties.join(", "),
            self.duration,
            self.timing_function
        )
    }
}

impl Default for ThemeTransition {
    fn default() -> Self {
        Self::new()
    }
}

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

    #[test]
    fn test_theme_mode_from_str() {
        assert_eq!(ThemeMode::parse("light"), ThemeMode::Light);
        assert_eq!(ThemeMode::parse("DARK"), ThemeMode::Dark);
        assert_eq!(ThemeMode::parse("system"), ThemeMode::System);
        assert_eq!(ThemeMode::parse("invalid"), ThemeMode::System);
        assert_eq!(ThemeMode::parse(""), ThemeMode::System);
    }

    #[test]
    fn test_theme_mode_as_str() {
        assert_eq!(ThemeMode::Light.as_str(), "light");
        assert_eq!(ThemeMode::Dark.as_str(), "dark");
        assert_eq!(ThemeMode::System.as_str(), "system");
    }

    #[test]
    fn test_theme_mode_resolve() {
        assert_eq!(ThemeMode::Light.resolve(false), EffectiveTheme::Light);
        assert_eq!(ThemeMode::Dark.resolve(false), EffectiveTheme::Dark);
        assert_eq!(ThemeMode::System.resolve(true), EffectiveTheme::Dark);
        assert_eq!(ThemeMode::System.resolve(false), EffectiveTheme::Light);
    }

    #[test]
    fn test_effective_theme() {
        assert!(EffectiveTheme::Dark.is_dark());
        assert!(!EffectiveTheme::Light.is_dark());
        assert!(EffectiveTheme::Light.is_light());
        assert!(!EffectiveTheme::Dark.is_light());
    }

    #[test]
    fn test_theme_config() {
        let config = ThemeConfig::new()
            .with_default_mode(ThemeMode::Dark)
            .with_storage_key("custom_theme")
            .without_persistence();

        assert_eq!(config.default_mode, ThemeMode::Dark);
        assert_eq!(config.storage_key, "custom_theme");
        assert!(!config.persist_preference);
        assert!(config.allow_system_detection);
    }

    #[test]
    fn test_theme_utils() {
        assert_eq!(ThemeUtils::css_class(EffectiveTheme::Dark), "theme-dark");
        assert_eq!(ThemeUtils::css_class(EffectiveTheme::Light), "theme-light");

        let (attr, value) = ThemeUtils::data_attribute(EffectiveTheme::Dark);
        assert_eq!(attr, "data-theme");
        assert_eq!(value, "dark");

        assert!(ThemeUtils::is_high_contrast(EffectiveTheme::Dark));
        assert!(!ThemeUtils::is_high_contrast(EffectiveTheme::Light));
    }

    #[test]
    fn test_theme_transition() {
        let transition = ThemeTransition::new();
        let css = transition.to_css();
        assert!(css.contains("background-color"));
        assert!(css.contains("0.2s"));
        assert!(css.contains("ease-in-out"));

        let fast = ThemeTransition::fast();
        assert_eq!(fast.duration, "0.1s");

        let slow = ThemeTransition::slow();
        assert_eq!(slow.duration, "0.5s");
    }

    #[test]
    fn test_theme_mode_display() {
        assert_eq!(format!("{}", ThemeMode::Light), "light");
        assert_eq!(format!("{}", ThemeMode::Dark), "dark");
        assert_eq!(format!("{}", ThemeMode::System), "system");
    }
}
