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

use serde::Deserialize;

#[derive(Deserialize)]
pub struct Config {
    pub influxdb: InfluxDbConfig,
}

impl Config {
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Config, ConfigError> {
        let file = fs::read(path)?;
        let config = toml::from_slice::<Config>(&file)?;
        config.validate()?;
        Ok(config)
    }

    fn validate(&self) -> Result<(), ConfigError> {
        self.influxdb.validate()?;
        Ok(())
    }
}

#[derive(Deserialize)]
pub struct InfluxDbConfig {
    #[serde(default)]
    pub enabled: bool,
    #[serde(default)]
    pub address: String,
    #[serde(default)]
    pub user: String,
    #[serde(default)]
    pub password: String,
}

impl InfluxDbConfig {
    fn validate(&self) -> Result<(), ConfigError> {
        if (self.user != "") != (self.password != "") {
            return Err(ConfigError::Settings(
                "need to specify both InfluxDB user and password".to_owned(),
            ));
        }
        Ok(())
    }
}

impl Default for InfluxDbConfig {
    fn default() -> InfluxDbConfig {
        InfluxDbConfig {
            enabled: false,
            address: "http://localhost:8086".to_owned(),
            user: "".to_owned(),
            password: "".to_owned(),
        }
    }
}

#[derive(thiserror::Error, Debug)]
pub enum ConfigError {
    #[error("I/O error")]
    Io(#[from] std::io::Error),
    #[error("Parser error")]
    Parser(#[from] toml::de::Error),
    #[error("Invalid settings")]
    Settings(String),
}
