use crate::geometry::{Point, Vector2, Line, Arc, Polyline};
use crate::data_structure::{Entity, EntityType, EntityGeometry, TextStyle};
use crate::geometric_tolerance::GeometricTolerance;
use serde::{Serialize, Deserialize};
use std::fmt;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Leader {
    pub start_point: Point,
    pub landing: LeaderLanding,
    pub content: LeaderContent,
    pub style: LeaderStyle,
    pub annotation: Option<Annotation>,
    pub is_mleader: bool,
    pub dogleg: DoglegSettings,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LeaderLanding {
    pub landing_point: Point,
    pub landing_length: f64,
    pub has_landing: bool,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum LeaderContent {
    None,
    Text(TextContent),
    Block(BlockContent),
    Tolerance(GeometricTolerance),
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TextContent {
    pub text: String,
    pub style: TextStyle,
    pub width_factor: f64,
    pub is_mtext: bool,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BlockContent {
    pub block_name: String,
    pub scale: f64,
    pub rotation: f64,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LeaderStyle {
    pub id: String,
    pub name: String,
    pub arrow_size: f64,
    pub arrow_style: LeaderArrowStyle,
    pub leader_line_type: LeaderLineType,
    pub leader_line_weight: f64,
    pub landing_gap: f64,
    pub landing_distance: f64,
    pub text_height: f64,
    pub text_style: TextStyle,
    pub first_segment_angle: f64,
    pub second_segment_angle: f64,
    pub dogleg_length: f64,
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum LeaderArrowStyle {
    Closed,
    ClosedFilled,
    Dot,
    DotSmall,
    Open,
    Origin,
    Origin02,
    Oblique,
    Box,
    BoxFilled,
    Circle,
    CircleFilled,
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum LeaderLineType {
    Straight,
    Splined,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct DoglegSettings {
    pub enabled: bool,
    pub direction: DoglegDirection,
    pub length: f64,
    pub first_segment_angle: f64,
    pub second_segment_angle: f64,
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum DoglegDirection {
    Left,
    Right,
    Automatic,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Annotation {
    pub content: AnnotationContent,
    pub position: Point,
    pub attachment_point: AnnotationAttachment,
    pub text_direction: TextDirection,
    pub line_rotation: f64,
    pub dogleg_position: Point,
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum AnnotationAttachment {
    TopLeft,
    TopCenter,
    TopRight,
    MiddleLeft,
    MiddleCenter,
    MiddleRight,
    BottomLeft,
    BottomCenter,
    BottomRight,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum AnnotationContent {
    Text(String),
    MText(String),
    Block(String, f64),
    Tolerance,
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum TextDirection {
    LeftToRight,
    RightToLeft,
}

impl Default for LeaderStyle {
    fn default() -> Self {
        Self {
            id: "Standard".to_string(),
            name: "Standard".to_string(),
            arrow_size: 2.5,
            arrow_style: LeaderArrowStyle::ClosedFilled,
            leader_line_type: LeaderLineType::Straight,
            leader_line_weight: 0.0,
            landing_gap: 0.625,
            landing_distance: 6.35,
            text_height: 2.5,
            text_style: TextStyle::default(),
            first_segment_angle: 0.0,
            second_segment_angle: 90.0,
            dogleg_length: 6.35,
        }
    }
}

impl Default for LeaderLanding {
    fn default() -> Self {
        Self {
            landing_point: Point::origin(),
            landing_length: 6.35,
            has_landing: true,
        }
    }
}

impl Default for TextContent {
    fn default() -> Self {
        Self {
            text: String::new(),
            style: TextStyle::default(),
            width_factor: 1.0,
            is_mtext: false,
        }
    }
}

impl Leader {
    pub fn new(start_point: Point, content: LeaderContent, style: LeaderStyle) -> Self {
        let dogleg_length = style.dogleg_length;
        let first_segment_angle = style.first_segment_angle;
        let second_segment_angle = style.second_segment_angle;
        
        Self {
            start_point,
            landing: LeaderLanding::default(),
            content,
            style,
            annotation: None,
            is_mleader: false,
            dogleg: DoglegSettings {
                enabled: true,
                direction: DoglegDirection::Automatic,
                length: dogleg_length,
                first_segment_angle,
                second_segment_angle,
            },
        }
    }
    
    pub fn add_segment(&mut self, point: Point) {
        match &mut self.content {
            LeaderContent::Text(text_content) => {
                text_content.text.push('\n');
                text_content.text.push_str(&format!("-> ({:.1}, {:.1})", point.x, point.y));
            }
            _ => {}
        }
    }
    
    pub fn set_landing(&mut self, landing_point: Point) {
        self.landing.landing_point = landing_point;
        self.landing.has_landing = true;
    }
    
    pub fn remove_landing(&mut self) {
        self.landing.has_landing = false;
    }
    
    pub fn flip_dogleg(&mut self) {
        self.dogleg.direction = match self.dogleg.direction {
            DoglegDirection::Left => DoglegDirection::Right,
            DoglegDirection::Right => DoglegDirection::Left,
            DoglegDirection::Automatic => DoglegDirection::Left,
        };
    }
    
    pub fn set_annotation(&mut self, annotation: Annotation) {
        self.annotation = Some(annotation);
    }
    
    pub fn to_entity(&self) -> Entity {
        let text = match &self.content {
            LeaderContent::Text(text_content) => text_content.text.clone(),
            LeaderContent::Block(block_content) => block_content.block_name.clone(),
            LeaderContent::Tolerance(_) => "Tolerance".to_string(),
            LeaderContent::None => String::new(),
        };
        Entity::new(
            EntityType::Dimension,
            EntityGeometry::Dimension {
                dim_type: crate::data_structure::DimensionType::Linear,
                measurement: 0.0,
                text,
                text_position: self.landing.landing_point,
                text_height: self.style.text_height,
                text_rotation: 0.0,
                definition_point: self.start_point,
                def_point_1: self.landing.landing_point,
                def_point_2: Point::origin(),
                def_point_3: Point::origin(),
                def_point_4: Point::origin(),
                angle: 0.0,
                extension_lines: false,
                center_marks: false,
            },
        )
    }
}

impl From<Leader> for Entity {
    fn from(leader: Leader) -> Self {
        leader.to_entity()
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MultiLeader {
    pub leaders: Vec<Leader>,
    pub common_content: LeaderContent,
    pub style: LeaderStyle,
    pub overall_scale: f64,
    pub landing_alignment: LandingAlignment,
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum LandingAlignment {
    AlignAll,
    AlignFirst,
    Distribute,
}

impl MultiLeader {
    pub fn new(style: LeaderStyle, content: LeaderContent) -> Self {
        Self {
            leaders: Vec::new(),
            common_content: content,
            style,
            overall_scale: 1.0,
            landing_alignment: LandingAlignment::AlignAll,
        }
    }
    
    pub fn add_leader(&mut self, start_point: Point) -> &mut Leader {
        let leader = Leader::new(start_point, self.common_content.clone(), self.style.clone());
        self.leaders.push(leader);
        self.leaders.last_mut().unwrap()
    }
    
    pub fn remove_leader(&mut self, index: usize) -> bool {
        if index < self.leaders.len() {
            self.leaders.remove(index);
            true
        } else {
            false
        }
    }
    
    pub fn set_overall_scale(&mut self, scale: f64) {
        self.overall_scale = scale;
        for leader in &mut self.leaders {
            leader.style.arrow_size *= scale;
            leader.style.landing_gap *= scale;
            leader.style.landing_distance *= scale;
            leader.style.text_height *= scale;
            leader.style.dogleg_length *= scale;
        }
    }
    
    pub fn align_landings(&mut self) {
        if self.leaders.is_empty() {
            return;
        }
        
        match self.landing_alignment {
            LandingAlignment::AlignFirst => {
                let first_landing = self.leaders[0].landing.landing_point;
                for leader in &mut self.leaders[1..] {
                    leader.landing.landing_point = first_landing;
                }
            }
            LandingAlignment::Distribute => {
                let min_y = self.leaders.iter()
                    .filter_map(|l| Some(l.landing.landing_point.y))
                    .fold(f64::MAX, f64::min);
                
                for leader in &mut self.leaders {
                    leader.landing.landing_point.y = min_y;
                }
            }
            _ => {}
        }
    }
    
    pub fn to_entities(&self) -> Vec<Entity> {
        self.leaders.iter()
            .map(|l| l.to_entity())
            .collect()
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LeaderAssociation {
    pub leader_id: usize,
    pub arrow_point: Point,
    pub target_point: Point,
    pub dogleg_point: Option<Point>,
}

impl LeaderAssociation {
    pub fn new(leader_id: usize, arrow_point: Point, target_point: Point) -> Self {
        Self {
            leader_id,
            arrow_point,
            target_point,
            dogleg_point: None,
        }
    }
    
    pub fn with_dogleg(mut self, dogleg_point: Point) -> Self {
        self.dogleg_point = Some(dogleg_point);
        self
    }
}