use serde::{Serialize, Deserialize};
use std::fmt;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TextStyle {
    pub name: String,
    pub font_name: String,
    pub big_font_name: Option<String>,
    pub height: f64,
    pub width_factor: f64,
    pub oblique_angle: f64,
    pub is_backwards: bool,
    pub is_upside_down: bool,
    pub is_vertical: bool,
    pub color: (u8, u8, u8),
    pub layer: Option<String>,
    pub annotation_scaling: bool,
    pub allow_fixed_height: bool,
    pub is_loaded: bool,
}

impl Default for TextStyle {
    fn default() -> Self {
        Self {
            name: "Standard".to_string(),
            font_name: "Arial".to_string(),
            big_font_name: None,
            height: 2.5,
            width_factor: 1.0,
            oblique_angle: 0.0,
            is_backwards: false,
            is_upside_down: false,
            is_vertical: false,
            color: (0, 0, 0),
            layer: None,
            annotation_scaling: false,
            allow_fixed_height: false,
            is_loaded: true,
        }
    }
}

impl Clone for TextStyle {
    fn clone(&self) -> Self {
        Self {
            name: self.name.clone(),
            font_name: self.font_name.clone(),
            big_font_name: self.big_font_name.clone(),
            height: self.height,
            width_factor: self.width_factor,
            oblique_angle: self.oblique_angle,
            is_backwards: self.is_backwards,
            is_upside_down: self.is_upside_down,
            is_vertical: self.is_vertical,
            color: self.color,
            layer: self.layer.clone(),
            annotation_scaling: self.annotation_scaling,
            allow_fixed_height: self.allow_fixed_height,
            is_loaded: self.is_loaded,
        }
    }
}

impl PartialEq for TextStyle {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
    }
}

impl TextStyle {
    pub fn new(name: impl Into<String>, font_name: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            font_name: font_name.into(),
            ..Default::default()
        }
    }

    pub fn with_height(mut self, height: f64) -> Self {
        self.height = height;
        self
    }

    pub fn with_width_factor(mut self, factor: f64) -> Self {
        self.width_factor = factor;
        self
    }

    pub fn with_oblique_angle(mut self, angle: f64) -> Self {
        self.oblique_angle = angle;
        self
    }

    pub fn set_height(&mut self, height: f64) {
        self.height = height;
    }

    pub fn set_color(&mut self, color: (u8, u8, u8)) {
        self.color = color;
    }

    pub fn set_backwards(&mut self, is_backwards: bool) {
        self.is_backwards = is_backwards;
    }

    pub fn set_upside_down(&mut self, is_upside_down: bool) {
        self.is_upside_down = is_upside_down;
    }

    pub fn set_vertical(&mut self, is_vertical: bool) {
        self.is_vertical = is_vertical;
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FontMetrics {
    pub font_name: String,
    pub baseline_to_baseline: f64,
    pub cap_height: f64,
    pub x_height: f64,
    pub descender_height: f64,
    pub italic_angle: f64,
    pub is_monospaced: bool,
    pub max_character_width: f64,
}

impl Default for FontMetrics {
    fn default() -> Self {
        Self {
            font_name: String::new(),
            baseline_to_baseline: 2.5,
            cap_height: 1.8,
            x_height: 1.3,
            descender_height: 0.5,
            italic_angle: 0.0,
            is_monospaced: false,
            max_character_width: 1.5,
        }
    }
}

impl FontMetrics {
    pub fn new(font_name: impl Into<String>) -> Self {
        Self {
            font_name: font_name.into(),
            ..Default::default()
        }
    }

    pub fn get_char_width(&self, _char: char) -> f64 {
        if self.is_monospaced {
            self.max_character_width
        } else {
            self.max_character_width * 0.6
        }
    }

    pub fn get_text_width(&self, text: &str) -> f64 {
        text.chars()
            .map(|c| self.get_char_width(c))
            .sum()
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TextStyleManager {
    styles: Vec<TextStyle>,
    current_style: Option<String>,
}

impl Default for TextStyleManager {
    fn default() -> Self {
        let mut manager = Self {
            styles: Vec::new(),
            current_style: None,
        };

        manager.add_style(TextStyle::default());
        manager.set_current_style("Standard");

        manager
    }
}

impl TextStyleManager {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn add_style(&mut self, style: TextStyle) -> bool {
        if self.styles.iter().any(|s| s.name == style.name) {
            return false;
        }
        self.styles.push(style);
        true
    }

    pub fn remove_style(&mut self, name: &str) -> bool {
        if name == "Standard" {
            return false;
        }
        let initial_len = self.styles.len();
        self.styles.retain(|s| s.name != name);
        if self.current_style == Some(name.to_string()) {
            self.current_style = Some("Standard".to_string());
        }
        self.styles.len() < initial_len
    }

    pub fn get_style(&self, name: &str) -> Option<&TextStyle> {
        self.styles.iter().find(|s| s.name == name)
    }

    pub fn get_style_mut(&mut self, name: &str) -> Option<&mut TextStyle> {
        self.styles.iter_mut().find(|s| s.name == name)
    }

    pub fn set_current_style(&mut self, name: &str) -> bool {
        if self.styles.iter().any(|s| s.name == name) {
            self.current_style = Some(name.to_string());
            true
        } else {
            false
        }
    }

    pub fn get_current_style(&self) -> Option<&TextStyle> {
        self.current_style
            .as_ref()
            .and_then(|name| self.get_style(name))
    }

    pub fn get_all_styles(&self) -> &[TextStyle] {
        &self.styles
    }

    pub fn get_style_names(&self) -> Vec<&str> {
        self.styles.iter().map(|s| s.name.as_str()).collect()
    }

    pub fn style_exists(&self, name: &str) -> bool {
        self.styles.iter().any(|s| s.name == name)
    }
}

impl fmt::Display for TextStyle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "TextStyle(name=\"{}\", font=\"{}\", height={}, width_factor={})",
            self.name, self.font_name, self.height, self.width_factor
        )
    }
}

impl fmt::Display for TextStyleManager {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "TextStyleManager(styles={}, current=\"{}\")",
            self.styles.len(),
            self.current_style.as_ref().unwrap_or(&"None".to_string())
        )
    }
}

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

    #[test]
    fn test_text_style_creation() {
        let style = TextStyle::new("MyStyle", "Arial")
            .with_height(3.0)
            .with_width_factor(0.8);

        assert_eq!(style.name, "MyStyle");
        assert_eq!(style.font_name, "Arial");
        assert_eq!(style.height, 3.0);
        assert_eq!(style.width_factor, 0.8);
    }

    #[test]
    fn test_text_style_manager() {
        let mut manager = TextStyleManager::new();

        let custom_style = TextStyle::new("Custom", "Verdana")
            .with_height(5.0);

        assert!(manager.add_style(custom_style.clone()));
        assert!(!manager.add_style(custom_style));

        assert!(manager.style_exists("Custom"));
        assert!(manager.set_current_style("Custom"));

        let current = manager.get_current_style().unwrap();
        assert_eq!(current.name, "Custom");
    }
}
