/* This file will be copied into the folder for generated code. */

use std::ops::{Deref, DerefMut};

use chrono::{TimeZone, Utc};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de, ser};
use time::{self, format_description::well_known::Rfc3339};

#[derive(Clone, Debug)]
pub struct Date(time::Date);

impl Deref for Date {
    type Target = time::Date;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Date {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl Serialize for Date {
    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        s.serialize_str(date_to_rfc3339(self).map_err(ser::Error::custom)?.as_str())
    }
}

impl<'de> Deserialize<'de> for Date {
    fn deserialize<D>(deserializer: D) -> Result<Date, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s: String = String::deserialize(deserializer)?;
        rfc3339_to_date(&s).map_err(de::Error::custom)
    }
}

fn date_to_rfc3339(date: &Date) -> Result<String, &'static str> {
    let date_time = Utc
        .with_ymd_and_hms(
            date.year(),
            date.month() as u32,
            u32::from(date.day()),
            0,
            0,
            0,
        )
        .unwrap();
    let date_time_string = date_time.to_rfc3339();
    let t_ix = date_time_string
        .find('T')
        .ok_or("error serializing Date to RFC 3339 format")?;
    Ok((date_time_string[..t_ix]).to_string())
}

fn rfc3339_to_date(date_str: &str) -> Result<Date, &'static str> {
    Ok(Date(
        time::Date::parse(format!("{date_str}T00:00:00Z").as_str(), &Rfc3339)
            .map_err(|_| "error deserializing Date from RFC 3339 format")?,
    ))
}
