use std::any::Any;
use std::sync::Arc;
use crate::{
    core::{Entity, System, SystemContext, SystemError},
    runtime::{AssetManager, World},
};
use super::{
    gpu::{GraphicsContext, RenderPipeline},
    pipeline::{SpriteBatch, RenderCommands},
    resources::TextureCache,
};

pub struct RenderSystem {
    graphics: Option<GraphicsContext>,
    render_pipeline: Option<RenderPipeline>,
    sprite_batch: SpriteBatch,
    texture_cache: Option<TextureCache>,
    initialized: bool,
}

impl RenderSystem {
    pub fn new() -> Self {
        Self {
            graphics: None,
            render_pipeline: None,
            sprite_batch: SpriteBatch::new(800.0, 600.0),  // 기본 크기
            texture_cache: None,
            initialized: false,
        }
    }
    
    pub async fn initialize(&mut self, window: Arc<winit::window::Window>) -> Result<(), SystemError> {
        let graphics = GraphicsContext::new(window).await
            .map_err(|e| SystemError::InitializationFailed(e))?;
        
        // 렌더 파이프라인 생성
        let render_pipeline = RenderPipeline::new_sprite_pipeline(
            graphics.device(),
            graphics.config().format
        );
        
        // TextureCache 초기화
        let texture_cache = TextureCache::new(
            Arc::new(graphics.device().clone()),
            Arc::new(graphics.queue().clone()),
        );
        
        self.graphics = Some(graphics);
        self.render_pipeline = Some(render_pipeline);
        self.texture_cache = Some(texture_cache);
        self.initialized = true;
        
        println!("✅ RenderSystem 초기화 완료");
        Ok(())
    }

    /// 메인 렌더링 메서드 - World 참조용
    pub fn render(&mut self, world: &World, asset_manager: &mut AssetManager) -> Result<(), SystemError> {
        // texture_cache를 사용하여 렌더링 (카메라 전달)
        self.render_entities_with_textures(world.entities(), world.camera(), asset_manager)
    }

    /// 엔티티 벡터로 렌더링하는 메서드 (텍스처 지원)
    fn render_entities_with_textures(
        &mut self, 
        entities: &[Entity],
        camera: &crate::runtime::Camera,
        asset_manager: &mut AssetManager,
    ) -> Result<(), SystemError> {
        if !self.initialized {
            return Err(SystemError::RuntimeError("RenderSystem not initialized. Call initialize() first.".to_string()));
        }
        
        let Some(graphics) = &self.graphics else {
            return Err(SystemError::RuntimeError("Graphics not initialized".to_string()));
        };
        
        let Some(render_pipeline) = &self.render_pipeline else {
            return Err(SystemError::RuntimeError("Render pipeline not initialized".to_string()));
        };
        
        let Some(texture_cache) = &mut self.texture_cache else {
            return Err(SystemError::RuntimeError("Texture cache not initialized".to_string()));
        };

        // 스프라이트 배치 수집 (카메라 전달)
        self.sprite_batch.begin_frame();
        self.sprite_batch.collect_sprites(entities, camera);
        
        if self.sprite_batch.is_empty() {
            return Ok(());
        }

        let output = graphics.get_current_frame()
            .map_err(|e| SystemError::RuntimeError(format!("Surface texture: {}", e)))?;
        
        let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
        let mut encoder = graphics.device().create_command_encoder(&wgpu::CommandEncoderDescriptor {
            label: Some("Render Encoder"),
        });

        let render_commands = RenderCommands::new(
            graphics,
            render_pipeline,
        );

        // 텍스처와 함께 렌더링
        render_commands.execute_render_pass_with_textures(
            &mut encoder, 
            &view, 
            &self.sprite_batch,
            texture_cache,
            asset_manager,
        );

        graphics.queue().submit(std::iter::once(encoder.finish()));
        output.present();

        Ok(())
    }
    
    /// 엔티티 벡터로 렌더링하는 메서드 (하위 호환성)
    pub fn render_entities(&mut self, entities: &[Entity], camera: &crate::runtime::Camera) -> Result<(), SystemError> {
        if !self.initialized {
            return Err(SystemError::RuntimeError("RenderSystem not initialized. Call initialize() first.".to_string()));
        }
        
        let Some(graphics) = &self.graphics else {
            return Err(SystemError::RuntimeError("Graphics not initialized".to_string()));
        };
        
        let Some(render_pipeline) = &self.render_pipeline else {
            return Err(SystemError::RuntimeError("Render pipeline not initialized".to_string()));
        };

        // 스프라이트 배치 수집 (카메라 전달)
        self.sprite_batch.begin_frame();
        self.sprite_batch.collect_sprites(entities, camera);
        
        if self.sprite_batch.is_empty() {
            return Ok(());
        }

        let output = graphics.get_current_frame()
            .map_err(|e| SystemError::RuntimeError(format!("Surface texture: {}", e)))?;
        
        let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
        let mut encoder = graphics.device().create_command_encoder(&wgpu::CommandEncoderDescriptor {
            label: Some("Render Encoder"),
        });

        let render_commands = RenderCommands::new(
            graphics,
            render_pipeline,
        );

        render_commands.execute_render_pass_direct(&mut encoder, &view, &self.sprite_batch);

        graphics.queue().submit(std::iter::once(encoder.finish()));
        output.present();

        Ok(())
    }

    /// Device 참조 가져오기 (더 이상 필요 없음 - TextureCache가 관리)
    #[deprecated(note = "TextureCache handles device internally")]
    pub fn device(&self) -> &wgpu::Device {
        self.graphics.as_ref()
            .expect("RenderSystem not initialized")
            .device()
    }
    
    /// Queue 참조 가져오기 (더 이상 필요 없음 - TextureCache가 관리)
    #[deprecated(note = "TextureCache handles queue internally")]
    pub fn queue(&self) -> &wgpu::Queue {
        self.graphics.as_ref()
            .expect("RenderSystem not initialized")
            .queue()
    }
}

impl System for RenderSystem {
    fn update(&mut self, context: &mut SystemContext) -> Result<(), SystemError> {
        self.render_entities(context.entities, context.camera)
    }
    
    fn name(&self) -> &'static str {
        "RenderSystem"
    }
    
    fn as_any(&self) -> &dyn Any {
        self
    }
    
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}