use std::net::SocketAddr;
use std::path::PathBuf;
use std::fs;

use serde::{Deserialize, Deserializer};
use chrono::Duration;
use toml;


#[derive(Debug, Deserialize)]
pub struct Config {
    pub dns: DnsConfig,
    pub web_app: WebAppConfig,
}

#[derive(Debug, Deserialize)]
pub struct DnsConfig {
    pub server: SocketAddr
}

#[derive(Debug, Deserialize)]
pub struct WebAppConfig {
    #[serde(deserialize_with = "from_base64")]
    pub secret: Vec<u8>,
    #[serde(deserialize_with = "from_duration")]
    pub token_duration: Duration,
}

fn from_base64<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
    where D: Deserializer<'de>
{
    use serde::de::Error;
    String::deserialize(deserializer)
        .and_then(|string| base64::decode(&string).map_err(|err| Error::custom(err.to_string())))
}

fn from_duration<'de, D>(deserializer: D) -> Result<Duration, D::Error>
    where D: Deserializer<'de>
{
    use serde::de::Error;
    String::deserialize(deserializer)
        .and_then(|string| humantime::parse_duration(&string).map_err(|err| Error::custom(err.to_string())))
        .and_then(|duration| Duration::from_std(duration).map_err(|err| Error::custom(err.to_string())))
}

pub fn load(file_name: PathBuf) -> Config {
    let file_content = fs::read_to_string(file_name).expect("could not read config file");
    toml::from_str(&file_content).expect("could not parse config file")
}