use std::borrow::Cow;
use std::fmt::Debug;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use ordered_varint::Variable;
use serde::{Deserialize, Serialize};
use crate::key::time::limited::{BonsaiEpoch, UnixEpoch};
use crate::key::{ByteSource, CompositeKind, Key, KeyEncoding, KeyKind, KeyVisitor};
impl<'k> Key<'k> for Duration {
    const CAN_OWN_BYTES: bool = false;
    fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
        let merged = u128::decode_variable(bytes.as_ref()).map_err(|_| TimeError::InvalidValue)?;
        let seconds = u64::try_from(merged >> 30).map_err(|_| TimeError::DeltaNotRepresentable)?;
        let nanos = u32::try_from(merged & (2_u128.pow(30) - 1)).unwrap();
        Ok(Self::new(seconds, nanos))
    }
}
impl KeyEncoding<Self> for Duration {
    type Error = TimeError;
    const LENGTH: Option<usize> = None;
    fn describe<Visitor>(visitor: &mut Visitor)
    where
        Visitor: KeyVisitor,
    {
        visitor.visit_composite(
            CompositeKind::Struct(Cow::Borrowed("std::time::Duration")),
            1,
        );
        visitor.visit_type(KeyKind::Unsigned);
    }
    fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
        let merged = u128::from(self.as_secs()) << 30 | u128::from(self.subsec_nanos());
        Ok(Cow::Owned(merged.to_variable_vec().unwrap()))
    }
}
#[test]
fn duration_key_tests() {
    assert_eq!(
        Duration::ZERO,
        Duration::from_ord_bytes(ByteSource::Borrowed(
            &Duration::ZERO.as_ord_bytes().unwrap()
        ))
        .unwrap()
    );
    assert_eq!(
        Duration::MAX,
        Duration::from_ord_bytes(ByteSource::Borrowed(&Duration::MAX.as_ord_bytes().unwrap()))
            .unwrap()
    );
}
impl<'k> Key<'k> for SystemTime {
    const CAN_OWN_BYTES: bool = false;
    fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
        let since_epoch = Duration::from_ord_bytes(bytes)?;
        UNIX_EPOCH
            .checked_add(since_epoch)
            .ok_or(TimeError::DeltaNotRepresentable)
    }
}
impl KeyEncoding<Self> for SystemTime {
    type Error = TimeError;
    const LENGTH: Option<usize> = None;
    fn describe<Visitor>(visitor: &mut Visitor)
    where
        Visitor: KeyVisitor,
    {
        visitor.visit_composite(
            CompositeKind::Struct(Cow::Borrowed("std::time::SystemTime")),
            1,
        );
        visitor.visit_type(KeyKind::Unsigned);
    }
    fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
        let since_epoch = self.duration_since(UNIX_EPOCH).unwrap();
        match since_epoch.as_ord_bytes()? {
            Cow::Owned(bytes) => Ok(Cow::Owned(bytes)),
            Cow::Borrowed(_) => unreachable!(),
        }
    }
}
#[test]
fn system_time_tests() {
    assert_eq!(
        UNIX_EPOCH,
        SystemTime::from_ord_bytes(ByteSource::Borrowed(&UNIX_EPOCH.as_ord_bytes().unwrap()))
            .unwrap()
    );
    let now = SystemTime::now();
    assert_eq!(
        now,
        SystemTime::from_ord_bytes(ByteSource::Borrowed(&now.as_ord_bytes().unwrap())).unwrap()
    );
}
#[derive(thiserror::Error, Debug)]
#[error("the stored timestamp is outside the allowed range")]
pub struct DeltaNotRepresentable;
#[derive(thiserror::Error, Debug, Clone, Serialize, Deserialize)]
pub enum TimeError {
    #[error("the stored timestamp is outside the allowed range")]
    DeltaNotRepresentable,
    #[error("invalid value")]
    InvalidValue,
}
impl From<DeltaNotRepresentable> for TimeError {
    fn from(_: DeltaNotRepresentable) -> Self {
        Self::DeltaNotRepresentable
    }
}
impl From<std::io::Error> for TimeError {
    fn from(_: std::io::Error) -> Self {
        Self::InvalidValue
    }
}
pub mod limited {
    use std::borrow::Cow;
    use std::fmt::{self, Debug, Display, Write};
    use std::hash::Hash;
    use std::iter;
    use std::marker::PhantomData;
    use std::str::FromStr;
    use std::time::{Duration, SystemTime, UNIX_EPOCH};
    use derive_where::derive_where;
    use ordered_varint::Variable;
    use serde::{Deserialize, Serialize};
    use crate::key::time::TimeError;
    use crate::key::{ByteSource, CompositeKind, Key, KeyEncoding, KeyVisitor};
    #[derive_where(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
    pub struct LimitedResolutionDuration<Resolution: TimeResolution> {
        representation: Resolution::Representation,
        _resolution: PhantomData<Resolution>,
    }
    pub trait TimeResolution: Debug + Send + Sync {
        type Representation: Variable
            + Serialize
            + for<'de> Deserialize<'de>
            + for<'k> Key<'k>
            + Display
            + Hash
            + Eq
            + PartialEq
            + Ord
            + PartialOrd
            + Clone
            + Copy
            + Send
            + Sync
            + Debug
            + Default;
        const FORMAT_SUFFIX: &'static str;
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError>;
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError>;
    }
    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    pub enum SignedDuration {
        Positive(Duration),
        Negative(Duration),
    }
    impl SignedDuration {
        #[must_use]
        pub fn checked_add(self, other: Self) -> Option<Self> {
            match (self, other) {
                (SignedDuration::Positive(a), SignedDuration::Positive(b)) => {
                    a.checked_add(b).map(SignedDuration::Positive)
                }
                (SignedDuration::Negative(a), SignedDuration::Negative(b)) => {
                    a.checked_add(b).map(SignedDuration::Negative)
                }
                (SignedDuration::Positive(a), SignedDuration::Negative(b)) => {
                    if let Some(result) = a.checked_sub(b) {
                        Some(SignedDuration::Positive(result))
                    } else {
                        Some(SignedDuration::Negative(b - a))
                    }
                }
                (SignedDuration::Negative(a), SignedDuration::Positive(b)) => {
                    if let Some(result) = a.checked_sub(b) {
                        Some(SignedDuration::Negative(result))
                    } else {
                        Some(SignedDuration::Positive(b - a))
                    }
                }
            }
        }
    }
    impl<Resolution> LimitedResolutionDuration<Resolution>
    where
        Resolution: TimeResolution,
    {
        pub const fn new(representation: Resolution::Representation) -> Self {
            Self {
                representation,
                _resolution: PhantomData,
            }
        }
        pub const fn representation(&self) -> Resolution::Representation {
            self.representation
        }
    }
    impl<Resolution: TimeResolution> Debug for LimitedResolutionDuration<Resolution> {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "{:?}{}", self.representation, Resolution::FORMAT_SUFFIX)
        }
    }
    impl<Resolution: TimeResolution> Display for LimitedResolutionDuration<Resolution> {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "{}{}", self.representation, Resolution::FORMAT_SUFFIX)
        }
    }
    impl iter::Sum<SignedDuration> for Option<SignedDuration> {
        fn sum<I: Iterator<Item = SignedDuration>>(mut iter: I) -> Self {
            let first = iter.next();
            iter.fold(first, |sum, duration| {
                sum.and_then(|sum| sum.checked_add(duration))
            })
        }
    }
    impl iter::Sum<Self> for SignedDuration {
        fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
            iter.sum::<Option<Self>>().expect("operation overflowed")
        }
    }
    impl<'k, Resolution> Key<'k> for LimitedResolutionDuration<Resolution>
    where
        Resolution: TimeResolution,
    {
        const CAN_OWN_BYTES: bool = false;
        fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
            let representation =
                <Resolution::Representation as Variable>::decode_variable(bytes.as_ref())
                    .map_err(|_| TimeError::InvalidValue)?;
            Ok(Self {
                representation,
                _resolution: PhantomData,
            })
        }
    }
    impl<Resolution> KeyEncoding<Self> for LimitedResolutionDuration<Resolution>
    where
        Resolution: TimeResolution,
    {
        type Error = TimeError;
        const LENGTH: Option<usize> = None;
        fn describe<Visitor>(visitor: &mut Visitor)
        where
            Visitor: KeyVisitor,
        {
            visitor.visit_composite(
                CompositeKind::Struct(Cow::Borrowed(
                    "bonsaidb::core::key::time::LimitedResolutionDuration",
                )),
                1,
            );
            <Resolution::Representation as KeyEncoding>::describe(visitor);
        }
        fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
            self.representation
                .to_variable_vec()
                .map(Cow::Owned)
                .map_err(|_| TimeError::InvalidValue)
        }
    }
    impl<Resolution> Default for LimitedResolutionDuration<Resolution>
    where
        Resolution: TimeResolution,
    {
        fn default() -> Self {
            Self {
                representation: <Resolution::Representation as Default>::default(),
                _resolution: PhantomData,
            }
        }
    }
    impl<Resolution> Serialize for LimitedResolutionDuration<Resolution>
    where
        Resolution: TimeResolution,
    {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: serde::Serializer,
        {
            self.representation.serialize(serializer)
        }
    }
    impl<'de, Resolution> Deserialize<'de> for LimitedResolutionDuration<Resolution>
    where
        Resolution: TimeResolution,
    {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            <Resolution::Representation as Deserialize<'de>>::deserialize(deserializer)
                .map(Self::new)
        }
    }
    impl<Resolution> TryFrom<SignedDuration> for LimitedResolutionDuration<Resolution>
    where
        Resolution: TimeResolution,
    {
        type Error = TimeError;
        fn try_from(duration: SignedDuration) -> Result<Self, Self::Error> {
            Resolution::duration_to_repr(duration).map(|representation| Self {
                representation,
                _resolution: PhantomData,
            })
        }
    }
    impl<Resolution> TryFrom<LimitedResolutionDuration<Resolution>> for SignedDuration
    where
        Resolution: TimeResolution,
    {
        type Error = TimeError;
        fn try_from(value: LimitedResolutionDuration<Resolution>) -> Result<Self, Self::Error> {
            Resolution::repr_to_duration(value.representation)
        }
    }
    impl<Resolution> TryFrom<Duration> for LimitedResolutionDuration<Resolution>
    where
        Resolution: TimeResolution,
    {
        type Error = TimeError;
        fn try_from(duration: Duration) -> Result<Self, Self::Error> {
            Self::try_from(SignedDuration::Positive(duration))
        }
    }
    impl<Resolution> TryFrom<LimitedResolutionDuration<Resolution>> for Duration
    where
        Resolution: TimeResolution,
    {
        type Error = TimeError;
        fn try_from(value: LimitedResolutionDuration<Resolution>) -> Result<Self, Self::Error> {
            match SignedDuration::try_from(value) {
                Ok(SignedDuration::Positive(value)) => Ok(value),
                _ => Err(TimeError::DeltaNotRepresentable),
            }
        }
    }
    impl<Resolution> iter::Sum<LimitedResolutionDuration<Resolution>>
        for Option<LimitedResolutionDuration<Resolution>>
    where
        Resolution: TimeResolution,
    {
        fn sum<I: Iterator<Item = LimitedResolutionDuration<Resolution>>>(mut iter: I) -> Self {
            let first = iter
                .next()
                .and_then(|dur| Resolution::repr_to_duration(dur.representation).ok());
            let duration = iter.fold(first, |sum, dur| {
                sum.and_then(|sum| {
                    Resolution::repr_to_duration(dur.representation)
                        .ok()
                        .and_then(|dur| sum.checked_add(dur))
                })
            });
            duration.and_then(|dur| {
                Resolution::duration_to_repr(dur)
                    .ok()
                    .map(LimitedResolutionDuration::new)
            })
        }
    }
    impl<Resolution> iter::Sum<Self> for LimitedResolutionDuration<Resolution>
    where
        Resolution: TimeResolution,
    {
        fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
            iter.sum::<Option<Self>>().expect("operation overflowed")
        }
    }
    #[test]
    fn limited_resolution_duration_sum() {
        use super::Nanoseconds;
        assert_eq!(
            [
                Nanoseconds::new(1),
                Nanoseconds::new(2),
                Nanoseconds::new(3),
            ]
            .into_iter()
            .sum::<Nanoseconds>(),
            Nanoseconds::new(6)
        );
        assert_eq!(
            [
                Nanoseconds::new(1),
                Nanoseconds::new(2),
                Nanoseconds::new(3),
            ]
            .into_iter()
            .sum::<Option<Nanoseconds>>(),
            Some(Nanoseconds::new(6))
        );
        assert_eq!(
            [Nanoseconds::new(1), Nanoseconds::new(i64::MAX)]
                .into_iter()
                .sum::<Option<Nanoseconds>>(),
            None
        );
        assert_eq!(
            [Nanoseconds::new(i64::MAX), Nanoseconds::new(1)]
                .into_iter()
                .sum::<Option<Nanoseconds>>(),
            None
        );
        assert_eq!(
            [Nanoseconds::new(i64::MIN), Nanoseconds::new(-11)]
                .into_iter()
                .sum::<Option<Nanoseconds>>(),
            None
        );
        assert_eq!(
            [Nanoseconds::new(1), Nanoseconds::new(i64::MIN)]
                .into_iter()
                .sum::<Option<Nanoseconds>>(),
            Some(Nanoseconds::new(i64::MIN + 1))
        );
        assert_eq!(
            [Nanoseconds::new(i64::MIN), Nanoseconds::new(1)]
                .into_iter()
                .sum::<Option<Nanoseconds>>(),
            Some(Nanoseconds::new(i64::MIN + 1))
        );
    }
    #[derive(Debug)]
    pub enum Nanoseconds {}
    const I64_MIN_ABS_AS_U64: u64 = 9_223_372_036_854_775_808;
    impl TimeResolution for Nanoseconds {
        type Representation = i64;
        const FORMAT_SUFFIX: &'static str = "ns";
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
            if let Ok(unsigned) = u64::try_from(value) {
                Ok(SignedDuration::Positive(Duration::from_nanos(unsigned)))
            } else {
                let positive = value
                    .checked_abs()
                    .and_then(|value| u64::try_from(value).ok())
                    .unwrap_or(I64_MIN_ABS_AS_U64);
                Ok(SignedDuration::Negative(Duration::from_nanos(positive)))
            }
        }
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
            match duration {
                SignedDuration::Positive(duration) => {
                    i64::try_from(duration.as_nanos()).map_err(|_| TimeError::DeltaNotRepresentable)
                }
                SignedDuration::Negative(duration) => {
                    let nanos = duration.as_nanos();
                    if let Ok(nanos) = i64::try_from(nanos) {
                        Ok(-nanos)
                    } else if nanos == u128::from(I64_MIN_ABS_AS_U64) {
                        Ok(i64::MIN)
                    } else {
                        Err(TimeError::DeltaNotRepresentable)
                    }
                }
            }
        }
    }
    #[derive(Debug)]
    pub enum Microseconds {}
    impl TimeResolution for Microseconds {
        type Representation = i64;
        const FORMAT_SUFFIX: &'static str = "us";
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
            if let Ok(unsigned) = u64::try_from(value) {
                Ok(SignedDuration::Positive(Duration::from_micros(unsigned)))
            } else {
                let positive = value
                    .checked_abs()
                    .and_then(|value| u64::try_from(value).ok())
                    .unwrap_or(u64::MAX);
                Ok(SignedDuration::Negative(Duration::from_micros(positive)))
            }
        }
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
            match duration {
                SignedDuration::Positive(duration) => i64::try_from(duration.as_micros())
                    .map_err(|_| TimeError::DeltaNotRepresentable),
                SignedDuration::Negative(duration) => {
                    let rounded_up = duration
                        .checked_add(Duration::from_nanos(999))
                        .ok_or(TimeError::DeltaNotRepresentable)?;
                    i64::try_from(rounded_up.as_micros())
                        .map(|repr| -repr)
                        .map_err(|_| TimeError::DeltaNotRepresentable)
                }
            }
        }
    }
    #[derive(Debug)]
    pub enum Milliseconds {}
    impl TimeResolution for Milliseconds {
        type Representation = i64;
        const FORMAT_SUFFIX: &'static str = "ms";
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
            if let Ok(unsigned) = u64::try_from(value) {
                Ok(SignedDuration::Positive(Duration::from_millis(unsigned)))
            } else {
                let positive = value
                    .checked_abs()
                    .and_then(|value| u64::try_from(value).ok())
                    .unwrap_or(u64::MAX);
                Ok(SignedDuration::Negative(Duration::from_millis(positive)))
            }
        }
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
            match duration {
                SignedDuration::Positive(duration) => i64::try_from(duration.as_millis())
                    .map_err(|_| TimeError::DeltaNotRepresentable),
                SignedDuration::Negative(duration) => {
                    let rounded_up = duration
                        .checked_add(Duration::from_nanos(999_999))
                        .ok_or(TimeError::DeltaNotRepresentable)?;
                    i64::try_from(rounded_up.as_millis())
                        .map(|repr| -repr)
                        .map_err(|_| TimeError::DeltaNotRepresentable)
                }
            }
        }
    }
    #[derive(Debug)]
    pub enum Seconds {}
    impl TimeResolution for Seconds {
        type Representation = i64;
        const FORMAT_SUFFIX: &'static str = "s";
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
            if let Ok(unsigned) = u64::try_from(value) {
                Ok(SignedDuration::Positive(Duration::from_secs(unsigned)))
            } else {
                let positive = value
                    .checked_abs()
                    .and_then(|value| u64::try_from(value).ok())
                    .unwrap_or(u64::MAX);
                Ok(SignedDuration::Negative(Duration::from_secs(positive)))
            }
        }
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
            match duration {
                SignedDuration::Positive(duration) => {
                    i64::try_from(duration.as_secs()).map_err(|_| TimeError::DeltaNotRepresentable)
                }
                SignedDuration::Negative(duration) => {
                    let rounded_up = duration
                        .checked_add(Duration::from_nanos(999_999_999))
                        .ok_or(TimeError::DeltaNotRepresentable)?;
                    i64::try_from(rounded_up.as_secs())
                        .map(|repr| -repr)
                        .map_err(|_| TimeError::DeltaNotRepresentable)
                }
            }
        }
    }
    #[derive(Debug)]
    pub enum Minutes {}
    impl TimeResolution for Minutes {
        type Representation = i32;
        const FORMAT_SUFFIX: &'static str = "m";
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
            if let Ok(unsigned) = u64::try_from(value) {
                Ok(SignedDuration::Positive(Duration::from_secs(unsigned * 60)))
            } else {
                let positive = u64::try_from(i64::from(value).abs()).unwrap();
                Ok(SignedDuration::Negative(Duration::from_secs(positive * 60)))
            }
        }
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
            match duration {
                SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / 60)
                    .map_err(|_| TimeError::DeltaNotRepresentable),
                SignedDuration::Negative(duration) => i32::try_from((duration.as_secs() + 59) / 60)
                    .map(|repr| -repr)
                    .map_err(|_| TimeError::DeltaNotRepresentable),
            }
        }
    }
    #[derive(Debug)]
    pub enum Hours {}
    impl TimeResolution for Hours {
        type Representation = i32;
        const FORMAT_SUFFIX: &'static str = "h";
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
            if let Ok(unsigned) = u64::try_from(value) {
                Ok(SignedDuration::Positive(Duration::from_secs(
                    unsigned * 60 * 60,
                )))
            } else {
                let positive = u64::try_from(i64::from(value).abs()).unwrap();
                Ok(SignedDuration::Negative(Duration::from_secs(
                    positive * 60 * 60,
                )))
            }
        }
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
            const FACTOR: u64 = 60 * 60;
            match duration {
                SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / FACTOR)
                    .map_err(|_| TimeError::DeltaNotRepresentable),
                SignedDuration::Negative(duration) => {
                    i32::try_from((duration.as_secs() + FACTOR - 1) / FACTOR)
                        .map(|repr| -repr)
                        .map_err(|_| TimeError::DeltaNotRepresentable)
                }
            }
        }
    }
    #[derive(Debug)]
    pub enum Days {}
    impl TimeResolution for Days {
        type Representation = i32;
        const FORMAT_SUFFIX: &'static str = "d";
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
            if let Ok(unsigned) = u64::try_from(value) {
                Ok(SignedDuration::Positive(Duration::from_secs(
                    unsigned * 24 * 60 * 60,
                )))
            } else {
                let positive = u64::try_from(i64::from(value).abs()).unwrap();
                Ok(SignedDuration::Negative(Duration::from_secs(
                    positive * 24 * 60 * 60,
                )))
            }
        }
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
            const FACTOR: u64 = 24 * 60 * 60;
            match duration {
                SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / FACTOR)
                    .map_err(|_| TimeError::DeltaNotRepresentable),
                SignedDuration::Negative(duration) => {
                    Ok(i32::try_from((duration.as_secs() + FACTOR - 1) / FACTOR)
                        .map_or(i32::MIN, |repr| -repr))
                }
            }
        }
    }
    #[derive(Debug)]
    pub enum Weeks {}
    impl TimeResolution for Weeks {
        type Representation = i32;
        const FORMAT_SUFFIX: &'static str = "w";
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
            if let Ok(unsigned) = u64::try_from(value) {
                Ok(SignedDuration::Positive(Duration::from_secs(
                    unsigned * 7 * 24 * 60 * 60,
                )))
            } else {
                let positive = u64::try_from(i64::from(value).abs()).unwrap();
                Ok(SignedDuration::Negative(Duration::from_secs(
                    positive * 7 * 24 * 60 * 60,
                )))
            }
        }
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
            const FACTOR: u64 = 7 * 24 * 60 * 60;
            match duration {
                SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / FACTOR)
                    .map_err(|_| TimeError::DeltaNotRepresentable),
                SignedDuration::Negative(duration) => {
                    i32::try_from((duration.as_secs() + FACTOR - 1) / FACTOR)
                        .map(|repr| -repr)
                        .map_err(|_| TimeError::DeltaNotRepresentable)
                }
            }
        }
    }
    #[test]
    fn limited_resolution_duration_tests() {
        fn test_limited<Resolution: TimeResolution>(
            duration: Duration,
            expected_step: Resolution::Representation,
        ) {
            let limited = LimitedResolutionDuration::<Resolution>::try_from(duration).unwrap();
            assert_eq!(limited.representation, expected_step);
            let encoded = limited.as_ord_bytes().unwrap();
            println!("Encoded {limited:?} to {} bytes", encoded.len());
            let decoded =
                LimitedResolutionDuration::from_ord_bytes(ByteSource::Borrowed(&encoded)).unwrap();
            assert_eq!(limited, decoded);
        }
        fn test_eq_limited<Resolution: TimeResolution>(
            duration: Duration,
            expected_step: Resolution::Representation,
        ) {
            test_limited::<Resolution>(duration, expected_step);
            let limited = LimitedResolutionDuration::<Resolution>::try_from(duration).unwrap();
            assert_eq!(duration, Duration::try_from(limited).unwrap());
        }
        let truncating_seconds = 7 * 24 * 60 * 60 + 24 * 60 * 60 + 60 * 60 + 60 + 1;
        let truncating = Duration::new(u64::try_from(truncating_seconds).unwrap(), 987_654_321);
        test_limited::<Weeks>(truncating, 1);
        test_limited::<Days>(truncating, 8);
        test_limited::<Hours>(truncating, 8 * 24 + 1);
        test_limited::<Minutes>(truncating, 8 * 24 * 60 + 60 + 1);
        test_limited::<Seconds>(truncating, 8 * 24 * 60 * 60 + 60 * 60 + 60 + 1);
        test_limited::<Milliseconds>(truncating, truncating_seconds * 1_000 + 987);
        test_limited::<Microseconds>(truncating, truncating_seconds * 1_000_000 + 987_654);
        let forty_two_days = Duration::from_secs(42 * 24 * 60 * 60);
        test_eq_limited::<Weeks>(forty_two_days, 6);
        test_eq_limited::<Days>(forty_two_days, 42);
        test_eq_limited::<Hours>(forty_two_days, 42 * 24);
        test_eq_limited::<Minutes>(forty_two_days, 42 * 24 * 60);
        test_eq_limited::<Seconds>(forty_two_days, 42 * 24 * 60 * 60);
        test_eq_limited::<Milliseconds>(forty_two_days, 42 * 24 * 60 * 60 * 1_000);
        test_eq_limited::<Microseconds>(forty_two_days, 42 * 24 * 60 * 60 * 1_000_000);
    }
    #[derive_where(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
    pub struct LimitedResolutionTimestamp<Resolution: TimeResolution, Epoch: TimeEpoch>(
        LimitedResolutionDuration<Resolution>,
        PhantomData<Epoch>,
    );
    impl<Resolution, Epoch> Default for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        fn default() -> Self {
            Self(LimitedResolutionDuration::default(), PhantomData)
        }
    }
    impl<Resolution, Epoch> Serialize for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: serde::Serializer,
        {
            self.0.serialize(serializer)
        }
    }
    impl<'de, Resolution, Epoch> Deserialize<'de> for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            LimitedResolutionDuration::deserialize(deserializer)
                .map(|duration| Self(duration, PhantomData))
        }
    }
    pub trait TimeEpoch: Sized + Send + Sync {
        fn name() -> &'static str;
        fn epoch_offset() -> Duration;
    }
    impl<Resolution, Epoch> LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        #[must_use]
        pub fn now() -> Self {
            Self::try_from(SystemTime::now()).expect("now should always be representable")
        }
        pub fn duration_since(
            &self,
            other: &impl AnyTimestamp,
        ) -> Result<Option<Duration>, TimeError> {
            let self_delta = self.duration_since_unix_epoch()?;
            let other_delta = other.duration_since_unix_epoch()?;
            Ok(self_delta.checked_sub(other_delta))
        }
        pub fn duration_between(&self, other: &impl AnyTimestamp) -> Result<Duration, TimeError> {
            let self_delta = self.duration_since_unix_epoch()?;
            let other_delta = other.duration_since_unix_epoch()?;
            if self_delta < other_delta {
                Ok(other_delta - self_delta)
            } else {
                Ok(self_delta - other_delta)
            }
        }
        pub const fn representation(&self) -> Resolution::Representation {
            self.0.representation()
        }
        pub fn from_representation(representation: Resolution::Representation) -> Self {
            Self::from(LimitedResolutionDuration::new(representation))
        }
        pub fn to_timestamp_string(&self) -> Result<String, TimeError> {
            let mut string = String::new();
            self.display(&mut string).map(|_| string)
        }
        fn display(&self, f: &mut impl Write) -> Result<(), TimeError> {
            let since_epoch = self.duration_since_unix_epoch()?;
            write!(f, "{}", since_epoch.as_secs()).map_err(|_| TimeError::InvalidValue)?;
            if since_epoch.subsec_nanos() > 0 {
                if since_epoch.subsec_nanos() % 1_000_000 == 0 {
                    write!(f, ".{:03}", since_epoch.subsec_millis())
                        .map_err(|_| TimeError::InvalidValue)
                } else if since_epoch.subsec_nanos() % 1_000 == 0 {
                    write!(f, ".{:06}", since_epoch.subsec_micros())
                        .map_err(|_| TimeError::InvalidValue)
                } else {
                    write!(f, ".{:09}", since_epoch.subsec_nanos())
                        .map_err(|_| TimeError::InvalidValue)
                }
            } else {
                Ok(())
            }
        }
    }
    pub trait AnyTimestamp {
        fn duration_since_unix_epoch(&self) -> Result<Duration, TimeError>;
    }
    impl AnyTimestamp for SystemTime {
        fn duration_since_unix_epoch(&self) -> Result<Duration, TimeError> {
            Ok(self.duration_since(UNIX_EPOCH).unwrap())
        }
    }
    impl<Resolution, Epoch> AnyTimestamp for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        fn duration_since_unix_epoch(&self) -> Result<Duration, TimeError> {
            let relative_offset = Resolution::repr_to_duration(self.0.representation)?;
            match relative_offset {
                SignedDuration::Positive(offset) => Epoch::epoch_offset()
                    .checked_add(offset)
                    .ok_or(TimeError::DeltaNotRepresentable),
                SignedDuration::Negative(offset) => Epoch::epoch_offset()
                    .checked_sub(offset)
                    .ok_or(TimeError::DeltaNotRepresentable),
            }
        }
    }
    impl<Resolution, Epoch> Debug for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "LimitedResolutionTimestamp({self})")
        }
    }
    impl<Resolution, Epoch> Display for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            self.display(f).or_else(|_| Display::fmt(&self.0, f))
        }
    }
    impl<Resolution, Epoch> FromStr for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        type Err = TimeError;
        fn from_str(s: &str) -> Result<Self, Self::Err> {
            let mut parts = s.split('.');
            let seconds = parts.next().ok_or(TimeError::InvalidValue)?;
            let seconds = seconds
                .parse::<u64>()
                .map_err(|_| TimeError::InvalidValue)?;
            let duration = if let Some(subseconds_str) = parts.next() {
                if subseconds_str.len() > 9 || parts.next().is_some() {
                    return Err(TimeError::InvalidValue);
                }
                let subseconds = subseconds_str
                    .parse::<u32>()
                    .map_err(|_| TimeError::InvalidValue)?;
                let nanos =
                    subseconds * 10_u32.pow(u32::try_from(9 - subseconds_str.len()).unwrap());
                Duration::new(seconds, nanos)
            } else {
                Duration::from_secs(seconds)
            };
            let epoch = Epoch::epoch_offset();
            let duration = if duration < epoch {
                SignedDuration::Negative(epoch - duration)
            } else {
                SignedDuration::Positive(duration - epoch)
            };
            Ok(Self::from(
                LimitedResolutionDuration::<Resolution>::try_from(duration)?,
            ))
        }
    }
    #[test]
    fn timestamp_parse_tests() {
        fn test_roundtrip_parsing<Resolution: TimeResolution>() {
            let original = LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::now();
            let unix_timestamp = original.to_string();
            let parsed = unix_timestamp.parse().unwrap();
            assert_eq!(
                original, parsed,
                "{original} produced {unix_timestamp}, but parsed {parsed}"
            );
        }
        test_roundtrip_parsing::<Weeks>();
        test_roundtrip_parsing::<Days>();
        test_roundtrip_parsing::<Minutes>();
        test_roundtrip_parsing::<Seconds>();
        test_roundtrip_parsing::<Milliseconds>();
        test_roundtrip_parsing::<Microseconds>();
        test_roundtrip_parsing::<Nanoseconds>();
    }
    impl<'k, Resolution, Epoch> Key<'k> for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        const CAN_OWN_BYTES: bool = false;
        fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
            let duration = LimitedResolutionDuration::<Resolution>::from_ord_bytes(bytes)?;
            Ok(Self::from(duration))
        }
    }
    impl<Resolution, Epoch> KeyEncoding<Self> for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        type Error = TimeError;
        const LENGTH: Option<usize> = None;
        fn describe<Visitor>(visitor: &mut Visitor)
        where
            Visitor: KeyVisitor,
        {
            visitor.visit_composite(
                CompositeKind::Struct(Cow::Borrowed(
                    "bonsaidb::core::key::time::LimitedResolutionTimestamp",
                )),
                1,
            );
            visitor.visit_composite_attribute("epoch", Epoch::epoch_offset().as_nanos());
            <Resolution::Representation as KeyEncoding>::describe(visitor);
        }
        fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
            self.0.as_ord_bytes()
        }
    }
    impl<Resolution, Epoch> From<LimitedResolutionDuration<Resolution>>
        for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        fn from(duration: LimitedResolutionDuration<Resolution>) -> Self {
            Self(duration, PhantomData)
        }
    }
    impl<Resolution, Epoch> From<LimitedResolutionTimestamp<Resolution, Epoch>>
        for LimitedResolutionDuration<Resolution>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        fn from(time: LimitedResolutionTimestamp<Resolution, Epoch>) -> Self {
            time.0
        }
    }
    impl<Resolution, Epoch> TryFrom<SystemTime> for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        type Error = TimeError;
        fn try_from(time: SystemTime) -> Result<Self, TimeError> {
            let epoch = UNIX_EPOCH
                .checked_add(Epoch::epoch_offset())
                .ok_or(TimeError::DeltaNotRepresentable)?;
            match time.duration_since(epoch) {
                Ok(duration) => {
                    LimitedResolutionDuration::try_from(SignedDuration::Positive(duration))
                        .map(Self::from)
                }
                Err(_) => match epoch.duration_since(time) {
                    Ok(duration) => {
                        LimitedResolutionDuration::try_from(SignedDuration::Negative(duration))
                            .map(Self::from)
                    }
                    Err(_) => Err(TimeError::DeltaNotRepresentable),
                },
            }
        }
    }
    impl<Resolution, Epoch> TryFrom<LimitedResolutionTimestamp<Resolution, Epoch>> for SystemTime
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        type Error = TimeError;
        fn try_from(
            time: LimitedResolutionTimestamp<Resolution, Epoch>,
        ) -> Result<Self, TimeError> {
            let since_epoch = SignedDuration::try_from(time.0)?;
            let epoch = UNIX_EPOCH
                .checked_add(Epoch::epoch_offset())
                .ok_or(TimeError::DeltaNotRepresentable)?;
            let time = match since_epoch {
                SignedDuration::Positive(since_epoch) => epoch.checked_add(since_epoch),
                SignedDuration::Negative(since_epoch) => epoch.checked_sub(since_epoch),
            };
            time.ok_or(TimeError::DeltaNotRepresentable)
        }
    }
    pub struct UnixEpoch;
    impl TimeEpoch for UnixEpoch {
        fn name() -> &'static str {
            "Unix"
        }
        fn epoch_offset() -> Duration {
            Duration::ZERO
        }
    }
    pub struct BonsaiEpoch;
    impl BonsaiEpoch {
        const EPOCH: Duration = Duration::new(1_931_747_507, 0);
    }
    impl TimeEpoch for BonsaiEpoch {
        fn name() -> &'static str {
            "BonsaiDb"
        }
        fn epoch_offset() -> Duration {
            Self::EPOCH
        }
    }
    #[test]
    fn limited_resolution_timestamp_tests() {
        fn test_resolution<Resolution: TimeResolution>(resolution: Duration) {
            let now_in_seconds = LimitedResolutionTimestamp::<Resolution, UnixEpoch>::now();
            let as_system = SystemTime::try_from(now_in_seconds).unwrap();
            let as_limited =
                LimitedResolutionTimestamp::<Resolution, UnixEpoch>::try_from(as_system).unwrap();
            assert_eq!(as_limited, now_in_seconds);
            let now_in_seconds = LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::now();
            let as_system = SystemTime::try_from(now_in_seconds).unwrap();
            let as_limited =
                LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(as_system).unwrap();
            assert_eq!(as_limited, now_in_seconds);
            let slightly_before_epoch = UNIX_EPOCH + BonsaiEpoch::EPOCH
                - Duration::from_nanos(u64::try_from(resolution.as_nanos() / 2).unwrap());
            let unix_epoch_in_recent =
                LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(
                    slightly_before_epoch,
                )
                .unwrap();
            let as_system = SystemTime::try_from(unix_epoch_in_recent).unwrap();
            let as_limited =
                LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(as_system).unwrap();
            assert!(
                slightly_before_epoch
                    .duration_since(as_system)
                    .expect("timestamp should have been trunctated towards MIN")
                    < resolution
            );
            assert_eq!(as_limited, unix_epoch_in_recent);
            let slightly_after_epoch = UNIX_EPOCH
                + BonsaiEpoch::EPOCH
                + Duration::from_nanos(u64::try_from(resolution.as_nanos() / 2).unwrap());
            let unix_epoch_in_recent =
                LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(
                    slightly_after_epoch,
                )
                .unwrap();
            let as_system = SystemTime::try_from(unix_epoch_in_recent).unwrap();
            println!("{slightly_after_epoch:?} converted to {unix_epoch_in_recent} and back as {as_system:?}");
            let as_limited =
                LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(as_system).unwrap();
            assert!(
                slightly_after_epoch
                    .duration_since(as_system)
                    .expect("timestamp should have been truncated towards 0")
                    < resolution
            );
            assert_eq!(as_limited, unix_epoch_in_recent);
        }
        test_resolution::<Weeks>(Duration::from_secs(7 * 24 * 60 * 60));
        test_resolution::<Days>(Duration::from_secs(24 * 60 * 60));
        test_resolution::<Hours>(Duration::from_secs(60 * 60));
        test_resolution::<Minutes>(Duration::from_secs(60));
        test_resolution::<Seconds>(Duration::from_secs(1));
        test_resolution::<Milliseconds>(Duration::from_millis(1));
        test_resolution::<Microseconds>(Duration::from_micros(1));
        test_resolution::<Nanoseconds>(Duration::from_nanos(1));
    }
    #[test]
    fn serialization_tests() {
        fn test_serialization<Resolution: TimeResolution>() {
            let original = LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::now();
            let serialized = pot::to_vec(&original).unwrap();
            let deserialized = pot::from_slice(&serialized).unwrap();
            assert_eq!(original, deserialized);
        }
        test_serialization::<Weeks>();
        test_serialization::<Days>();
        test_serialization::<Hours>();
        test_serialization::<Minutes>();
        test_serialization::<Seconds>();
        test_serialization::<Milliseconds>();
        test_serialization::<Microseconds>();
        test_serialization::<Nanoseconds>();
    }
}
pub type Weeks = limited::LimitedResolutionDuration<limited::Weeks>;
pub type Days = limited::LimitedResolutionDuration<limited::Days>;
pub type Hours = limited::LimitedResolutionDuration<limited::Hours>;
pub type Minutes = limited::LimitedResolutionDuration<limited::Minutes>;
pub type Seconds = limited::LimitedResolutionDuration<limited::Seconds>;
pub type Milliseconds = limited::LimitedResolutionDuration<limited::Milliseconds>;
pub type Microseconds = limited::LimitedResolutionDuration<limited::Microseconds>;
pub type Nanoseconds = limited::LimitedResolutionDuration<limited::Nanoseconds>;
pub type WeeksSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Weeks, UnixEpoch>;
pub type DaysSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Days, UnixEpoch>;
pub type HoursSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Hours, UnixEpoch>;
pub type MinutesSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Minutes, UnixEpoch>;
pub type SecondsSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Seconds, UnixEpoch>;
pub type MillisecondsSinceUnixEpoch =
    limited::LimitedResolutionTimestamp<limited::Milliseconds, UnixEpoch>;
pub type MicrosecondsSinceUnixEpoch =
    limited::LimitedResolutionTimestamp<limited::Microseconds, UnixEpoch>;
pub type NanosecondsSinceUnixEpoch =
    limited::LimitedResolutionTimestamp<limited::Nanoseconds, UnixEpoch>;
pub type TimestampAsWeeks = limited::LimitedResolutionTimestamp<limited::Weeks, BonsaiEpoch>;
pub type TimestampAsDays = limited::LimitedResolutionTimestamp<limited::Days, BonsaiEpoch>;
pub type TimestampAsHours = limited::LimitedResolutionTimestamp<limited::Hours, BonsaiEpoch>;
pub type TimestampAsMinutes = limited::LimitedResolutionTimestamp<limited::Minutes, BonsaiEpoch>;
pub type TimestampAsSeconds = limited::LimitedResolutionTimestamp<limited::Seconds, BonsaiEpoch>;
pub type TimestampAsMilliseconds =
    limited::LimitedResolutionTimestamp<limited::Milliseconds, BonsaiEpoch>;
pub type TimestampAsMicroseconds =
    limited::LimitedResolutionTimestamp<limited::Microseconds, BonsaiEpoch>;
pub type TimestampAsNanoseconds =
    limited::LimitedResolutionTimestamp<limited::Nanoseconds, BonsaiEpoch>;