use anyhow::Context;
use serde::de::DeserializeOwned;
use std::fs;
use std::path::Path;

pub fn load_toml_config<T>(path: &Path) -> anyhow::Result<T>
where
    T: DeserializeOwned + Default,
{
    if !path.exists() {
        return Ok(T::default());
    }

    let contents = fs::read_to_string(path)
        .with_context(|| format!("failed to read config file {}", path.display()))?;
    toml::from_str(&contents)
        .with_context(|| format!("failed to parse config file {}", path.display()))
}

#[cfg(test)]
mod tests {
    use super::load_toml_config;
    use serde::Deserialize;
    use std::fs;
    use std::path::PathBuf;
    use std::time::{SystemTime, UNIX_EPOCH};

    #[derive(Debug, Default, Deserialize, PartialEq)]
    struct TestConfig {
        value: String,
    }

    fn temp_path(name: &str) -> PathBuf {
        let nanos = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_nanos();
        std::env::temp_dir().join(format!("{}-{}-{}.toml", name, std::process::id(), nanos))
    }

    #[test]
    fn returns_default_when_file_is_missing() {
        let path = temp_path("photon-config-missing");
        let config: TestConfig = load_toml_config(&path).unwrap();
        assert_eq!(config, TestConfig::default());
    }

    #[test]
    fn loads_existing_toml_file() {
        let path = temp_path("photon-config-load");
        fs::write(&path, "value = \"hello\"\n").unwrap();

        let config: TestConfig = load_toml_config(&path).unwrap();
        assert_eq!(config.value, "hello");

        let _ = fs::remove_file(path);
    }
}
