use std::time::Duration;

use newtype::NewType;
use serde::Deserialize;
use serde_with::serde_as;

#[serde_as]
#[derive(NewType, Debug, Clone, PartialEq, Eq, Deserialize, Copy)]
pub struct DurationAsMillis<const N: u64>(#[serde_as(as = "serde_with::DurationMilliSeconds<u64>")] Duration);

impl<const N: u64> Default for DurationAsMillis<N> {
    fn default() -> Self {
        Self(Duration::from_millis(N))
    }
}

impl<const N: u64> From<u64> for DurationAsMillis<N> {
    fn from(millis: u64) -> Self {
        Self(Duration::from_millis(millis))
    }
}

#[serde_as]
#[derive(NewType, Debug, Clone, PartialEq, Eq, Deserialize, Copy)]
pub struct DurationAsSecs<const N: u64>(#[serde_as(as = "serde_with::DurationSeconds<u64>")] Duration);

impl<const N: u64> Default for DurationAsSecs<N> {
    fn default() -> Self {
        Self(Duration::from_secs(N))
    }
}

impl<const N: u64> From<u64> for DurationAsSecs<N> {
    fn from(secs: u64) -> Self {
        Self(Duration::from_secs(secs))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_case_duration_as_mills_deserilize() {
        let d: DurationAsMillis<1500> = serde_json::from_str("123").unwrap();
        assert_eq!(*d, Duration::from_millis(123));
        assert_eq!(d.into_inner(), Duration::from_millis(123));

        assert_eq!(
            *serde_json::from_str::<DurationAsMillis<1500>>("xx").unwrap_or_default(),
            Duration::from_millis(1500)
        );

        assert_eq!(DurationAsMillis::<1500>::from(500u64), 500.into());
    }

    #[test]
    fn test_case_duration_as_secs_deserilize() {
        let d: DurationAsSecs<30> = serde_json::from_str("60").unwrap();
        assert_eq!(*d, Duration::from_secs(60));
        assert_eq!(d.into_inner(), Duration::from_secs(60));

        assert_eq!(
            *serde_json::from_str::<DurationAsSecs<30>>("xx").unwrap_or_default(),
            Duration::from_secs(30)
        );

        assert_eq!(DurationAsSecs::<30>::from(120u64), 120.into());
    }
}
