use chrono::{DateTime, Duration, Utc};
use serde::{Deserialize, Serialize};

pub static SYNC_AMOUNT_DEFAULT: u32 = 300;
pub static CONCURRENT_DOWNLOADS_DEFAULT: u32 = 24;

#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub backend: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    #[serde(alias = "concurrent_downlaods")]
    pub concurrent_downloads: Option<u32>,
    pub sync_amount: u32,
    #[serde(with = "json_time")]
    pub last_sync: DateTime<Utc>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub keep_articles_days: Option<u64>,
}

impl Default for Config {
    fn default() -> Self {
        Self {
            backend: None,
            sync_amount: SYNC_AMOUNT_DEFAULT,
            concurrent_downloads: Some(CONCURRENT_DOWNLOADS_DEFAULT),
            last_sync: Utc::now() - Duration::try_weeks(1).unwrap(),
            keep_articles_days: None,
        }
    }
}

mod json_time {
    use chrono::{DateTime, Utc};
    use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};

    pub fn time_to_json(t: DateTime<Utc>) -> String {
        t.to_rfc3339()
    }

    pub fn serialize<S: Serializer>(time: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> {
        time_to_json(*time).serialize(serializer)
    }

    pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<DateTime<Utc>, D::Error> {
        let time: String = Deserialize::deserialize(deserializer)?;
        Ok(DateTime::parse_from_rfc3339(&time).map_err(D::Error::custom)?.with_timezone(&Utc))
    }
}
