use std::collections::HashMap;
use serde_yaml::Value;
use crate::core::Component;
use crate::math::Vec2;
use super::manifest::{yaml_keys, yaml_utils};

#[derive(Debug, thiserror::Error)]
pub enum FactoryError {
    #[error("Unknown component type: {0}")]
    UnknownComponent(String),
    #[error("Invalid component data: {0}")]
    InvalidData(String),
    #[error("YAML parsing error: {0}")]
    YamlParse(#[from] yaml_utils::YamlParseError),
}

pub trait ComponentFactory: Send + Sync {
    fn create_component(&self, yaml_value: &Value) -> Result<Box<dyn Component>, FactoryError>;
}

pub struct ComponentRegistry {
    factories: HashMap<String, Box<dyn ComponentFactory>>,
}

impl ComponentRegistry {
    pub fn new() -> Self {
        let mut registry = Self {
            factories: HashMap::new(),
        };
        
        // 기본 컴포넌트 팩토리들 등록
        registry.register("Transform", TransformFactory);
        registry.register("Sprite", SpriteFactory);
        registry.register("Text", TextFactory);
        
        registry
    }
    
    pub fn register<F: ComponentFactory + 'static>(&mut self, name: &str, factory: F) {
        self.factories.insert(name.to_string(), Box::new(factory));
    }
    
    pub fn create(&self, component_name: &str, yaml: &Value) -> Result<Box<dyn Component>, FactoryError> {
        self.factories
            .get(component_name)
            .ok_or_else(|| FactoryError::UnknownComponent(component_name.to_string()))?
            .create_component(yaml)
    }
}

// Transform 팩토리
pub struct TransformFactory;

impl ComponentFactory for TransformFactory {
    fn create_component(&self, yaml: &Value) -> Result<Box<dyn Component>, FactoryError> {
        use crate::components::Transform;
        use yaml_keys::transform::*;
        use yaml_utils::*;
        
        let position = if yaml[POSITION].is_null() {
            Vec2::zero()
        } else {
            parse_vec2_array(&yaml[POSITION], POSITION)?
        };
        
        let rotation = yaml[ROTATION].as_f64().unwrap_or(0.0) as f32;
        
        let scale = if yaml[SCALE].is_null() {
            Vec2::one()
        } else {
            parse_vec2_array(&yaml[SCALE], SCALE)?
        };
        
        Ok(Box::new(Transform { position, rotation, scale }))
    }
}

// Sprite 팩토리
pub struct SpriteFactory;

impl ComponentFactory for SpriteFactory {
    fn create_component(&self, yaml: &Value) -> Result<Box<dyn Component>, FactoryError> {
        use crate::components::{Sprite, Color};
        use yaml_keys::sprite::*;
        use yaml_utils::*;
        
        let texture_path = yaml[TEXTURE].as_str().unwrap_or("").to_string();
        
        let size = if yaml[SIZE].is_null() {
            Vec2::new(32.0, 32.0)
        } else {
            parse_vec2_array(&yaml[SIZE], SIZE)?
        };
        
        let visible = yaml[VISIBLE].as_bool().unwrap_or(true);
        
        let color = if yaml[TINT].is_null() {
            Color::white()
        } else {
            parse_color_array(&yaml[TINT])?
        };
        
        let flip_x = yaml[FLIP_X].as_bool().unwrap_or(false);
        let flip_y = yaml[FLIP_Y].as_bool().unwrap_or(false);
        let layer = yaml[LAYER].as_i64().unwrap_or(0) as i32;
        
        Ok(Box::new(Sprite {
            texture_path,
            visible,
            size,
            color,
            flip_x,
            flip_y,
            layer,
        }))
    }
}

// Text 팩토리
pub struct TextFactory;

impl ComponentFactory for TextFactory {
    fn create_component(&self, yaml: &Value) -> Result<Box<dyn Component>, FactoryError> {
        use crate::components::{Text, Color, TextAlignment};
        use yaml_keys::text::*;
        use yaml_utils::*;
        
        let content = yaml[CONTENT].as_str().unwrap_or("").to_string();
        let font_path = yaml[FONT].as_str().unwrap_or("").to_string();
        let font_size = yaml[FONT_SIZE].as_f64().unwrap_or(16.0) as f32;
        let visible = yaml[VISIBLE].as_bool().unwrap_or(true);
        
        let color = if yaml[COLOR].is_null() {
            Color::white()
        } else {
            parse_color_array(&yaml[COLOR])?
        };
        
        let alignment = match yaml[ALIGNMENT].as_str().unwrap_or("left") {
            "center" => TextAlignment::Center,
            "right" => TextAlignment::Right,
            _ => TextAlignment::Left,
        };
        
        let line_spacing = yaml[LINE_SPACING].as_f64().unwrap_or(1.0) as f32;
        let layer = yaml[LAYER].as_i64().unwrap_or(0) as i32;
        
        Ok(Box::new(Text {
            content,
            font_path,
            font_size,
            color,
            visible,
            alignment,
            line_spacing,
            layer,
        }))
    }
}