use std::fs::File;
use std::path::Path;

use serde::Deserialize;
use tracing::debug;

use crate::error::Error;

// TODO: support more VCS than just "git"?
#[derive(Debug, Deserialize)]
#[non_exhaustive]
pub(crate) struct CargoVcsInfo {
    pub git: GitInfo,
    pub path_in_vcs: Option<String>,
}

#[derive(Debug, Deserialize)]
#[non_exhaustive]
pub(crate) struct GitInfo {
    pub sha1: String,
    #[serde(default)]
    pub dirty: bool,
}

pub(crate) fn vcs_info_from_root<P: AsRef<Path>>(root: P) -> Result<Option<CargoVcsInfo>, Error> {
    let path = root.as_ref().join(".cargo_vcs_info.json");

    debug!("Loading '.cargo_vcs_info.json' from path: {}", path.to_string_lossy());
    let file = match File::open(path) {
        Ok(file) => file,
        Err(err) => {
            if err.kind() == std::io::ErrorKind::NotFound {
                return Ok(None);
            }
            return Err(Error::VcsInfo {
                inner: format!("failed to open file ({err})"),
            });
        },
    };

    let info: CargoVcsInfo = serde_json::from_reader(file).map_err(|err| Error::VcsInfo {
        inner: format!("failed to deserialize JSON ({err})"),
    })?;

    Ok(Some(info))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_deserialize_vcs_info() {
        let contents = std::fs::read_to_string("tests/cargo_vcs_info.json").unwrap();
        let _data: CargoVcsInfo = serde_json::from_str(&contents).unwrap();
    }
}
