use std::fs::File;
use std::io::Read;
use std::path::Path;
use serde_yaml;

use super::structure::{
    EntityManifest, SceneManifest, ScenarioManifest, ProjectManifest
};

#[derive(Debug, thiserror::Error)]
pub enum ManifestLoaderError {
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
    #[error("YAML parse error: {0}")]
    Yaml(#[from] serde_yaml::Error),
}

/// 제네릭 함수로 모든 매니페스트 타입을 로드할 수 있습니다
fn load_manifest<T, P>(path: P) -> Result<T, ManifestLoaderError>
where
    T: serde::de::DeserializeOwned,
    P: AsRef<Path>,
{
    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    let manifest: T = serde_yaml::from_str(&contents)?;
    Ok(manifest)
}

pub fn load_entity_manifest<P: AsRef<Path>>(path: P) -> Result<EntityManifest, ManifestLoaderError> {
    load_manifest(path)
}

pub fn load_scene_manifest<P: AsRef<Path>>(path: P) -> Result<SceneManifest, ManifestLoaderError> {
    load_manifest(path)
}

pub fn load_scenario_manifest<P: AsRef<Path>>(path: P) -> Result<ScenarioManifest, ManifestLoaderError> {
    load_manifest(path)
}

pub fn load_project_manifest<P: AsRef<Path>>(path: P) -> Result<ProjectManifest, ManifestLoaderError> {
    load_manifest(path)
}