use serde::{Serialize, Deserialize, Deserializer};
use std::fmt;
use rand::{thread_rng, Rng};
use chrono::prelude::{DateTime, Utc, NaiveDate, Datelike};

/// ID
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Hash)]
pub struct Id(pub u64);

impl From<Id> for String {
    fn from(val: Id) -> Self {
        format!("{:x}", val.0)
    }
}
impl fmt::Display for Id {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

pub fn generate_id() -> Id {
    Id(thread_rng().gen())
}


pub fn parse_date_iso(inp: &str) -> Option<DateTime<Utc>> {
    let date = NaiveDate::parse_from_str(inp, "%Y-%m-%d").ok()?;
    Some(DateTime::<Utc>::from_naive_utc_and_offset(
        date.and_hms_opt(0, 0, 0).unwrap(),
        Utc
    ))
}

pub fn parse_datetime_american(inp: &str) -> Option<DateTime<Utc>> {
    let date = NaiveDate::parse_from_str(inp, "%m/%d/%Y").ok()?;
    Some(DateTime::<Utc>::from_naive_utc_and_offset(
        date.and_hms_opt(0, 0, 0).unwrap(),
        Utc
    ))
}

pub fn parse_datetime_french(inp: &str) -> Option<DateTime<Utc>> {
    let date = NaiveDate::parse_from_str(inp, "%d/%m/%Y").ok()?;
    Some(DateTime::<Utc>::from_naive_utc_and_offset(
        date.and_hms_opt(0, 0, 0).unwrap(),
        Utc
    ))
}

pub fn parse_normalize_phone(inp: String) -> Option<String> {
    let parsed = match phonenumber::parse(
        Some(phonenumber::country::Id::FR), inp
    ) {
        Ok(r) => r,
        Err(_e) => {
            return None;
        }
    };

    Some(parsed.to_string())
}

pub fn complete_date(inp: NaiveDate) -> DateTime<Utc> {
    DateTime::<Utc>::from_naive_utc_and_offset(
        inp.and_hms_opt(0, 0, 0).unwrap(),
        Utc
    )
}

pub fn normalize_str(subject: String) -> String {
    subject.trim().replace('\n', ";").to_string()
}

/// remove year precision to comply with GDPR eu rules
pub fn parse_and_get_birthday_year(raw_date: String) -> Option<u32> {
    let d_res = NaiveDate::parse_from_str(raw_date.trim(), "%d/%m/%Y");
    let d = d_res.ok()?;
    d.year().try_into().ok()
}

pub fn capitalize(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
    }
}

/// normalisation d'un prénom
pub fn normalize_first_name(subject: String) -> String {
    subject
        .trim()
        .to_lowercase()
        .replace(' ', "-")
        .split('-')
        .map(capitalize)
        .collect::<Vec<String>>()
        .join("-")
}

pub fn normalize_last_name(subject: String) -> String {
    subject
        .to_uppercase()
}



/// https://serde.rs/field-attrs.html
pub fn deserialize_datetime<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
where
    D: Deserializer<'de>,
{
    let s = String::deserialize(deserializer)?;
    DateTime::parse_from_rfc3339(&s)
        .map_err(serde::de::Error::custom)
        .map(|dt| dt.with_timezone(&Utc))
}

pub fn deserialize_date<'de, D>(deserializer: D) -> Result<NaiveDate, D::Error>
where
    D: Deserializer<'de>,
{
    let s = String::deserialize(deserializer)?;
    NaiveDate::parse_from_str(&s, "%Y-%m-%d")
        .map_err(serde::de::Error::custom)
}

pub fn deserialize_json_list<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where
    D: Deserializer<'de>,
{
    let s = String::deserialize(deserializer)?;
    serde_json::from_str(&s).map_err(serde::de::Error::custom)
}