use crate::geometry::{Point, Line, Circle, Arc, Ellipse, Polyline};
use crate::render::{RenderStyle, Renderer};
use std::f64::consts::PI;

pub struct SVGRendererImpl {
    width: usize,
    height: usize,
    elements: Vec<String>,
    current_style: RenderStyle,
}

impl SVGRendererImpl {
    pub fn new(width: usize, height: usize) -> Self {
        Self {
            width,
            height,
            elements: Vec::new(),
            current_style: RenderStyle::default(),
        }
    }

    pub fn get_svg_content(&self) -> String {
        let mut svg = format!(
            r#"<svg xmlns="http://www.w3.org/2000/svg" width="{}" height="{}" viewBox="0 0 {} {}">"#,
            self.width, self.height, self.width, self.height
        );
        
        for element in &self.elements {
            svg.push_str(element);
        }
        
        svg.push_str("</svg>");
        svg
    }

    fn color_to_rgb(&self, color: (u8, u8, u8)) -> String {
        format!("rgb({},{},{})", color.0, color.1, color.2)
    }

    fn style_to_stroke(&self, style: &RenderStyle) -> String {
        let mut stroke = format!(r#"stroke="{}""#, self.color_to_rgb(style.color));
        
        match style.line_pattern {
            super::renderer::LinePattern::Solid => {},
            super::renderer::LinePattern::Dashed => {
                stroke.push_str(r#" stroke-dasharray="5,5""#);
            }
            super::renderer::LinePattern::Dotted => {
                stroke.push_str(r#" stroke-dasharray="2,2""#);
            }
            super::renderer::LinePattern::DashDot => {
                stroke.push_str(r#" stroke-dasharray="5,2,2""#);
            }
            super::renderer::LinePattern::Custom(ref pattern) => {
                let pattern_str = pattern.iter()
                    .map(|f| f.to_string())
                    .collect::<Vec<_>>()
                    .join(",");
                stroke.push_str(&format!(r#" stroke-dasharray="{}""#, pattern_str));
            }
        }
        
        stroke
    }

    fn format_line_style(&self, style: &RenderStyle) -> String {
        let mut attrs = format!(r#"stroke-width="{}" fill="none""#, style.line_width);
        attrs.push_str(&format!(r#" stroke="{}""#, self.color_to_rgb(style.color)));
        
        match style.line_pattern {
            super::renderer::LinePattern::Solid => {},
            super::renderer::LinePattern::Dashed => {
                attrs.push_str(r#" stroke-dasharray="5,5""#);
            }
            super::renderer::LinePattern::Dotted => {
                attrs.push_str(r#" stroke-dasharray="2,2""#);
            }
            _ => {},
        }
        
        if style.anti_aliasing {
            attrs.push_str(r#" shape-rendering="geometricPrecision""#);
        }
        
        attrs
    }
}

impl Renderer for SVGRendererImpl {
    fn initialize(&mut self) -> Result<(), String> {
        self.elements.clear();
        Ok(())
    }

    fn clear(&mut self, color: (u8, u8, u8)) {
        self.elements.push(format!(
            r#"<rect width="100%" height="100%" fill="{}"/>"#,
            self.color_to_rgb(color)
        ));
    }

    fn draw_line(&mut self, x1: f64, y1: f64, x2: f64, y2: f64, style: &RenderStyle) {
        let attrs = self.format_line_style(style);
        self.elements.push(format!(
            r#"<line x1="{:.2}" y1="{:.2}" x2="{:.2}" y2="{:.2}" {}"/>"#,
            x1, y1, x2, y2, attrs
        ));
    }

    fn draw_circle(&mut self, cx: f64, cy: f64, r: f64, style: &RenderStyle) {
        let fill = match style.fill {
            Some(color) => self.color_to_rgb(color),
            None => "none".to_string(),
        };
        
        self.elements.push(format!(
            r#"<circle cx="{:.2}" cy="{:.2}" r="{:.2}" fill="{}" stroke="{}" stroke-width="{:.2}"/>"#,
            cx, cy, r, fill, self.color_to_rgb(style.color), style.line_width
        ));
    }

    fn draw_arc(&mut self, cx: f64, cy: f64, r: f64, start_angle: f64, end_angle: f64, style: &RenderStyle) {
        let start_rad = start_angle * PI / 180.0;
        let end_rad = end_angle * PI / 180.0;
        
        let x1 = cx + r * start_rad.cos();
        let y1 = cy + r * start_rad.sin();
        let x2 = cx + r * end_rad.cos();
        let y2 = cy + r * end_rad.sin();
        
        let large_arc = if (end_angle - start_angle).abs() > 180.0 { 1 } else { 0 };
        
        let sweep = if start_angle < end_angle { 1 } else { 0 };
        
        let attrs = self.format_line_style(style);
        self.elements.push(format!(
            r#"<path d="M {:.2},{:.2} A {:.2},{:.2} 0 {} {} {:.2},{:.2}" {}"/>"#,
            x1, y1, r, r, large_arc, sweep, x2, y2, attrs
        ));
    }

    fn draw_polyline(&mut self, points: &[(f64, f64)], style: &RenderStyle) {
        if points.is_empty() {
            return;
        }
        
        let points_str: Vec<String> = points.iter()
            .map(|(x, y)| format!("{:.2},{:.2}", x, y))
            .collect();
        
        let attrs = self.format_line_style(style);
        self.elements.push(format!(
            r#"<polyline points="{}" {}"/>"#,
            points_str.join(" "), attrs
        ));
    }

    fn draw_point(&mut self, x: f64, y: f64, size: f64, style: &RenderStyle) {
        self.elements.push(format!(
            r#"<circle cx="{:.2}" cy="{:.2}" r="{:.2}" fill="{}"/>"#,
            x, y, size / 2.0, self.color_to_rgb(style.color)
        ));
    }

    fn draw_text(&mut self, x: f64, y: f64, text: &str, size: f64, rotation: f64, style: &RenderStyle) {
        let rotation_rad = rotation * PI / 180.0;
        let transform = if rotation.abs() > 0.001 {
            format!(r#" transform="rotate({:.2} {:.2},{:.2})""#, -rotation, x, y)
        } else {
            String::new()
        };
        
        self.elements.push(format!(
            r#"<text x="{:.2}" y="{:.2}" font-size="{:.2}" fill="{}"{}>{}</text>"#,
            x, y, size, self.color_to_rgb(style.color), transform, text
        ));
    }
    
    fn draw_text_enhanced(
        &mut self,
        x: f64,
        y: f64,
        text: &str,
        font_name: &str,
        size: f64,
        rotation: f64,
        width_factor: f64,
        style: &RenderStyle,
        bold: bool,
        italic: bool,
        underline: bool,
        alignment: i32,
    ) {
        let rotation_rad = rotation * PI / 180.0;
        let transform = if rotation.abs() > 0.001 {
            format!(r#" transform="rotate({:.2} {:.2},{:.2})""#, -rotation, x, y)
        } else {
            String::new()
        };
        
        let font_style = if italic { "italic" } else { "normal" };
        let font_weight = if bold { "bold" } else { "normal" };
        let text_decoration = if underline { "underline" } else { "none" };
        
        let text_anchor = match alignment {
            1 => "middle",
            2 => "end",
            _ => "start",
        };
        
        self.elements.push(format!(
            r#"<text x="{:.2}" y="{:.2}" font-family="{}" font-size="{:.2}" font-style="{}" font-weight="{}" text-decoration="{}" text-anchor="{}" fill="{}"{}>{}</text>"#,
            x, y, font_name, size, font_style, font_weight, text_decoration, text_anchor, self.color_to_rgb(style.color), transform, text
        ));
    }

    fn present(&mut self) {
    }

    fn flush(&mut self) {
    }
}

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

    #[test]
    fn test_svg_renderer_creation() {
        let renderer = SVGRendererImpl::new(800, 600);
        assert!(renderer.get_svg_content().contains("<svg"));
    }

    #[test]
    fn test_svg_renderer_draw_line() {
        let mut renderer = SVGRendererImpl::new(800, 600);
        renderer.initialize().unwrap();
        renderer.clear((255, 255, 255));
        renderer.draw_line(0.0, 0.0, 100.0, 100.0, &RenderStyle::default());
        
        let content = renderer.get_svg_content();
        assert!(content.contains("<line"));
        assert!(content.contains("100.00,100.00"));
    }

    #[test]
    fn test_svg_renderer_draw_circle() {
        let mut renderer = SVGRendererImpl::new(800, 600);
        renderer.initialize().unwrap();
        renderer.draw_circle(100.0, 100.0, 50.0, &RenderStyle::default());
        
        let content = renderer.get_svg_content();
        assert!(content.contains("<circle"));
        assert!(content.contains("100.00"));
        assert!(content.contains("50.00"));
    }
}
