#[cfg(feature = "dates")]
use chrono::{DateTime, Duration, NaiveDate, Utc};

#[cfg(feature = "dates")]
pub fn now() -> DateTime<Utc> {
    Utc::now()
}

#[cfg(feature = "dates")]
pub fn today() -> NaiveDate {
    Utc::now().date_naive()
}

#[cfg(feature = "dates")]
pub fn yesterday() -> NaiveDate {
    (Utc::now() - Duration::days(1)).date_naive()
}

#[cfg(feature = "dates")]
pub fn tomorrow() -> NaiveDate {
    (Utc::now() + Duration::days(1)).date_naive()
}

#[cfg(feature = "dates")]
pub fn format_date(dt: &DateTime<Utc>, fmt: &str) -> String {
    dt.format(fmt).to_string()
}

#[cfg(feature = "dates")]
pub fn parse_date(s: &str, fmt: &str) -> Result<DateTime<Utc>, crate::errors::RokError> {
    NaiveDate::parse_from_str(s, fmt)
        .map(|d| d.and_hms_opt(0, 0, 0).unwrap().and_utc())
        .map_err(|e| crate::errors::RokError::InvalidDate(e.to_string()))
}

#[cfg(feature = "dates")]
pub fn diff_days(a: &NaiveDate, b: &NaiveDate) -> i64 {
    (*a - *b).num_days()
}

#[cfg(feature = "dates")]
pub fn human_diff(dt: &DateTime<Utc>) -> String {
    let now = Utc::now();
    let diff = now.signed_duration_since(*dt);

    if diff.num_seconds() < 0 {
        let abs = -diff;
        if abs.num_days() > 0 {
            return format!("in {} days", abs.num_days());
        }
        if abs.num_hours() > 0 {
            return format!("in {} hours", abs.num_hours());
        }
        if abs.num_minutes() > 0 {
            return format!("in {} minutes", abs.num_minutes());
        }
        return "in a few seconds".to_string();
    }

    if diff.num_days() > 0 {
        return format!("{} days ago", diff.num_days());
    }
    if diff.num_hours() > 0 {
        return format!("{} hours ago", diff.num_hours());
    }
    if diff.num_minutes() > 0 {
        return format!("{} minutes ago", diff.num_minutes());
    }
    "a few seconds ago".to_string()
}

#[cfg(feature = "dates")]
pub fn add_days(dt: &NaiveDate, days: i64) -> NaiveDate {
    *dt + Duration::days(days)
}

#[cfg(feature = "dates")]
pub fn add_hours(dt: &DateTime<Utc>, hours: i64) -> DateTime<Utc> {
    *dt + Duration::hours(hours)
}

#[cfg(feature = "dates")]
#[cfg(test)]
mod tests {
    use super::*;
    use chrono::Datelike;

    #[test]
    fn test_now() {
        let n = now();
        assert!(n.timestamp() > 0);
    }

    #[test]
    fn test_today() {
        let t = today();
        assert!(t.year() > 2020);
    }

    #[test]
    fn test_diff_days() {
        let a = NaiveDate::from_ymd_opt(2025, 1, 10).unwrap();
        let b = NaiveDate::from_ymd_opt(2025, 1, 5).unwrap();
        assert_eq!(diff_days(&a, &b), 5);
    }

    #[test]
    fn test_add_days() {
        let d = NaiveDate::from_ymd_opt(2025, 1, 1).unwrap();
        let result = add_days(&d, 5);
        assert_eq!(result.day(), 6);
    }

    #[test]
    fn test_add_hours() {
        let dt = Utc::now();
        let result = add_hours(&dt, 24);
        assert!(result > dt);
    }
}
