use super::{Exporter, FormatInfo, Error};
use super::io::SUPPORTED_FORMATS;
use crate::data_structure::{Document, Entity, EntityType, EntityGeometry, ObjectId, Layer, Block};
use crate::geometry::{Point, Line, Circle, Arc, Polyline};
use std::path::Path;
use std::io::{self, Write};
use quick_xml::events::{Event, BytesText};
use quick_xml::writer::Writer;
use std::fs::File;

#[derive(Debug)]
pub struct DXFExporter {
    version: DXFVersion,
}

#[derive(Debug, Clone, PartialEq)]
pub enum DXFVersion {
    R12,
    R2000,
    R2018,
}

impl DXFExporter {
    pub fn new() -> Self {
        Self {
            version: DXFVersion::R2018,
        }
    }

    fn format_version(&self) -> &str {
        match self.version {
            DXFVersion::R12 => "AC1009",
            DXFVersion::R2000 => "AC1015",
            DXFVersion::R2018 => "AC1032",
        }
    }
}

impl Exporter for DXFExporter {
    fn can_export(&self, extension: &str) -> bool {
        extension.to_lowercase() == "dxf"
    }

    fn export_to_file(&self, doc: &Document, filename: &str) -> Result<(), Error> {
        let mut output = String::new();

        self.write_header(doc, &mut output);
        self.write_classes(&mut output);
        self.write_blocks(doc, &mut output);
        self.write_entities(doc, &mut output);
        self.write_objects(&mut output);
        self.write_footer(&mut output);

        std::fs::write(filename, output)
            .map_err(|e| Error::ExportError(format!("Failed to write file: {}", e)))
    }

    fn export_to_bytes(&self, doc: &Document) -> Result<Vec<u8>, Error> {
        let mut output = String::new();

        self.write_header(doc, &mut output);
        self.write_classes(&mut output);
        self.write_blocks(doc, &mut output);
        self.write_entities(doc, &mut output);
        self.write_objects(&mut output);
        self.write_footer(&mut output);

        Ok(output.into_bytes())
    }
}

impl DXFExporter {
    fn write_header(&self, doc: &Document, output: &mut String) {
        output.push_str("SECTION\n");
        output.push_str("  2\n");
        output.push_str("HEADER\n");

        output.push_str("  9\n");
        output.push_str("$ACADVER\n");
        output.push_str("  1\n");
        output.push_str(&format!("{}\n", self.format_version()));

        output.push_str("  9\n");
        output.push_str("$INSBASE\n");
        output.push_str("  10\n");
        output.push_str("0.0\n");
        output.push_str("  20\n");
        output.push_str("0.0\n");
        output.push_str("  30\n");
        output.push_str("0.0\n");

        output.push_str("  9\n");
        output.push_str("$EXTMIN\n");
        output.push_str("  10\n");
        output.push_str("0.0\n");
        output.push_str("  20\n");
        output.push_str("0.0\n");

        output.push_str("  9\n");
        output.push_str("$EXTMAX\n");
        output.push_str("  10\n");
        output.push_str("1000.0\n");
        output.push_str("  20\n");
        output.push_str("1000.0\n");

        output.push_str("ENDSEC\n");
    }

    fn write_classes(&self, output: &mut String) {
        output.push_str("SECTION\n");
        output.push_str("  2\n");
        output.push_str("CLASSES\n");
        output.push_str("ENDSEC\n");
    }

    fn write_blocks(&self, doc: &Document, output: &mut String) {
        output.push_str("SECTION\n");
        output.push_str("  2\n");
        output.push_str("BLOCKS\n");

        for (_, block) in &doc.blocks {
            output.push_str("  0\n");
            output.push_str("BLOCK\n");
            output.push_str("  8\n");
            output.push_str("0\n");
            output.push_str("  2\n");
            output.push_str(&format!("{}\n", block.name));
            output.push_str(" 70\n");
            output.push_str("1\n");

            output.push_str("  0\n");
            output.push_str("ENDBLK\n");
            output.push_str("  8\n");
            output.push_str("0\n");
        }

        output.push_str("ENDSEC\n");
    }

    fn write_entities(&self, doc: &Document, output: &mut String) {
        output.push_str("SECTION\n");
        output.push_str("  2\n");
        output.push_str("ENTITIES\n");

        for (_, entity) in &doc.entities {
            self.write_entity(entity, output);
        }

        output.push_str("ENDSEC\n");
    }

    fn write_entity(&self, entity: &Entity, output: &mut String) {
        match &entity.geometry {
            EntityGeometry::Line(line) => {
                self.write_line_entity(&line.start, &line.end, &entity.layer_id, output);
            }
            EntityGeometry::Circle(circle) => {
                self.write_circle_entity(&circle.center, circle.radius, &entity.layer_id, output);
            }
            EntityGeometry::Arc(arc) => {
                self.write_arc_entity(arc, &entity.layer_id, output);
            }
            EntityGeometry::Polyline(polyline) => {
                self.write_polyline_entity(polyline, &entity.layer_id, output);
            }
            _ => {}
        }
    }

    fn write_line_entity(&self, start: &Point, end: &Point, layer: &str, output: &mut String) {
        output.push_str("  0\n");
        output.push_str("LINE\n");
        output.push_str("  8\n");
        output.push_str(&format!("{}\n", layer));
        output.push_str(" 10\n");
        output.push_str(&format!("{}\n", start.x));
        output.push_str(" 20\n");
        output.push_str(&format!("{}\n", start.y));
        output.push_str(" 11\n");
        output.push_str(&format!("{}\n", end.x));
        output.push_str(" 21\n");
        output.push_str(&format!("{}\n", end.y));
    }

    fn write_circle_entity(&self, center: &Point, radius: f64, layer: &str, output: &mut String) {
        output.push_str("  0\n");
        output.push_str("CIRCLE\n");
        output.push_str("  8\n");
        output.push_str(&format!("{}\n", layer));
        output.push_str(" 10\n");
        output.push_str(&format!("{}\n", center.x));
        output.push_str(" 20\n");
        output.push_str(&format!("{}\n", center.y));
        output.push_str(" 40\n");
        output.push_str(&format!("{}\n", radius));
    }

    fn write_arc_entity(&self, arc: &Arc, layer: &str, output: &mut String) {
        output.push_str("  0\n");
        output.push_str("ARC\n");
        output.push_str("  8\n");
        output.push_str(&format!("{}\n", layer));
        output.push_str(" 10\n");
        output.push_str(&format!("{}\n", arc.center.x));
        output.push_str(" 20\n");
        output.push_str(&format!("{}\n", arc.center.y));
        output.push_str(" 40\n");
        output.push_str(&format!("{}\n", arc.radius));
        output.push_str(" 50\n");
        output.push_str(&format!("{}\n", arc.start_angle.to_degrees()));
        output.push_str(" 51\n");
        output.push_str(&format!("{}\n", arc.end_angle.to_degrees()));
    }

    fn write_polyline_entity(&self, polyline: &Polyline, layer: &str, output: &mut String) {
        output.push_str("  0\n");
        output.push_str("LWPOLYLINE\n");
        output.push_str("  8\n");
        output.push_str(&format!("{}\n", layer));
        output.push_str(" 90\n");
        output.push_str(&format!("{}\n", polyline.vertices.len()));
        output.push_str(" 70\n");
        output.push_str(&format!("{}\n", if polyline.is_closed { 1 } else { 0 }));

        for (i, vertex) in polyline.vertices.iter().enumerate() {
            output.push_str(" 10\n");
            output.push_str(&format!("{}\n", vertex.x));
            output.push_str(" 20\n");
            output.push_str(&format!("{}\n", vertex.y));
        }
    }

    fn write_objects(&self, output: &mut String) {
        output.push_str("SECTION\n");
        output.push_str("  2\n");
        output.push_str("OBJECTS\n");

        output.push_str("  0\n");
        output.push_str("DICTIONARY\n");
        output.push_str("  5\n");
        output.push_str("ACAD_GROUP\n");
        output.push_str("330\n");
        output.push_str("0\n");
        output.push_str("100\n");
        output.push_str("AcDbDictionary\n");

        output.push_str("ENDSEC\n");
    }

    fn write_footer(&self, output: &mut String) {
        output.push_str("EOF\n");
    }
}

#[derive(Debug)]
pub struct SVGExporter {
    width: f64,
    height: f64,
    scale: f64,
}

impl SVGExporter {
    pub fn new() -> Self {
        Self {
            width: 800.0,
            height: 600.0,
            scale: 1.0,
        }
    }

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

impl Exporter for SVGExporter {
    fn can_export(&self, extension: &str) -> bool {
        extension.to_lowercase() == "svg"
    }

    fn export_to_file(&self, doc: &Document, filename: &str) -> Result<(), Error> {
        let mut buffer = Vec::new();
        self.write_svg(doc, &mut buffer);

        let mut file = File::create(filename)
            .map_err(|e| Error::ExportError(format!("Failed to create file: {}", e)))?;

        file.write_all(&buffer)
            .map_err(|e| Error::ExportError(format!("Failed to write file: {}", e)))
    }

    fn export_to_bytes(&self, doc: &Document) -> Result<Vec<u8>, Error> {
        let mut buffer = Vec::new();
        self.write_svg(doc, &mut buffer);
        Ok(buffer)
    }
}

impl SVGExporter {
    fn write_svg(&self, doc: &Document, buffer: &mut Vec<u8>) {
        let mut writer = Writer::new_with_indent(buffer, b' ', 2);

        let svg_start = format!(
            r#"<svg xmlns="http://www.w3.org/2000/svg" width="{}" height="{}" viewBox="0 0 {} {}">"#,
            self.width, self.height, self.width, self.height
        );

        writer.write_event(Event::Text(BytesText::new(&svg_start)))
            .expect("Failed to write SVG start");

        writer.write_event(Event::Text(BytesText::new("\n")))
            .expect("Failed to write newline");

        writer.write_event(Event::Text(BytesText::new(&format!("  <!-- Generated by CAD SDK -->\n"))))
            .expect("Failed to write comment");

        writer.write_event(Event::Text(BytesText::new(&format!("  <g transform=\"scale(1, -1) translate(0, -{})\">\n", self.height))))
            .expect("Failed to write transform");

        let mut bbox = self.calculate_bbox(doc);

        for (_, entity) in &doc.entities {
            self.write_entity(entity, &mut writer);
        }

        writer.write_event(Event::Text(BytesText::new("  </g>\n")))
            .expect("Failed to write group end");

        writer.write_event(Event::Text(BytesText::new("</svg>\n")))
            .expect("Failed to write SVG end");
    }

    fn calculate_bbox(&self, doc: &Document) -> (f64, f64, f64, f64) {
        let mut min_x = f64::MAX;
        let mut min_y = f64::MAX;
        let mut max_x = f64::MIN;
        let mut max_y = f64::MIN;

        for (_, entity) in &doc.entities {
            match &entity.geometry {
                EntityGeometry::Line(line) => {
                    min_x = min_x.min(line.start.x).min(line.end.x);
                    min_y = min_y.min(line.start.y).min(line.end.y);
                    max_x = max_x.max(line.start.x).max(line.end.x);
                    max_y = max_y.max(line.start.y).max(line.end.y);
                }
                EntityGeometry::Circle(circle) => {
                    min_x = min_x.min(circle.center.x - circle.radius);
                    min_y = min_y.min(circle.center.y - circle.radius);
                    max_x = max_x.max(circle.center.x + circle.radius);
                    max_y = max_y.max(circle.center.y + circle.radius);
                }
                _ => {}
            }
        }

        (min_x, min_y, max_x, max_y)
    }

    fn write_entity<W: Write>(&self, entity: &Entity, writer: &mut Writer<W>) {
        match &entity.geometry {
            EntityGeometry::Line(line) => {
                let stroke = self.get_layer_color(&entity.layer_id);
                let element = format!(
                    r#"    <line x1="{}" y1="{}" x2="{}" y2="{}" stroke="{}" stroke-width="1" />"#,
                    line.start.x, line.start.y, line.end.x, line.end.y, stroke
                );
                writer.write_event(Event::Text(BytesText::new(&element)))
                    .expect("Failed to write line");
                writer.write_event(Event::Text(BytesText::new("\n")))
                    .expect("Failed to write newline");
            }
            EntityGeometry::Circle(circle) => {
                let stroke = self.get_layer_color(&entity.layer_id);
                let element = format!(
                    r#"    <circle cx="{}" cy="{}" r="{}" fill="none" stroke="{}" stroke-width="1" />"#,
                    circle.center.x, circle.center.y, circle.radius, stroke
                );
                writer.write_event(Event::Text(BytesText::new(&element)))
                    .expect("Failed to write circle");
                writer.write_event(Event::Text(BytesText::new("\n")))
                    .expect("Failed to write newline");
            }
            EntityGeometry::Arc(arc) => {
                let stroke = self.get_layer_color(&entity.layer_id);
                let start_x = arc.center.x + arc.radius * arc.start_angle.to_radians().cos();
                let start_y = arc.center.y + arc.radius * arc.start_angle.to_radians().sin();
                let end_x = arc.center.x + arc.radius * arc.end_angle.to_radians().cos();
                let end_y = arc.center.y + arc.radius * arc.end_angle.to_radians().sin();

                let large_arc = if arc.angle_span() > std::f64::consts::PI { 1 } else { 0 };
                let sweep = if arc.is_counter_clockwise { 1 } else { 0 };

                let element = format!(
                    r#"    <path d="M {} {} A {} {} 0 {} {} {} {}" fill="none" stroke="{}" stroke-width="1" />"#,
                    start_x, start_y, arc.radius, arc.radius, large_arc, sweep, end_x, end_y, stroke
                );
                writer.write_event(Event::Text(BytesText::new(&element)))
                    .expect("Failed to write arc");
                writer.write_event(Event::Text(BytesText::new("\n")))
                    .expect("Failed to write newline");
            }
            EntityGeometry::Polyline(polyline) => {
                if polyline.vertices.len() < 2 {
                    return;
                }

                let points: String = polyline.vertices.iter()
                    .map(|v| format!("{},{}", v.x, v.y))
                    .collect::<Vec<_>>()
                    .join(" ");

                let stroke = self.get_layer_color(&entity.layer_id);
                let fill = if polyline.is_closed { "none" } else { "none" };
                let element = format!(
                    r#"    <polyline points="{}" fill="{}" stroke="{}" stroke-width="1" />"#,
                    points, fill, stroke
                );
                writer.write_event(Event::Text(BytesText::new(&element)))
                    .expect("Failed to write polyline");
                writer.write_event(Event::Text(BytesText::new("\n")))
                    .expect("Failed to write newline");
            }
            _ => {}
        }
    }

    fn get_layer_color(&self, _layer_id: &ObjectId) -> String {
        "#000000".to_string()
    }
}

#[derive(Debug)]
pub struct JSONExporter;

impl JSONExporter {
    pub fn new() -> Self {
        Self
    }
}

impl Exporter for JSONExporter {
    fn can_export(&self, extension: &str) -> bool {
        extension.to_lowercase() == "json"
    }

    fn export_to_file(&self, doc: &Document, filename: &str) -> Result<(), Error> {
        let json = self.to_json(doc);
        std::fs::write(filename, json)
            .map_err(|e| Error::ExportError(format!("Failed to write file: {}", e)))
    }

    fn export_to_bytes(&self, doc: &Document) -> Result<Vec<u8>, Error> {
        Ok(self.to_json(doc).into_bytes())
    }
}

impl JSONExporter {
    fn to_json(&self, doc: &Document) -> String {
        let mut json = String::new();

        json.push_str("{\n");
        json.push_str(&format!("  \"name\": \"{}\",\n", doc.name));
        json.push_str(&format!("  \"version\": \"{}\",\n", doc.version));
        json.push_str(&format!("  \"units\": \"{:?}\",\n", doc.units));
        json.push_str("  \"entities\": [\n");

        let entity_count = doc.entities.len();
        for (i, (_, entity)) in doc.entities.iter().enumerate() {
            json.push_str("    {\n");
            json.push_str(&format!("      \"type\": \"{:?}\",\n", entity.entity_type));
            json.push_str(&format!("      \"layer\": \"{}\",\n", entity.layer_id));

            match &entity.geometry {
                EntityGeometry::Line(line) => {
                    json.push_str(&format!("      \"start\": {{ \"x\": {}, \"y\": {} }},\n", line.start.x, line.start.y));
                    json.push_str(&format!("      \"end\": {{ \"x\": {}, \"y\": {} }}\n", line.end.x, line.end.y));
                }
                EntityGeometry::Circle(circle) => {
                    json.push_str(&format!("      \"center\": {{ \"x\": {}, \"y\": {} }},\n", circle.center.x, circle.center.y));
                    json.push_str(&format!("      \"radius\": {}\n", circle.radius));
                }
                _ => {
                    json.push_str("      \"data\": {}\n");
                }
            }

            json.push_str("    }");
            if i < entity_count - 1 {
                json.push_str(",");
            }
            json.push_str("\n");
        }

        json.push_str("  ]\n");
        json.push_str("}\n");

        json
    }
}

pub struct ExporterRegistry {
    exporters: Vec<Box<dyn Exporter>>,
}

impl ExporterRegistry {
    pub fn new() -> Self {
        let mut registry = Self {
            exporters: Vec::new(),
        };
        registry.register_all();
        registry
    }

    fn register_all(&mut self) {
        self.exporters.push(Box::new(DXFExporter::new()));
        self.exporters.push(Box::new(SVGExporter::new()));
        self.exporters.push(Box::new(JSONExporter::new()));
    }

    pub fn get_exporter(&self, extension: &str) -> Option<&dyn Exporter> {
        for exporter in &self.exporters {
            if exporter.can_export(extension) {
                return Some(exporter.as_ref());
            }
        }
        None
    }

    pub fn export_to_file(&self, doc: &Document, filename: &str) -> Result<(), String> {
        let path = Path::new(filename);
        let extension = path.extension()
            .and_then(|ext| ext.to_str())
            .map(|ext| ext.to_lowercase())
            .ok_or("无法获取文件扩展名")?;

        if let Some(exporter) = self.get_exporter(&extension) {
            exporter.export_to_file(doc, filename)
                .map_err(|e| e.to_string())
        } else {
            Err(format!("不支持的文件格式: {}", extension))
        }
    }

    pub fn export_to_bytes(&self, doc: &Document, extension: &str) -> Result<Vec<u8>, String> {
        let ext = extension.to_lowercase();
        if let Some(exporter) = self.get_exporter(&ext) {
            exporter.export_to_bytes(doc)
                .map_err(|e| e.to_string())
        } else {
            Err(format!("不支持的文件格式: {}", ext))
        }
    }

    pub fn supported_formats(&self) -> Vec<&'static str> {
        vec!["dxf", "svg", "json"]
    }
}

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

pub fn get_exporter(extension: &str) -> Option<Box<dyn Exporter>> {
    match extension.to_lowercase().as_str() {
        "dxf" => Some(Box::new(DXFExporter::new())),
        "svg" => Some(Box::new(SVGExporter::new())),
        "json" => Some(Box::new(JSONExporter::new())),
        _ => None,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::data_structure::{Document, Entity, EntityType, EntityGeometry, Layer};
    use crate::geometry::{Point, Line, Circle};

    #[test]
    fn test_dxf_exporter() {
        let exporter = DXFExporter::new();
        assert!(exporter.can_export("dxf"));
        assert!(!exporter.can_export("dwg"));
    }

    #[test]
    fn test_svg_exporter() {
        let exporter = SVGExporter::new();
        assert!(exporter.can_export("svg"));
        assert!(!exporter.can_export("dxf"));
    }

    #[test]
    fn test_json_exporter() {
        let exporter = JSONExporter::new();
        assert!(exporter.can_export("json"));
        assert!(!exporter.can_export("svg"));
    }

    #[test]
    fn test_exporter_registry() {
        let registry = ExporterRegistry::new();
        assert!(registry.get_exporter("dxf").is_some());
        assert!(registry.get_exporter("svg").is_some());
        assert!(registry.get_exporter("json").is_some());
        assert!(registry.get_exporter("dwg").is_none());
    }

    #[test]
    fn test_document_export() {
        let mut doc = Document::new("Test".to_string());
        let line = Line::new(Point::new(0.0, 0.0), Point::new(100.0, 100.0));
        let entity = Entity::new(EntityType::Line, EntityGeometry::Line(line));
        doc.add_entity(entity);

        let exporter = DXFExporter::new();
        let bytes = exporter.export_to_bytes(&doc);

        assert!(bytes.is_ok());
        let content = String::from_utf8(bytes.unwrap()).unwrap();
        assert!(content.contains("LINE"));
        assert!(content.contains("SECTION"));
    }
}
