//! Interactive theme builder for customizing TUI appearance

use ratatui::style::Color;
use serde::{Deserialize, Serialize};

/// Color representation for serialization
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum ColorValue {
    /// Black color
    Black,
    /// Red color
    Red,
    /// Green color
    Green,
    /// Yellow color
    Yellow,
    /// Blue color
    Blue,
    /// Magenta color
    Magenta,
    /// Cyan color
    Cyan,
    /// White color
    White,
    /// Dark gray
    DarkGray,
    /// Light red
    LightRed,
    /// Light green
    LightGreen,
    /// Light yellow
    LightYellow,
    /// Light blue
    LightBlue,
    /// Light magenta
    LightMagenta,
    /// Light cyan
    LightCyan,
    /// Light white
    LightWhite,
    /// RGB color (r, g, b)
    Rgb(u8, u8, u8),
}

impl ColorValue {
    /// Convert to ratatui Color
    #[must_use]
    pub const fn to_color(&self) -> Color {
        match self {
            Self::Black => Color::Black,
            Self::Red => Color::Red,
            Self::Green => Color::Green,
            Self::Yellow => Color::Yellow,
            Self::Blue => Color::Blue,
            Self::Magenta => Color::Magenta,
            Self::Cyan => Color::Cyan,
            Self::White | Self::LightWhite => Color::White, // Map to White as LightWhite doesn't exist in ratatui 0.30.0-beta.0
            Self::DarkGray => Color::DarkGray,
            Self::LightRed => Color::LightRed,
            Self::LightGreen => Color::LightGreen,
            Self::LightYellow => Color::LightYellow,
            Self::LightBlue => Color::LightBlue,
            Self::LightMagenta => Color::LightMagenta,
            Self::LightCyan => Color::LightCyan,
            Self::Rgb(r, g, b) => Color::Rgb(*r, *g, *b),
        }
    }

    /// Get color name
    #[must_use]
    pub fn name(&self) -> String {
        match self {
            Self::Black => "Black".to_string(),
            Self::Red => "Red".to_string(),
            Self::Green => "Green".to_string(),
            Self::Yellow => "Yellow".to_string(),
            Self::Blue => "Blue".to_string(),
            Self::Magenta => "Magenta".to_string(),
            Self::Cyan => "Cyan".to_string(),
            Self::White => "White".to_string(),
            Self::DarkGray => "Dark Gray".to_string(),
            Self::LightRed => "Light Red".to_string(),
            Self::LightGreen => "Light Green".to_string(),
            Self::LightYellow => "Light Yellow".to_string(),
            Self::LightBlue => "Light Blue".to_string(),
            Self::LightMagenta => "Light Magenta".to_string(),
            Self::LightCyan => "Light Cyan".to_string(),
            Self::LightWhite => "Light White".to_string(),
            Self::Rgb(r, g, b) => format!("RGB({r},{g},{b})"),
        }
    }
}

/// Theme customization
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ThemeCustomization {
    /// Theme name
    pub name: String,
    /// Primary/selected color
    pub primary: ColorValue,
    /// Success color
    pub success: ColorValue,
    /// Warning color
    pub warning: ColorValue,
    /// Error/critical color
    pub error: ColorValue,
    /// Secondary color
    pub secondary: ColorValue,
    /// Background color
    pub background: ColorValue,
    /// Foreground/text color
    pub foreground: ColorValue,
    /// Dimmed/inactive color
    pub dimmed: ColorValue,
}

impl ThemeCustomization {
    /// Create new theme
    #[must_use]
    pub const fn new(name: String) -> Self {
        Self {
            name,
            primary: ColorValue::Cyan,
            success: ColorValue::Green,
            warning: ColorValue::Yellow,
            error: ColorValue::Red,
            secondary: ColorValue::Blue,
            background: ColorValue::Black,
            foreground: ColorValue::White,
            dimmed: ColorValue::DarkGray,
        }
    }

    /// Create dark theme
    #[must_use]
    pub fn dark() -> Self {
        Self::new("Dark".to_string())
    }

    /// Create light theme
    #[must_use]
    pub fn light() -> Self {
        let mut theme = Self::new("Light".to_string());
        theme.background = ColorValue::White;
        theme.foreground = ColorValue::Black;
        theme.dimmed = ColorValue::LightWhite;
        theme
    }

    /// Get all editable fields as list
    #[must_use]
    pub fn fields(&self) -> Vec<(&str, ColorValue)> {
        vec![
            ("Primary", self.primary),
            ("Success", self.success),
            ("Warning", self.warning),
            ("Error", self.error),
            ("Secondary", self.secondary),
            ("Background", self.background),
            ("Foreground", self.foreground),
            ("Dimmed", self.dimmed),
        ]
    }
}

impl Default for ThemeCustomization {
    fn default() -> Self {
        Self::dark()
    }
}

/// Theme builder for interactive customization
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ThemeBuilder {
    /// Current theme being edited
    theme: ThemeCustomization,
    /// Available colors
    available_colors: Vec<ColorValue>,
    /// Selected field index
    selected_field: usize,
    /// Selected color index
    selected_color: usize,
    /// Whether changes are unsaved
    dirty: bool,
}

impl ThemeBuilder {
    /// Create new theme builder
    #[must_use]
    pub fn new() -> Self {
        Self {
            theme: ThemeCustomization::dark(),
            available_colors: vec![
                ColorValue::Black,
                ColorValue::Red,
                ColorValue::Green,
                ColorValue::Yellow,
                ColorValue::Blue,
                ColorValue::Magenta,
                ColorValue::Cyan,
                ColorValue::White,
                ColorValue::DarkGray,
                ColorValue::LightRed,
                ColorValue::LightGreen,
                ColorValue::LightYellow,
                ColorValue::LightBlue,
                ColorValue::LightMagenta,
                ColorValue::LightCyan,
                ColorValue::LightWhite,
            ],
            selected_field: 0,
            selected_color: 0,
            dirty: false,
        }
    }

    /// Load theme for editing
    pub fn load_theme(&mut self, theme: ThemeCustomization) {
        self.theme = theme;
        self.dirty = false;
    }

    /// Get current theme
    #[must_use]
    pub const fn theme(&self) -> &ThemeCustomization {
        &self.theme
    }

    /// Get mutable theme
    #[must_use]
    pub const fn theme_mut(&mut self) -> &mut ThemeCustomization {
        self.dirty = true;
        &mut self.theme
    }

    /// Get available colors
    #[must_use]
    pub fn available_colors(&self) -> &[ColorValue] {
        &self.available_colors
    }

    /// Get theme fields
    #[must_use]
    pub fn fields(&self) -> Vec<(&str, ColorValue)> {
        self.theme.fields()
    }

    /// Select next field
    pub fn select_next_field(&mut self) {
        self.selected_field = (self.selected_field + 1) % self.fields().len();
        self.selected_color = 0;
    }

    /// Select previous field
    pub fn select_previous_field(&mut self) {
        let len = self.fields().len();
        self.selected_field = if self.selected_field == 0 {
            len - 1
        } else {
            self.selected_field - 1
        };
        self.selected_color = 0;
    }

    /// Select next color
    pub const fn select_next_color(&mut self) {
        self.selected_color = (self.selected_color + 1) % self.available_colors.len();
    }

    /// Select previous color
    pub const fn select_previous_color(&mut self) {
        let len = self.available_colors.len();
        self.selected_color = if self.selected_color == 0 {
            len - 1
        } else {
            self.selected_color - 1
        };
    }

    /// Apply selected color to current field
    pub fn apply_color(&mut self) {
        let color = self.available_colors[self.selected_color];
        let fields = self.fields();

        if self.selected_field < fields.len() {
            match fields[self.selected_field].0 {
                "Primary" => self.theme.primary = color,
                "Success" => self.theme.success = color,
                "Warning" => self.theme.warning = color,
                "Error" => self.theme.error = color,
                "Secondary" => self.theme.secondary = color,
                "Background" => self.theme.background = color,
                "Foreground" => self.theme.foreground = color,
                "Dimmed" => self.theme.dimmed = color,
                _ => {}
            }
            self.dirty = true;
        }
    }

    /// Reset theme to default
    pub fn reset(&mut self) {
        self.theme = ThemeCustomization::dark();
        self.selected_field = 0;
        self.selected_color = 0;
        self.dirty = false;
    }

    /// Check if changes are unsaved
    #[must_use]
    pub const fn is_dirty(&self) -> bool {
        self.dirty
    }

    /// Mark as saved
    pub const fn save(&mut self) {
        self.dirty = false;
    }

    /// Export theme as JSON
    ///
    /// # Errors
    ///
    /// Returns an error if serialization fails
    pub fn export_json(&self) -> Result<String, serde_json::Error> {
        serde_json::to_string_pretty(&self.theme)
    }

    /// Import theme from JSON
    ///
    /// # Errors
    ///
    /// Returns an error if deserialization fails
    pub fn import_json(&mut self, json: &str) -> Result<(), serde_json::Error> {
        self.theme = serde_json::from_str(json)?;
        self.dirty = true;
        Ok(())
    }
}

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

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

    #[test]
    fn test_color_value_name() {
        assert_eq!(ColorValue::Red.name(), "Red");
        assert_eq!(ColorValue::DarkGray.name(), "Dark Gray");
        assert_eq!(ColorValue::Rgb(255, 128, 0).name(), "RGB(255,128,0)");
    }

    #[test]
    fn test_theme_customization_new() {
        let theme = ThemeCustomization::new("Custom".to_string());
        assert_eq!(theme.name, "Custom");
        assert_eq!(theme.primary, ColorValue::Cyan);
    }

    #[test]
    fn test_theme_dark() {
        let theme = ThemeCustomization::dark();
        assert_eq!(theme.background, ColorValue::Black);
        assert_eq!(theme.foreground, ColorValue::White);
    }

    #[test]
    fn test_theme_light() {
        let theme = ThemeCustomization::light();
        assert_eq!(theme.background, ColorValue::White);
        assert_eq!(theme.foreground, ColorValue::Black);
    }

    #[test]
    fn test_theme_fields() {
        let theme = ThemeCustomization::dark();
        let fields = theme.fields();
        assert_eq!(fields.len(), 8);
        assert_eq!(fields[0].0, "Primary");
    }

    #[test]
    fn test_theme_builder_new() {
        let builder = ThemeBuilder::new();
        assert!(!builder.dirty);
        assert_eq!(builder.selected_field, 0);
    }

    #[test]
    fn test_select_next_field() {
        let mut builder = ThemeBuilder::new();
        assert_eq!(builder.selected_field, 0);

        builder.select_next_field();
        assert_eq!(builder.selected_field, 1);
    }

    #[test]
    fn test_select_previous_field() {
        let mut builder = ThemeBuilder::new();
        builder.selected_field = 1;

        builder.select_previous_field();
        assert_eq!(builder.selected_field, 0);
    }

    #[test]
    fn test_select_next_color() {
        let mut builder = ThemeBuilder::new();
        assert_eq!(builder.selected_color, 0);

        builder.select_next_color();
        assert_eq!(builder.selected_color, 1);
    }

    #[test]
    fn test_apply_color() {
        let mut builder = ThemeBuilder::new();
        builder.selected_field = 0; // Primary
        builder.selected_color = 1; // Red

        builder.apply_color();

        assert_eq!(builder.theme.primary, ColorValue::Red);
        assert!(builder.dirty);
    }

    #[test]
    fn test_reset() {
        let mut builder = ThemeBuilder::new();
        builder.theme.primary = ColorValue::Red;
        builder.dirty = true;

        builder.reset();

        assert_eq!(builder.theme.primary, ColorValue::Cyan);
        assert!(!builder.dirty);
    }

    #[test]
    fn test_load_theme() {
        let mut builder = ThemeBuilder::new();
        let custom = ThemeCustomization::light();

        builder.load_theme(custom);

        assert_eq!(builder.theme.name, "Light");
        assert!(!builder.dirty);
    }

    #[test]
    fn test_save() {
        let mut builder = ThemeBuilder::new();
        builder.dirty = true;

        builder.save();

        assert!(!builder.dirty);
    }

    #[test]
    fn test_export_json() {
        let builder = ThemeBuilder::new();
        let json = builder.export_json();

        assert!(json.is_ok());
        assert!(json.unwrap().contains("Dark"));
    }

    #[test]
    fn test_import_json() {
        let mut builder = ThemeBuilder::new();
        let json = r#"{"name":"Test","primary":"Blue","success":"Green","warning":"Yellow","error":"Red","secondary":"Magenta","background":"Black","foreground":"White","dimmed":"DarkGray"}"#;

        assert!(builder.import_json(json).is_ok());
        assert_eq!(builder.theme.name, "Test");
        assert!(builder.dirty);
    }

    #[test]
    fn test_available_colors() {
        let builder = ThemeBuilder::new();
        assert!(builder.available_colors().len() > 10);
    }
}
