use crate::manifest_mode::{ManifestMode, ManifestShExSyntaxMode};
use serde::{Deserialize, Serialize};
use std::{fs, io};
use thiserror::Error;

#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct Config {
    pub manifest_mode: ManifestMode,
    pub excluded_entries: Vec<String>,
    pub single_entries: Option<Vec<String>>,
    pub manifest_shex_syntax_mode: Option<ManifestShExSyntaxMode>,
}

#[derive(Error, Debug)]
pub enum ConfigError {
    #[error("Reading path {path_name:?} error: {error:?}")]
    ReadingConfigError { path_name: String, error: io::Error },

    #[error("Reading TOML from {path_name:?}. Error: {error:?}")]
    TomlError { path_name: String, error: toml::de::Error },
}

impl Config {
    pub fn from_file(file_name: &str) -> Result<Config, ConfigError> {
        let config_str = fs::read_to_string(file_name).map_err(|e| ConfigError::ReadingConfigError {
            path_name: file_name.to_string(),
            error: e,
        })?;
        toml::from_str::<Config>(&config_str).map_err(|e| ConfigError::TomlError {
            path_name: file_name.to_string(),
            error: e,
        })
    }

    pub fn manifest_shex_syntax_mode(&self) -> ManifestShExSyntaxMode {
        self.manifest_shex_syntax_mode.unwrap_or(ManifestShExSyntaxMode::ShExC)
    }
}

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

    #[test]
    fn parse_example() {
        let sample_str = r#"
         { "manifest_mode": "Schemas",
           "excluded_entries": ["entry1", "entry2"]
         }
        "#;
        let sample = Config {
            manifest_mode: ManifestMode::Schemas,
            excluded_entries: vec!["entry1".to_string(), "entry2".to_string()],
            single_entries: None,
            manifest_shex_syntax_mode: None,
        };
        let sample_parsed = serde_json::from_str::<Config>(sample_str).unwrap();
        assert_eq!(sample_parsed, sample);
    }
}
