use crate::geometry::{Point, Line, Circle, Arc, Ellipse, Polyline};
use crate::render::{RenderStyle, RenderBuffer, Renderer};
use std::error::Error;
use std::fmt;

pub trait RenderBackend {
    fn name(&self) -> &str;
    fn is_available(&self) -> bool;
    fn initialize(&mut self) -> Result<(), String>;
    fn set_size(&mut self, width: usize, height: usize);
    fn clear(&mut self, color: (u8, u8, u8));
    fn present(&mut self);
    fn get_framebuffer(&mut self) -> Option<&mut RenderBuffer>;
    fn get_capabilities(&self) -> BackendCapabilities;
}

#[derive(Debug, Clone)]
pub struct BackendCapabilities {
    pub max_texture_size: usize,
    pub supports_shaders: bool,
    pub supports_anti_aliasing: bool,
    pub supports_hardware_acceleration: bool,
    pub max_vertex_count: usize,
    pub supports_geometry_shader: bool,
    pub supports_compute_shader: bool,
}

impl Default for BackendCapabilities {
    fn default() -> Self {
        Self {
            max_texture_size: 4096,
            supports_shaders: false,
            supports_anti_aliasing: false,
            supports_hardware_acceleration: false,
            max_vertex_count: 1000000,
            supports_geometry_shader: false,
            supports_compute_shader: false,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum BackendType {
    Software,
    SVG,
    #[cfg(target_arch = "wasm32")]
    WebGL,
    #[cfg(target_os = "windows")]
    Direct2D,
    #[cfg(target_os = "windows")]
    Direct3D11,
    #[cfg(target_os = "macos")]
    Metal,
    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
    OpenGL,
    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
    Vulkan,
}

impl BackendType {
    pub fn from_str(name: &str) -> Option<Self> {
        match name.to_lowercase().as_str() {
            "software" => Some(BackendType::Software),
            "svg" => Some(BackendType::SVG),
            #[cfg(target_arch = "wasm32")]
            "webgl" | "web_gpu" => Some(BackendType::WebGL),
            #[cfg(target_os = "windows")]
            "direct2d" | "d2d" => Some(BackendType::Direct2D),
            #[cfg(target_os = "windows")]
            "direct3d" | "d3d11" | "dx11" => Some(BackendType::Direct3D11),
            #[cfg(target_os = "macos")]
            "metal" | "mtl" => Some(BackendType::Metal),
            #[cfg(any(target_os = "linux", target_os = "freebsd"))]
            "opengl" | "gl" | "gl3" => Some(BackendType::OpenGL),
            #[cfg(any(target_os = "linux", target_os = "freebsd"))]
            "vulkan" | "vk" => Some(BackendType::Vulkan),
            _ => None,
        }
    }

    pub fn gpu_backends() -> Vec<Self> {
        let mut backends = Vec::new();
        
        #[cfg(target_os = "windows")]
        backends.push(BackendType::Direct3D11);
        
        #[cfg(target_os = "macos")]
        backends.push(BackendType::Metal);
        
        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
        backends.push(BackendType::Vulkan);
        
        #[cfg(target_arch = "wasm32")]
        backends.push(BackendType::WebGL);
        
        backends
    }

    pub fn default() -> Self {
        BackendType::Software
    }

    pub fn default_gpu() -> Self {
        let gpu_backends = Self::gpu_backends();
        if !gpu_backends.is_empty() {
            gpu_backends[0].clone()
        } else {
            BackendType::Software
        }
    }

    pub fn create_backend(&self) -> Box<dyn RenderBackend> {
        match self {
            BackendType::Software => Box::new(SoftwareRenderer::new()),
            BackendType::SVG => Box::new(SVGRenderer::new()),
            #[cfg(target_arch = "wasm32")]
            BackendType::WebGL => Box::new(WebGLRenderer::new()),
            #[cfg(target_os = "windows")]
            BackendType::Direct2D => Box::new(Direct2DRenderer::new()),
            #[cfg(target_os = "windows")]
            BackendType::Direct3D11 => Box::new(D3D11Renderer::new()),
            #[cfg(target_os = "macos")]
            BackendType::Metal => Box::new(MetalRenderer::new()),
            #[cfg(any(target_os = "linux", target_os = "freebsd"))]
            BackendType::OpenGL => Box::new(OpenGLRenderer::new()),
            #[cfg(any(target_os = "linux", target_os = "freebsd"))]
            BackendType::Vulkan => Box::new(VulkanRenderer::new()),
        }
    }
}

pub struct RenderingContext {
    backend: Box<dyn RenderBackend>,
    width: usize,
    height: usize,
}

impl RenderingContext {
    pub fn new(backend_type: BackendType) -> Result<Self, String> {
        let mut backend = backend_type.create_backend();
        backend.initialize()?;
        
        Ok(Self {
            backend,
            width: 800,
            height: 600,
        })
    }

    pub fn with_size(backend_type: BackendType, width: usize, height: usize) -> Result<Self, String> {
        let mut context = Self::new(backend_type)?;
        context.set_size(width, height);
        Ok(context)
    }

    pub fn set_size(&mut self, width: usize, height: usize) {
        self.width = width;
        self.height = height;
        self.backend.set_size(width, height);
    }

    pub fn width(&self) -> usize {
        self.width
    }

    pub fn height(&self) -> usize {
        self.height
    }

    pub fn clear(&mut self, color: (u8, u8, u8)) {
        self.backend.clear(color);
    }

    pub fn present(&mut self) {
        self.backend.present();
    }

    pub fn get_framebuffer(&mut self) -> Option<&mut RenderBuffer> {
        self.backend.get_framebuffer()
    }

    pub fn get_capabilities(&self) -> BackendCapabilities {
        self.backend.get_capabilities()
    }
}

pub struct GPURenderer {
    width: usize,
    height: usize,
    capabilities: BackendCapabilities,
    vertex_buffer: Vec<Vertex>,
    index_buffer: Vec<u32>,
    texture_cache: std::collections::HashMap<String, TextureHandle>,
    shader_programs: std::collections::HashMap<String, ShaderProgram>,
}

#[derive(Debug, Clone)]
pub struct Vertex {
    pub position: [f32; 3],
    pub color: [f32; 4],
    pub texcoord: [f32; 2],
    pub normal: [f32; 3],
}

#[derive(Debug, Clone)]
pub struct TextureHandle {
    width: usize,
    height: usize,
    format: TextureFormat,
}

#[derive(Debug, Clone)]
pub enum TextureFormat {
    RGBA8,
    RGBA16F,
    RGBA32F,
    R8,
    R16F,
    R32F,
}

#[derive(Debug, Clone)]
pub struct ShaderProgram {
    vertex_shader: String,
    fragment_shader: String,
    uniforms: Vec<Uniform>,
}

#[derive(Debug, Clone)]
pub struct Uniform {
    name: String,
    uniform_type: UniformType,
    value: UniformValue,
}

#[derive(Debug, Clone)]
pub enum UniformType {
    Float,
    Vec2,
    Vec3,
    Vec4,
    Mat4,
    Int,
    Sampler2D,
}

#[derive(Debug, Clone)]
pub enum UniformValue {
    Float(f32),
    Vec2([f32; 2]),
    Vec3([f32; 3]),
    Vec4([f32; 4]),
    Mat4([[f32; 4]; 4]),
    Int(i32),
    Texture(TextureHandle),
}

impl GPURenderer {
    pub fn new() -> Self {
        Self {
            width: 800,
            height: 600,
            capabilities: BackendCapabilities {
                max_texture_size: 8192,
                supports_shaders: true,
                supports_anti_aliasing: true,
                supports_hardware_acceleration: true,
                max_vertex_count: 10000000,
                supports_geometry_shader: true,
                supports_compute_shader: true,
            },
            vertex_buffer: Vec::new(),
            index_buffer: Vec::new(),
            texture_cache: std::collections::HashMap::new(),
            shader_programs: std::collections::HashMap::new(),
        }
    }

    pub fn with_size(width: usize, height: usize) -> Self {
        let mut renderer = Self::new();
        renderer.width = width;
        renderer.height = height;
        renderer
    }

    fn create_default_shaders(&mut self) {
        let vertex_shader = r#"#version 330 core
            layout(location = 0) in vec3 aPos;
            layout(location = 1) in vec4 aColor;
            layout(location = 2) in vec2 aTexCoord;
            layout(location = 3) in vec3 aNormal;
            
            uniform mat4 uModel;
            uniform mat4 uView;
            uniform mat4 uProjection;
            
            out vec4 vColor;
            out vec2 vTexCoord;
            out vec3 vNormal;
            out vec3 vFragPos;
            
            void main() {
                gl_Position = uProjection * uView * uModel * vec4(aPos, 1.0);
                vColor = aColor;
                vTexCoord = aTexCoord;
                vNormal = mat3(transpose(inverse(uModel))) * aNormal;
                vFragPos = vec3(uModel * vec4(aPos, 1.0));
            }
        "#.to_string();

        let fragment_shader = r#"#version 330 core
            out vec4 FragColor;
            
            in vec4 vColor;
            in vec2 vTexCoord;
            in vec3 vNormal;
            in vec3 vFragPos;
            
            uniform sampler2D uTexture;
            uniform vec4 uColor;
            uniform bool uUseTexture;
            uniform bool uUseLighting;
            uniform vec3 uLightPos;
            uniform vec3 uLightColor;
            uniform vec3 uViewPos;
            
            void main() {
                vec4 result = vColor * uColor;
                
                if (uUseTexture) {
                    vec4 texColor = texture(uTexture, vTexCoord);
                    result *= texColor;
                }
                
                if (uUseLighting) {
                    float ambientStrength = 0.1;
                    vec3 ambient = ambientStrength * uLightColor;
                    
                    vec3 norm = normalize(vNormal);
                    vec3 lightDir = normalize(uLightPos - vFragPos);
                    float diff = max(dot(norm, lightDir), 0.0);
                    vec3 diffuse = diff * uLightColor;
                    
                    vec3 viewDir = normalize(uViewPos - vFragPos);
                    vec3 reflectDir = reflect(-lightDir, norm);
                    float spec = 0.0;
                    if (diff > 0.0) {
                        float specularStrength = 0.5;
                        vec3 halfwayDir = normalize(lightDir + viewDir);
                        spec = pow(max(dot(norm, halfwayDir), 0.0), 32.0);
                    }
                    vec3 specular = specularStrength * spec * uLightColor;
                    
                    vec4 lighting = vec4(ambient + diffuse + specular, 1.0);
                    result *= lighting;
                }
                
                FragColor = result;
            }
        "#.to_string();

        self.shader_programs.insert("default".to_string(), ShaderProgram {
            vertex_shader,
            fragment_shader,
            uniforms: Vec::new(),
        });
    }

    fn create_text_shaders(&mut self) {
        let vertex_shader = r#"#version 330 core
            layout(location = 0) in vec3 aPos;
            layout(location = 1) in vec4 aColor;
            layout(location = 2) in vec2 aTexCoord;
            
            uniform mat4 uProjection;
            
            out vec4 vColor;
            out vec2 vTexCoord;
            
            void main() {
                gl_Position = uProjection * vec4(aPos, 1.0);
                vColor = aColor;
                vTexCoord = vTexCoord;
            }
        "#.to_string();

        let fragment_shader = r#"#version 330 core
            in vec4 vColor;
            in vec2 vTexCoord;
            
            out vec4 FragColor;
            
            uniform sampler2D uTexture;
            
            void main() {
                vec4 texColor = texture(uTexture, vTexCoord);
                if (texColor.a < 0.1) discard;
                FragColor = vColor * texColor;
            }
        "#.to_string();

        self.shader_programs.insert("text".to_string(), ShaderProgram {
            vertex_shader,
            fragment_shader,
            uniforms: Vec::new(),
        });
    }

    fn create_anti_aliased_shaders(&mut self) {
        let vertex_shader = r#"#version 330 core
            layout(location = 0) in vec3 aPos;
            layout(location = 1) in vec4 aColor;
            layout(location = 2) in vec2 aTexCoord;
            layout(location = 3) in float aEdgeDistance;
            
            uniform mat4 uModel;
            uniform mat4 uView;
            uniform mat4 uProjection;
            
            out vec4 vColor;
            out vec2 vTexCoord;
            out float vEdgeDistance;
            
            void main() {
                gl_Position = uProjection * uView * uModel * vec4(aPos, 1.0);
                vColor = aColor;
                vTexCoord = vTexCoord;
                vEdgeDistance = aEdgeDistance;
            }
        "#.to_string();

        let fragment_shader = r#"#version 330 core
            in vec4 vColor;
            in vec2 vTexCoord;
            in float vEdgeDistance;
            
            out vec4 FragColor;
            
            uniform float uEdgeWidth;
            
            void main() {
                float edgeFactor = smoothstep(0.0, uEdgeWidth, vEdgeDistance);
                FragColor = vColor * edgeFactor;
            }
        "#.to_string();

        self.shader_programs.insert("anti_aliased".to_string(), ShaderProgram {
            vertex_shader,
            fragment_shader,
            uniforms: Vec::new(),
        });
    }
}

#[cfg(target_os = "windows")]
pub struct Direct2DRenderer {
    width: usize,
    height: usize,
    render_target: Option<*mut std::ffi::c_void>,
    device_context: Option<*mut std::ffi::c_void>,
    swap_chain: Option<*mut std::ffi::c_void>,
}

#[cfg(target_os = "windows")]
impl Direct2DRenderer {
    pub fn new() -> Self {
        Self {
            width: 800,
            height: 600,
            render_target: None,
            device_context: None,
            swap_chain: None,
        }
    }
}

#[cfg(target_os = "windows")]
impl RenderBackend for Direct2DRenderer {
    fn name(&self) -> &str {
        "Direct2D"
    }

    fn is_available(&self) -> bool {
        false
    }

    fn initialize(&mut self) -> Result<(), String> {
        Ok(())
    }

    fn set_size(&mut self, width: usize, height: usize) {
        self.width = width;
        self.height = height;
    }

    fn clear(&mut self, _color: (u8, u8, u8)) {}

    fn present(&mut self) {}

    fn get_framebuffer(&mut self) -> Option<&mut RenderBuffer> {
        None
    }

    fn get_capabilities(&self) -> BackendCapabilities {
        BackendCapabilities {
            max_texture_size: 8192,
            supports_shaders: false,
            supports_anti_aliasing: true,
            supports_hardware_acceleration: true,
            max_vertex_count: 1000000,
            supports_geometry_shader: false,
            supports_compute_shader: false,
        }
    }
}

#[cfg(target_os = "windows")]
pub struct D3D11Renderer {
    width: usize,
    height: usize,
    device: Option<*mut std::ffi::c_void>,
    device_context: Option<*mut std::ffi::c_void>,
    swap_chain: Option<*mut std::ffi::c_void>,
    render_target_view: Option<*mut std::ffi::c_void>,
    depth_stencil_view: Option<*mut std::ffi::c_void>,
    vertex_shader: Option<*mut std::ffi::c_void>,
    pixel_shader: Option<*mut std::ffi::c_void>,
    input_layout: Option<*mut std::ffi::c_void>,
    vertex_buffer: Option<*mut std::ffi::c_void>,
    index_buffer: Option<*mut std::ffi::c_void>,
    constant_buffer: Option<*mut std::ffi::c_void>,
    blend_state: Option<*mut std::ffi::c_void>,
    rasterizer_state: Option<*mut std::ffi::c_void>,
    depth_stencil_state: Option<*mut std::ffi::c_void>,
}

#[cfg(target_os = "windows")]
impl D3D11Renderer {
    pub fn new() -> Self {
        Self {
            width: 800,
            height: 600,
            device: None,
            device_context: None,
            swap_chain: None,
            render_target_view: None,
            depth_stencil_view: None,
            vertex_shader: None,
            pixel_shader: None,
            input_layout: None,
            vertex_buffer: None,
            index_buffer: None,
            constant_buffer: None,
            blend_state: None,
            rasterizer_state: None,
            depth_stencil_state: None,
        }
    }

    fn compile_shader(source: &[u8], target: &str, entry_point: &str) -> Result<Vec<u8>, String> {
        Ok(Vec::new())
    }
}

#[cfg(target_os = "windows")]
impl RenderBackend for D3D11Renderer {
    fn name(&self) -> &str {
        "Direct3D 11"
    }

    fn is_available(&self) -> bool {
        false
    }

    fn initialize(&mut self) -> Result<(), String> {
        Ok(())
    }

    fn set_size(&mut self, width: usize, height: usize) {
        self.width = width;
        self.height = height;
    }

    fn clear(&mut self, _color: (u8, u8, u8)) {}

    fn present(&mut self) {}

    fn get_framebuffer(&mut self) -> Option<&mut RenderBuffer> {
        None
    }

    fn get_capabilities(&self) -> BackendCapabilities {
        BackendCapabilities {
            max_texture_size: 16384,
            supports_shaders: true,
            supports_anti_aliasing: true,
            supports_hardware_acceleration: true,
            max_vertex_count: 10000000,
            supports_geometry_shader: true,
            supports_compute_shader: true,
        }
    }
}

#[cfg(target_os = "macos")]
pub struct MetalRenderer {
    width: usize,
    height: usize,
    device: Option<*mut std::ffi::c_void>,
    command_queue: Option<*mut std::ffi::c_void>,
    render_pipeline_state: Option<*mut std::ffi::c_void>,
    vertex_buffer: Option<*mut std::ffi::c_void>,
    uniform_buffer: Option<*mut std::ffi::c_void>,
}

#[cfg(target_os = "macos")]
impl MetalRenderer {
    pub fn new() -> Self {
        Self {
            width: 800,
            height: 600,
            device: None,
            command_queue: None,
            render_pipeline_state: None,
            vertex_buffer: None,
            uniform_buffer: None,
        }
    }
}

#[cfg(target_os = "macos")]
impl RenderBackend for MetalRenderer {
    fn name(&self) -> &str {
        "Metal"
    }

    fn is_available(&self) -> bool {
        false
    }

    fn initialize(&mut self) -> Result<(), String> {
        Ok(())
    }

    fn set_size(&mut self, width: usize, height: usize) {
        self.width = width;
        self.height = height;
    }

    fn clear(&mut self, _color: (u8, u8, u8)) {}

    fn present(&mut self) {}

    fn get_framebuffer(&mut self) -> Option<&mut RenderBuffer> {
        None
    }

    fn get_capabilities(&self) -> BackendCapabilities {
        BackendCapabilities {
            max_texture_size: 16384,
            supports_shaders: true,
            supports_anti_aliasing: true,
            supports_hardware_acceleration: true,
            max_vertex_count: 10000000,
            supports_geometry_shader: true,
            supports_compute_shader: true,
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
pub struct OpenGLRenderer {
    width: usize,
    height: usize,
    context: glutin::context::PossiblyCurrentContext,
    surface: glutin::surface::Surface<glutin::surface::Window>,
    vertex_array: Option<gl::types::GLuint>,
    vertex_buffer: Option<gl::types::GLuint>,
    shader_program: Option<gl::types::GLuint>,
    texture: Option<gl::types::GLuint>,
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
impl OpenGLRenderer {
    pub fn new() -> Self {
        Self {
            width: 800,
            height: 600,
            context: unsafe { std::mem::zeroed() },
            surface: unsafe { std::mem::zeroed() },
            vertex_array: None,
            vertex_buffer: None,
            shader_program: None,
            texture: None,
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
impl RenderBackend for OpenGLRenderer {
    fn name(&self) -> &str {
        "OpenGL"
    }

    fn is_available(&self) -> bool {
        false
    }

    fn initialize(&mut self) -> Result<(), String> {
        Ok(())
    }

    fn set_size(&mut self, width: usize, height: usize) {
        self.width = width;
        self.height = height;
    }

    fn clear(&mut self, _color: (u8, u8, u8)) {}

    fn present(&mut self) {}

    fn get_framebuffer(&mut self) -> Option<&mut RenderBuffer> {
        None
    }

    fn get_capabilities(&self) -> BackendCapabilities {
        BackendCapabilities {
            max_texture_size: 16384,
            supports_shaders: true,
            supports_anti_aliasing: true,
            supports_hardware_acceleration: true,
            max_vertex_count: 10000000,
            supports_geometry_shader: true,
            supports_compute_shader: true,
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
pub struct VulkanRenderer {
    width: usize,
    height: usize,
    instance: Option<*mut std::ffi::c_void>,
    physical_device: Option<*mut std::ffi::c_void>,
    device: Option<*mut std::ffi::c_void>,
    queue: Option<*mut std::ffi::c_void>,
    swap_chain: Option<*mut std::ffi::c_void>,
    pipeline: Option<*mut std::ffi::c_void>,
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
impl VulkanRenderer {
    pub fn new() -> Self {
        Self {
            width: 800,
            height: 600,
            instance: None,
            physical_device: None,
            device: None,
            queue: None,
            swap_chain: None,
            pipeline: None,
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
impl RenderBackend for VulkanRenderer {
    fn name(&self) -> &str {
        "Vulkan"
    }

    fn is_available(&self) -> bool {
        false
    }

    fn initialize(&mut self) -> Result<(), String> {
        Ok(())
    }

    fn set_size(&mut self, width: usize, height: usize) {
        self.width = width;
        self.height = height;
    }

    fn clear(&mut self, _color: (u8, u8, u8)) {}

    fn present(&mut self) {}

    fn get_framebuffer(&mut self) -> Option<&mut RenderBuffer> {
        None
    }

    fn get_capabilities(&self) -> BackendCapabilities {
        BackendCapabilities {
            max_texture_size: 16384,
            supports_shaders: true,
            supports_anti_aliasing: true,
            supports_hardware_acceleration: true,
            max_vertex_count: 10000000,
            supports_geometry_shader: true,
            supports_compute_shader: true,
        }
    }
}

#[cfg(target_arch = "wasm32")]
pub struct WebGLRenderer {
    width: usize,
    height: usize,
    canvas: web_sys::HtmlCanvasElement,
    context: web_sys::WebGlRenderingContext,
    program: Option<web_sys::WebGlProgram>,
    buffers: std::collections::HashMap<String, web_sys::WebGlBuffer>,
}

#[cfg(target_arch = "wasm32")]
impl WebGLRenderer {
    pub fn new() -> Self {
        Self {
            width: 800,
            height: 600,
            canvas: unsafe { std::mem::zeroed() },
            context: unsafe { std::mem::zeroed() },
            program: None,
            buffers: std::collections::HashMap::new(),
        }
    }
}

#[cfg(target_arch = "wasm32")]
impl RenderBackend for WebGLRenderer {
    fn name(&self) -> &str {
        "WebGL"
    }

    fn is_available(&self) -> bool {
        false
    }

    fn initialize(&mut self) -> Result<(), String> {
        Ok(())
    }

    fn set_size(&mut self, width: usize, height: usize) {
        self.width = width;
        self.height = height;
    }

    fn clear(&mut self, _color: (u8, u8, u8)) {}

    fn present(&mut self) {}

    fn get_framebuffer(&mut self) -> Option<&mut RenderBuffer> {
        None
    }

    fn get_capabilities(&self) -> BackendCapabilities {
        BackendCapabilities {
            max_texture_size: 4096,
            supports_shaders: true,
            supports_anti_aliasing: true,
            supports_hardware_acceleration: true,
            max_vertex_count: 1000000,
            supports_geometry_shader: false,
            supports_compute_shader: false,
        }
    }
}

pub struct SoftwareRenderer {
    width: usize,
    height: usize,
    buffer: RenderBuffer,
}

impl SoftwareRenderer {
    pub fn new() -> Self {
        Self {
            width: 800,
            height: 600,
            buffer: RenderBuffer::new(800, 600),
        }
    }

    pub fn with_size(width: usize, height: usize) -> Self {
        Self {
            width,
            height,
            buffer: RenderBuffer::new(width, height),
        }
    }
}

impl RenderBackend for SoftwareRenderer {
    fn name(&self) -> &str {
        "Software"
    }

    fn is_available(&self) -> bool {
        true
    }

    fn initialize(&mut self) -> Result<(), String> {
        self.buffer = RenderBuffer::new(self.width, self.height);
        Ok(())
    }

    fn set_size(&mut self, width: usize, height: usize) {
        self.width = width;
        self.height = height;
        self.buffer = RenderBuffer::new(width, height);
    }

    fn clear(&mut self, color: (u8, u8, u8)) {
        self.buffer.clear(color);
    }

    fn present(&mut self) {}

    fn get_framebuffer(&mut self) -> Option<&mut RenderBuffer> {
        Some(&mut self.buffer)
    }

    fn get_capabilities(&self) -> BackendCapabilities {
        BackendCapabilities::default()
    }
}

pub struct SVGRenderer {
    width: usize,
    height: usize,
    svg_content: String,
}

impl SVGRenderer {
    pub fn new() -> Self {
        Self {
            width: 800,
            height: 600,
            svg_content: String::new(),
        }
    }

    pub fn with_size(width: usize, height: usize) -> Self {
        Self {
            width,
            height,
            svg_content: format!(r#"<svg xmlns="http://www.w3.org/2000/svg" width="{}" height="{}">"#, width, height),
        }
    }

    pub fn finalize(&mut self) {
        self.svg_content.push_str("</svg>");
    }

    pub fn get_svg(&self) -> &str {
        &self.svg_content
    }
}

impl RenderBackend for SVGRenderer {
    fn name(&self) -> &str {
        "SVG"
    }

    fn is_available(&self) -> bool {
        true
    }

    fn initialize(&mut self) -> Result<(), String> {
        self.svg_content = format!(r#"<svg xmlns="http://www.w3.org/2000/svg" width="{}" height="{}">"#, self.width, self.height);
        Ok(())
    }

    fn set_size(&mut self, width: usize, height: usize) {
        self.width = width;
        self.height = height;
        self.svg_content = format!(r#"<svg xmlns="http://www.w3.org/2000/svg" width="{}" height="{}">"#, width, height);
    }

    fn clear(&mut self, color: (u8, u8, u8)) {
        self.svg_content.push_str(&format!(
            r#"<rect width="100%" height="100%" fill="rgb({},{},{})"/>"#,
            color.0, color.1, color.2
        ));
    }

    fn present(&mut self) {
        self.finalize();
    }

    fn get_framebuffer(&mut self) -> Option<&mut RenderBuffer> {
        None
    }

    fn get_capabilities(&self) -> BackendCapabilities {
        BackendCapabilities::default()
    }
}

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

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

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

    #[test]
    fn test_backend_type_creation() {
        let backend = BackendType::Software;
        assert_eq!(backend.name(), "Software");
    }

    #[test]
    fn test_rendering_context() {
        let context = RenderingContext::new(BackendType::Software);
        assert!(context.is_ok());
    }

    #[test]
    fn test_gpu_renderer_creation() {
        let renderer = GPURenderer::new();
        assert_eq!(renderer.capabilities.supports_shaders, true);
        assert_eq!(renderer.capabilities.max_vertex_count, 10000000);
    }

    #[test]
    fn test_backend_capabilities() {
        let capabilities = BackendCapabilities::default();
        assert_eq!(capabilities.max_texture_size, 4096);
        assert!(!capabilities.supports_shaders);
    }

    #[test]
    fn test_shader_program_creation() {
        let program = ShaderProgram {
            vertex_shader: "#version 330 core\nvoid main() { gl_Position = vec4(0.0); }".to_string(),
            fragment_shader: "#version 330 core\nvoid main() { FragColor = vec4(1.0); }".to_string(),
            uniforms: Vec::new(),
        };
        assert!(!program.vertex_shader.is_empty());
        assert!(!program.fragment_shader.is_empty());
    }

    #[test]
    fn test_vertex_structure() {
        let vertex = Vertex {
            position: [0.0, 0.0, 0.0],
            color: [1.0, 0.0, 0.0, 1.0],
            texcoord: [0.5, 0.5],
            normal: [0.0, 0.0, 1.0],
        };
        assert_eq!(vertex.color[0], 1.0);
        assert_eq!(vertex.position[2], 0.0);
    }
}
