use std::sync::Arc;
use std::path::PathBuf;
use crate::core::{SystemError, InputState};
use super::world::World;
use super::asset::AssetManager;
use super::scene::manifest::{load_project_manifest, ProjectManifest};
use super::scene::SceneManager;
use super::input::InputManager;
use crate::systems::RenderSystem;

/// MoltRun 엔진의 메인 구조체
/// 외부 프로젝트에서 쉽게 사용할 수 있도록 통합된 API 제공
pub struct Engine {
    pub world: World,
    pub render_system: RenderSystem,
    pub input_manager: InputManager,
    pub asset_manager: Option<AssetManager>, // initially None
    scene_manager: Option<SceneManager>,
    project_root: PathBuf,
    project_manifest: Option<ProjectManifest>,
    initialized: bool,
}

impl Engine {
    /// 새 엔진 인스턴스 생성
    /// project_root: project.yaml이 있는 프로젝트 루트 경로
    pub fn new<P: Into<PathBuf>>(project_root: P) -> Self {
        let project_root = project_root.into();
        Self {
            world: World::new(),
            render_system: RenderSystem::new(),
            input_manager: InputManager::new(),
            asset_manager: None,
            scene_manager: Some(SceneManager::new(project_root.clone())),
            project_root,
            project_manifest: None,
            initialized: false,
        }
    }
    
    /// project.yaml 로드
    pub fn load_project_manifest(&mut self) -> Result<(), SystemError> {
        let project_yaml = self.project_root.join("project.yaml");
        
        if !project_yaml.exists() {
            return Err(SystemError::RuntimeError(
                format!("project.yaml not found at {}", project_yaml.display())
            ));
        }
        
        let manifest = load_project_manifest(&project_yaml)
            .map_err(|e| SystemError::RuntimeError(format!("Failed to load project.yaml: {}", e)))?;
        
        log::info!("✅ Project loaded: {} v{}", manifest.name, manifest.version);
        self.project_manifest = Some(manifest);
        Ok(())
    }
    
    /// 엔진 초기화 (비동기)
    /// winit Window가 준비된 후에 호출해야 함
    pub async fn initialize(&mut self, window: Arc<winit::window::Window>) -> Result<(), SystemError> {
        // project.yaml 로드
        if self.project_manifest.is_none() {
            self.load_project_manifest()?;
        }
        
        // asset_root 결정 (config.asset_root 또는 기본값 "assets")
        let asset_root = self.project_manifest.as_ref()
            .and_then(|m| m.config.as_ref())
            .and_then(|c| c.asset_root.as_ref())
            .map(|s| s.as_str())
            .unwrap_or("assets");
        
        let asset_root_path = self.project_root.join(asset_root);
        
        // 렌더 시스템 초기화
        self.render_system.initialize(window).await?;

        // AssetManager 초기화
        self.asset_manager = Some(AssetManager::new(asset_root_path));
        
        // 월드 초기화
        self.world.initialize()?;
        
        // entry_scene 자동 로드
        if let Some(manifest) = &self.project_manifest {
            if let Some(config) = &manifest.config {
                let entry_scene = &config.entry_scene;
                log::info!("🎬 Loading entry scene: {}", entry_scene);
                
                if let Some(scene_manager) = &mut self.scene_manager {
                    scene_manager.load_scene(entry_scene, &mut self.world)
                        .map_err(|e| SystemError::RuntimeError(format!("Failed to load entry scene: {}", e)))?;
                }
            }
        }
        
        self.initialized = true;
        log::info!("✅ MoltRun Engine 초기화 완료");
        Ok(())
    }
    
    /// 한 프레임 업데이트
    /// 게임 루프에서 매 프레임 호출
    pub fn update(&mut self, delta_time: f32) -> Result<(), SystemError> {
        if !self.initialized {
            return Err(SystemError::RuntimeError("Engine not initialized. Call initialize() first.".to_string()));
        }
        
        // 입력 프레임 시작
        self.input_manager.begin_frame();
        
        // 월드 업데이트 (시스템들 실행) - InputState 전달
        self.world.update(delta_time, self.input_manager.state())?;
        
        // 입력 프레임 종료
        self.input_manager.end_frame();
        
        Ok(())
    }
    
    /// 렌더링 수행
    /// 게임 루프에서 update() 후에 호출
    pub fn render(&mut self) -> Result<(), SystemError> {
        if !self.initialized {
            return Err(SystemError::RuntimeError("Engine not initialized. Call initialize() first.".to_string()));
        }
        
        // AssetManager 참조 얻기
        let asset_manager = self.asset_manager.as_mut()
            .ok_or(SystemError::RuntimeError("AssetManager not initialized".to_string()))?;
        
        // RenderSystem에 AssetManager 전달
        self.render_system.render(&self.world, asset_manager)
    }
    
    /// AssetManager 참조 가져오기
    pub fn asset_manager(&self) -> Option<&AssetManager> {
        self.asset_manager.as_ref()
    }
    
    /// AssetManager 가변 참조 가져오기
    pub fn asset_manager_mut(&mut self) -> Option<&mut AssetManager> {
        self.asset_manager.as_mut()
    }
    
    /// 엔진 종료 및 리소스 정리
    pub fn shutdown(&mut self) -> Result<(), SystemError> {
        if self.initialized {
            self.world.shutdown()?;
            self.initialized = false;
            log::info!("MoltRun Engine 종료됨");
        }
        Ok(())
    }
    
    /// 초기화 상태 확인
    pub fn is_initialized(&self) -> bool {
        self.initialized
    }
    
    /// ProjectManifest 참조 가져오기
    pub fn project_manifest(&self) -> Option<&ProjectManifest> {
        self.project_manifest.as_ref()
    }
    
    /// 프로젝트 루트 경로 가져오기
    pub fn project_root(&self) -> &PathBuf {
        &self.project_root
    }
    
    /// SceneManager 가변 참조 가져오기
    pub fn scene_manager_mut(&mut self) -> Option<&mut SceneManager> {
        self.scene_manager.as_mut()
    }
    
    /// 씬 전환
    pub fn load_scene(&mut self, scene_name: &str) -> Result<(), SystemError> {
        if let Some(scene_manager) = &mut self.scene_manager {
            scene_manager.load_scene(scene_name, &mut self.world)
                .map_err(|e| SystemError::RuntimeError(format!("Failed to load scene: {}", e)))?;
        }
        Ok(())
    }
    
    /// winit WindowEvent 처리 (입력 이벤트를 InputManager로 전달)
    /// preview_runner 등 외부 이벤트 루프에서 호출
    pub fn handle_window_event(&mut self, event: &winit::event::WindowEvent) {
        self.input_manager.process_window_event(event);
    }
    
    /// InputState 읽기 전용 참조 가져오기
    pub fn input_state(&self) -> &InputState {
        self.input_manager.state()
    }
    
    /// 현재 씬을 디스크에서 다시 로드
    pub fn reload_current_scene(&mut self) -> Result<(), SystemError> {
        if let Some(scene_manager) = &mut self.scene_manager {
            if let Some(scene_name) = scene_manager.current_scene().map(|s| s.to_string()) {
                scene_manager.load_scene(&scene_name, &mut self.world)
                    .map_err(|e| SystemError::RuntimeError(format!("Failed to reload scene: {}", e)))?;
                Ok(())
            } else {
                Err(SystemError::RuntimeError("No scene loaded".to_string()))
            }
        } else {
            Err(SystemError::RuntimeError("SceneManager not available".to_string()))
        }
    }
}

impl Default for Engine {
    fn default() -> Self {
        Self::new(".")
    }
}

