use super::geometry::Color;
use std::collections::HashMap;

#[derive(Debug, Clone)]
pub struct LayerManager {
    pub layers: HashMap<String, Layer>,
    pub layer_groups: Vec<LayerGroup>,
    pub active_layer: Option<String>,
    pub layer_states: LayerStateManager,
    pub filters: Vec<LayerFilter>,
}

impl LayerManager {
    pub fn new() -> Self {
        let mut manager = Self {
            layers: HashMap::new(),
            layer_groups: Vec::new(),
            active_layer: None,
            layer_states: LayerStateManager::new(),
            filters: Vec::new(),
        };

        manager.add_default_layers();
        manager
    }

    fn add_default_layers(&mut self) {
        let mut layer = Layer::new(String::from("0"));
        layer.color = Color::white();
        layer.is_locked = false;
        layer.is_visible = true;
        layer.is_printable = true;
        self.layers.insert(String::from("0"), layer);
        
        self.active_layer = Some(String::from("0"));

        let mut defpoints = Layer::new(String::from("DEFPOINTS"));
        defpoints.color = Color::white();
        defpoints.description = Some(String::from("Layer for definition points"));
        self.layers.insert(String::from("DEFPOINTS"), defpoints);

        let mut viewport = Layer::new(String::from("VIEWPORT"));
        viewport.color = Color::rgb(255, 255, 0);
        viewport.description = Some(String::from("Viewport layer"));
        self.layers.insert(String::from("VIEWPORT"), viewport);

        let mut construction = Layer::new(String::from("CONSTRUCTION"));
        construction.color = Color::rgb(100, 100, 100);
        construction.description = Some(String::from("Construction geometry"));
        construction.line_type = Some(String::from("CENTER"));
        self.layers.insert(String::from("CONSTRUCTION"), construction);
    }

    pub fn create_layer(&mut self, name: String) -> &mut Layer {
        let layer = Layer::new(name.clone());
        self.layers.insert(name.clone(), layer);
        self.active_layer = Some(name);
        self.layers.get_mut(&name).unwrap()
    }

    pub fn get_layer(&self, name: &str) -> Option<&Layer> {
        self.layers.get(name)
    }

    pub fn get_layer_mut(&mut self, name: &str) -> Option<&mut Layer> {
        self.layers.get_mut(name)
    }

    pub fn delete_layer(&mut self, name: &str) -> bool {
        if name == "0" {
            return false;
        }
        self.layers.remove(name);
        true
    }

    pub fn rename_layer(&mut self, old_name: &str, new_name: &str) -> bool {
        if old_name == "0" || new_name == "0" {
            return false;
        }
        
        if let Some(layer) = self.layers.remove(old_name) {
            layer.name = new_name.clone();
            self.layers.insert(new_name.clone(), layer);
            true
        } else {
            false
        }
    }

    pub fn set_active_layer(&mut self, name: &str) -> bool {
        if self.layers.contains_key(name) {
            self.active_layer = Some(name.to_string());
            true
        } else {
            false
        }
    }

    pub fn get_active_layer(&self) -> Option<&Layer> {
        self.active_layer.as_ref().and_then(|name| self.layers.get(name))
    }

    pub fn get_active_layer_mut(&mut self) -> Option<&mut Layer> {
        self.active_layer.as_ref().and_then(|name| self.layers.get_mut(name))
    }

    pub fn create_layer_group(&mut self, name: String, description: String) -> &mut LayerGroup {
        let group = LayerGroup::new(name, description);
        self.layer_groups.push(group);
        self.layer_groups.last_mut().unwrap()
    }

    pub fn add_layer_to_group(&mut self, layer_name: &str, group_name: &str) -> bool {
        if let Some(group) = self.layer_groups.iter_mut().find(|g| g.name == group_name) {
            if self.layers.contains_key(layer_name) {
                group.layer_names.push(layer_name.to_string());
                true
            } else {
                false
            }
        } else {
            false
        }
    }

    pub fn remove_layer_from_group(&mut self, layer_name: &str, group_name: &str) -> bool {
        if let Some(group) = self.layer_groups.iter_mut().find(|g| g.name == group_name) {
            let original_len = group.layer_names.len();
            group.layer_names.retain(|n| n != layer_name);
            group.layer_names.len() < original_len
        } else {
            false
        }
    }

    pub fn get_group(&self, name: &str) -> Option<&LayerGroup> {
        self.layer_groups.iter().find(|g| g.name == name)
    }

    pub fn apply_filter(&self, filter: &LayerFilter) -> Vec<&Layer> {
        self.layers.values()
            .filter(|layer| filter.matches(layer))
            .collect()
    }

    pub fn create_filter(&mut self, name: String, criteria: FilterCriteria) -> &mut LayerFilter {
        let filter = LayerFilter::new(name, criteria);
        self.filters.push(filter);
        self.filters.last_mut().unwrap()
    }

    pub fn save_state(&mut self, state_name: String) {
        self.layer_states.save_state(state_name, &self.layers);
    }

    pub fn restore_state(&mut self, state_name: &str) -> bool {
        if let Some(saved_layers) = self.layer_states.get_state(state_name) {
            for (name, saved_layer) in saved_layers {
                if let Some(layer) = self.layers.get_mut(name) {
                    layer.is_visible = saved_layer.is_visible;
                    layer.is_locked = saved_layer.is_locked;
                    layer.is_printable = saved_layer.is_printable;
                    layer.color = saved_layer.color;
                    layer.line_weight = saved_layer.line_weight;
                    layer.line_type = saved_layer.line_type.clone();
                }
            }
            true
        } else {
            false
        }
    }

    pub fn available_states(&self) -> Vec<&String> {
        self.layer_states.available_states()
    }

    pub fn all_layers(&self) -> Vec<&Layer> {
        self.layers.values().collect()
    }

    pub fn visible_layers(&self) -> Vec<&Layer> {
        self.layers.values()
            .filter(|l| l.is_visible)
            .collect()
    }

    pub fn locked_layers(&self) -> Vec<&Layer> {
        self.layers.values()
            .filter(|l| l.is_locked)
            .collect()
    }

    pub fn printable_layers(&self) -> Vec<&Layer> {
        self.layers.values()
            .filter(|l| l.is_printable)
            .collect()
    }

    pub fn freeze_all(&mut self) {
        for layer in self.layers.values_mut() {
            if layer.name != "0" {
                layer.is_visible = false;
                layer.is_frozen = true;
            }
        }
    }

    pub fn thaw_all(&mut self) {
        for layer in self.layers.values_mut() {
            layer.is_frozen = false;
        }
    }

    pub fn lock_all(&mut self) {
        for layer in self.layers.values_mut() {
            if layer.name != "0" {
                layer.is_locked = true;
            }
        }
    }

    pub fn unlock_all(&mut self) {
        for layer in self.layers.values_mut() {
            layer.is_locked = false;
        }
    }
}

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

#[derive(Debug, Clone)]
pub struct Layer {
    pub name: String,
    pub color: Color,
    pub line_type: Option<String>,
    pub line_weight: f64,
    pub is_visible: bool,
    pub is_locked: bool,
    pub is_printable: bool,
    pub is_frozen: bool,
    pub plot_style: Option<PlotStyle>,
    pub description: Option<String>,
    pub extended_properties: HashMap<String, LayerProperty>,
}

impl Layer {
    pub fn new(name: String) -> Self {
        Self {
            name,
            color: Color::rgb(255, 255, 255),
            line_type: None,
            line_weight: -1.0,
            is_visible: true,
            is_locked: false,
            is_printable: true,
            is_frozen: false,
            plot_style: None,
            description: None,
            extended_properties: HashMap::new(),
        }
    }

    pub fn with_color(mut self, color: Color) -> Self {
        self.color = color;
        self
    }

    pub fn with_line_type(mut self, line_type: String) -> Self {
        self.line_type = Some(line_type);
        self
    }

    pub fn with_line_weight(mut self, weight: f64) -> Self {
        self.line_weight = weight;
        self
    }

    pub fn with_description(mut self, description: String) -> Self {
        self.description = Some(description);
        self
    }

    pub fn with_plot_style(mut self, plot_style: PlotStyle) -> Self {
        self.plot_style = Some(plot_style);
        self
    }

    pub fn add_property(mut self, name: String, property: LayerProperty) -> Self {
        self.extended_properties.insert(name, property);
        self
    }

    pub fn is_editable(&self) -> bool {
        !self.is_locked && self.is_visible && !self.is_frozen
    }
}

#[derive(Debug, Clone)]
pub struct PlotStyle {
    pub name: String,
    pub color: Option<Color>,
    pub screen: u8,
    pub screen_pattern: ScreenPattern,
    pub linetype_scale: f64,
    pub adaptive_linetype: bool,
    pub lineweight: Option<f64>,
    pub end_style: LineEndStyle,
    pub join_style: LineJoinStyle,
    pub fill_style: FillStyle,
}

impl PlotStyle {
    pub fn new(name: String) -> Self {
        Self {
            name,
            color: None,
            screen: 100,
            screen_pattern: ScreenPattern::Solid,
            linetype_scale: 1.0,
            adaptive_linetype: true,
            lineweight: None,
            end_style: LineEndStyle::Round,
            join_style: LineJoinStyle::Round,
            fill_style: FillStyle::Solid,
        }
    }

    pub fn with_color(mut self, color: Color) -> Self {
        self.color = Some(color);
        self
    }

    pub fn with_screen(mut self, screen: u8) -> Self {
        self.screen = screen.clamp(0, 100);
        self
    }

    pub fn with_linetype_scale(mut self, scale: f64) -> Self {
        self.linetype_scale = scale;
        self
    }

    pub fn with_lineweight(mut self, weight: f64) -> Self {
        self.lineweight = Some(weight);
        self
    }

    pub fn with_end_style(mut self, style: LineEndStyle) -> Self {
        self.end_style = style;
        self
    }

    pub fn with_join_style(mut self, style: LineJoinStyle) -> Self {
        self.join_style = style;
        self
    }

    pub fn with_fill_style(mut self, style: FillStyle) -> Self {
        self.fill_style = style;
        self
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ScreenPattern {
    Solid,
    Crosshatch,
    Diagonal,
    Horizontal,
    Vertical,
    Grid,
    Dots,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineEndStyle {
    Butt,
    Round,
    Square,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineJoinStyle {
    Miter,
    Round,
    Bevel,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FillStyle {
    Solid,
    Hatch,
    OutlinedHatch,
    Background,
}

#[derive(Debug, Clone)]
pub enum LayerProperty {
    String(String),
    Number(f64),
    Boolean(bool),
    Color(Color),
    ColorIndex(u16),
}

#[derive(Debug, Clone)]
pub struct LayerGroup {
    pub name: String,
    pub description: String,
    pub layer_names: Vec<String>,
    pub is_expanded: bool,
}

impl LayerGroup {
    pub fn new(name: String, description: String) -> Self {
        Self {
            name,
            description,
            layer_names: Vec::new(),
            is_expanded: true,
        }
    }

    pub fn add_layer(mut self, layer_name: String) -> Self {
        self.layer_names.push(layer_name);
        self
    }

    pub fn toggle_expand(&mut self) {
        self.is_expanded = !self.is_expanded;
    }

    pub fn get_layers(&self, layer_manager: &LayerManager) -> Vec<&Layer> {
        self.layer_names.iter()
            .filter_map(|name| layer_manager.get_layer(name))
            .collect()
    }
}

#[derive(Debug, Clone)]
pub struct LayerFilter {
    pub name: String,
    pub criteria: FilterCriteria,
    pub is_group_filter: bool,
    pub nested_filters: Vec<LayerFilter>,
}

impl LayerFilter {
    pub fn new(name: String, criteria: FilterCriteria) -> Self {
        Self {
            name,
            criteria,
            is_group_filter: false,
            nested_filters: Vec::new(),
        }
    }

    pub fn as_group_filter(mut self) -> Self {
        self.is_group_filter = true;
        self
    }

    pub fn add_nested_filter(mut self, filter: LayerFilter) -> Self {
        self.nested_filters.push(filter);
        self
    }

    pub fn matches(&self, layer: &Layer) -> bool {
        if self.is_group_filter {
            self.nested_filters.iter()
                .any(|f| f.matches(layer))
        } else {
            self.criteria.matches(layer)
        }
    }
}

#[derive(Debug, Clone)]
pub struct FilterCriteria {
    pub name_pattern: Option<NamePattern>,
    pub color_filter: Option<ColorFilter>,
    pub visibility_filter: Option<VisibilityFilter>,
    pub lock_filter: Option<LockFilter>,
    pub plot_filter: Option<PlotFilter>,
    pub line_type_filter: Option<LineTypeFilter>,
    pub description_pattern: Option<DescriptionPattern>,
    pub custom_property_filters: Vec<CustomPropertyFilter>,
    pub combination_operator: CombinationOperator,
}

impl FilterCriteria {
    pub fn new() -> Self {
        Self {
            name_pattern: None,
            color_filter: None,
            visibility_filter: None,
            lock_filter: None,
            plot_filter: None,
            line_type_filter: None,
            description_pattern: None,
            custom_property_filters: Vec::new(),
            combination_operator: CombinationOperator::And,
        }
    }

    pub fn with_name_pattern(mut self, pattern: NamePattern) -> Self {
        self.name_pattern = Some(pattern);
        self
    }

    pub fn with_color(mut self, color: Color, match_type: ColorMatchType) -> Self {
        self.color_filter = Some(ColorFilter { color, match_type });
        self
    }

    pub fn with_visibility(mut self, visible: bool) -> Self {
        self.visibility_filter = Some(VisibilityFilter { visible });
        self
    }

    pub fn with_locked(mut self, locked: bool) -> Self {
        self.lock_filter = Some(LockFilter { locked });
        self
    }

    pub fn with_printable(mut self, printable: bool) -> Self {
        self.plot_filter = Some(PlotFilter { printable });
        self
    }

    pub fn with_line_type(mut self, line_type: String) -> Self {
        self.line_type_filter = Some(LineTypeFilter { line_type });
        self
    }

    pub fn with_description_pattern(mut self, pattern: DescriptionPattern) -> Self {
        self.description_pattern = Some(pattern);
        self
    }

    pub fn with_custom_property(
        mut self,
        name: String,
        value: LayerProperty,
        match_type: PropertyMatchType,
    ) -> Self {
        self.custom_property_filters.push(CustomPropertyFilter {
            name,
            value,
            match_type,
        });
        self
    }

    pub fn with_or_operator(mut self) -> Self {
        self.combination_operator = CombinationOperator::Or;
        self
    }

    pub fn matches(&self, layer: &Layer) -> bool {
        match self.combination_operator {
            CombinationOperator::And => {
                let mut all_match = true;
                
                if let Some(ref pattern) = self.name_pattern {
                    all_match &= pattern.matches(&layer.name);
                }
                if let Some(ref filter) = self.color_filter {
                    all_match &= filter.matches(&layer.color);
                }
                if let Some(ref filter) = self.visibility_filter {
                    all_match &= filter.matches(layer.is_visible);
                }
                if let Some(ref filter) = self.lock_filter {
                    all_match &= filter.matches(layer.is_locked);
                }
                if let Some(ref filter) = self.plot_filter {
                    all_match &= filter.matches(layer.is_printable);
                }
                if let Some(ref filter) = self.line_type_filter {
                    all_match &= filter.matches(layer.line_type.as_ref());
                }
                if let Some(ref pattern) = self.description_pattern {
                    all_match &= pattern.matches(layer.description.as_ref());
                }
                
                all_match
            }
            CombinationOperator::Or => {
                let mut any_match = false;
                
                if let Some(ref pattern) = self.name_pattern {
                    any_match |= pattern.matches(&layer.name);
                }
                if let Some(ref filter) = self.color_filter {
                    any_match |= filter.matches(&layer.color);
                }
                if let Some(ref filter) = self.visibility_filter {
                    any_match |= filter.matches(layer.is_visible);
                }
                if let Some(ref filter) = self.lock_filter {
                    any_match |= filter.matches(layer.is_locked);
                }
                if let Some(ref filter) = self.plot_filter {
                    any_match |= filter.matches(layer.is_printable);
                }
                if let Some(ref filter) = self.line_type_filter {
                    any_match |= filter.matches(layer.line_type.as_ref());
                }
                if let Some(ref pattern) = self.description_pattern {
                    any_match |= pattern.matches(layer.description.as_ref());
                }
                
                any_match
            }
        }
    }
}

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

#[derive(Debug, Clone)]
pub struct NamePattern {
    pub pattern: String,
    pub use_wildcards: bool,
    pub case_sensitive: bool,
}

impl NamePattern {
    pub fn new(pattern: String) -> Self {
        Self {
            pattern,
            use_wildcards: true,
            case_sensitive: false,
        }
    }

    pub fn matches(&self, name: &str) -> bool {
        if self.use_wildcards {
            wildcard_match(&self.pattern, name, self.case_sensitive)
        } else {
            if self.case_sensitive {
                name.contains(&self.pattern)
            } else {
                name.to_lowercase().contains(&self.pattern.to_lowercase())
            }
        }
    }
}

#[derive(Debug, Clone)]
pub struct ColorFilter {
    pub color: Color,
    pub match_type: ColorMatchType,
}

impl ColorFilter {
    pub fn matches(&self, layer_color: &Color) -> bool {
        match self.match_type {
            ColorMatchType::Exact => {
                (self.color.r - layer_color.r).abs() < 0.01 &&
                (self.color.g - layer_color.g).abs() < 0.01 &&
                (self.color.b - layer_color.b).abs() < 0.01
            }
            ColorMatchType::Similar => {
                (self.color.r - layer_color.r).abs() < 0.1 &&
                (self.color.g - layer_color.g).abs() < 0.1 &&
                (self.color.b - layer_color.b).abs() < 0.1
            }
            ColorMatchType::HueMatch => {
                let self_hsv = rgb_to_hsv(self.color.r, self.color.g, self.color.b);
                let layer_hsv = rgb_to_hsv(layer_color.r, layer_color.g, layer_color.b);
                (self_hsv.0 - layer_hsv.0).abs() < 10.0
            }
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ColorMatchType {
    Exact,
    Similar,
    HueMatch,
}

#[derive(Debug, Clone)]
pub struct VisibilityFilter {
    pub visible: bool,
}

impl VisibilityFilter {
    pub fn matches(&self, is_visible: bool) -> bool {
        self.visible == is_visible
    }
}

#[derive(Debug, Clone)]
pub struct LockFilter {
    pub locked: bool,
}

impl LockFilter {
    pub fn matches(&self, is_locked: bool) -> bool {
        self.locked == is_locked
    }
}

#[derive(Debug, Clone)]
pub struct PlotFilter {
    pub printable: bool,
}

impl PlotFilter {
    pub fn matches(&self, is_printable: bool) -> bool {
        self.printable == is_printable
    }
}

#[derive(Debug, Clone)]
pub struct LineTypeFilter {
    pub line_type: String,
}

impl LineTypeFilter {
    pub fn matches(&self, layer_line_type: Option<&String>) -> bool {
        match layer_line_type {
            Some(lt) => lt.to_lowercase() == self.line_type.to_lowercase(),
            None => self.line_type.is_empty(),
        }
    }
}

#[derive(Debug, Clone)]
pub struct DescriptionPattern {
    pub pattern: String,
    pub case_sensitive: bool,
}

impl DescriptionPattern {
    pub fn matches(&self, description: Option<&String>) -> bool {
        match description {
            Some(desc) => {
                if self.case_sensitive {
                    desc.contains(&self.pattern)
                } else {
                    desc.to_lowercase().contains(&self.pattern.to_lowercase())
                }
            }
            None => self.pattern.is_empty(),
        }
    }
}

#[derive(Debug, Clone)]
pub struct CustomPropertyFilter {
    pub name: String,
    pub value: LayerProperty,
    pub match_type: PropertyMatchType,
}

impl CustomPropertyFilter {
    pub fn matches(&self, properties: &HashMap<String, LayerProperty>) -> bool {
        if let Some(prop) = properties.get(&self.name) {
            match (prop, &self.value) {
                (LayerProperty::String(s1), LayerProperty::String(s2)) => {
                    s1 == s2
                }
                (LayerProperty::Number(n1), LayerProperty::Number(n2)) => {
                    (n1 - n2).abs() < 0.001
                }
                (LayerProperty::Boolean(b1), LayerProperty::Boolean(b2)) => {
                    b1 == b2
                }
                (LayerProperty::Color(c1), LayerProperty::Color(c2)) => {
                    (c1.r - c2.r).abs() < 0.01 &&
                    (c1.g - c2.g).abs() < 0.01 &&
                    (c1.b - c2.b).abs() < 0.01
                }
                (LayerProperty::ColorIndex(i1), LayerProperty::ColorIndex(i2)) => {
                    i1 == i2
                }
                _ => false,
            }
        } else {
            false
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PropertyMatchType {
    Exact,
    Contains,
    StartsWith,
    EndsWith,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CombinationOperator {
    And,
    Or,
}

#[derive(Debug, Clone)]
pub struct LayerStateManager {
    states: HashMap<String, HashMap<String, Layer>>,
}

impl LayerStateManager {
    pub fn new() -> Self {
        Self {
            states: HashMap::new(),
        }
    }

    pub fn save_state(&mut self, state_name: String, layers: &HashMap<String, Layer>) {
        let mut state = HashMap::new();
        for (name, layer) in layers {
            state.insert(name.clone(), layer.clone());
        }
        self.states.insert(state_name, state);
    }

    pub fn get_state(&self, state_name: &str) -> Option<&HashMap<String, Layer>> {
        self.states.get(state_name)
    }

    pub fn delete_state(&mut self, state_name: &str) -> bool {
        self.states.remove(state_name).is_some()
    }

    pub fn available_states(&self) -> Vec<&String> {
        self.states.keys().collect()
    }

    pub fn rename_state(&mut self, old_name: &str, new_name: String) -> bool {
        if let Some(state) = self.states.remove(old_name) {
            self.states.insert(new_name, state);
            true
        } else {
            false
        }
    }
}

fn wildcard_match(pattern: &str, text: &str, case_sensitive: bool) -> bool {
    let text = if case_sensitive { text.to_string() } else { text.to_lowercase() };
    let pattern = if case_sensitive { pattern.to_string() } else { pattern.to_lowercase() };
    
    let mut pattern_chars = pattern.chars().collect::<Vec<_>>();
    let mut text_chars = text.chars().collect::<Vec<_>>();
    
    let mut dp = vec![vec![false; text_chars.len() + 1]; pattern_chars.len() + 1];
    dp[0][0] = true;
    
    for i in 1..=pattern_chars.len() {
        if pattern_chars[i-1] == '*' {
            dp[i][0] = dp[i-1][0];
        }
    }
    
    for i in 1..=pattern_chars.len() {
        for j in 1..=text_chars.len() {
            match pattern_chars[i-1] {
                '*' => {
                    dp[i][j] = dp[i-1][j] || dp[i][j-1];
                }
                '?' => {
                    dp[i][j] = dp[i-1][j-1];
                }
                _ => {
                    dp[i][j] = dp[i-1][j-1] && pattern_chars[i-1] == text_chars[j-1];
                }
            }
        }
    }
    
    dp[pattern_chars.len()][text_chars.len()]
}

fn rgb_to_hsv(r: f64, g: f64, b: f64) -> (f64, f64, f64) {
    let max = r.max(g).max(b);
    let min = r.min(g).min(b);
    let delta = max - min;
    
    let h = if delta < 0.001 {
        0.0
    } else if max == r {
        60.0 * (((g - b) / delta) % 6.0)
    } else if max == g {
        60.0 * (((b - r) / delta) + 2.0)
    } else {
        60.0 * (((r - g) / delta) + 4.0)
    };
    
    let s = if max < 0.001 { 0.0 } else { delta / max };
    let v = max;
    
    (h, s * 100.0, v * 100.0)
}
