///|
/// The greatest non-negative duration accepted by MoonCache.
pub const MAX_DELTA_SECONDS : Int64 = 9_223_372_036_854_775_807

///|
/// A non-negative instant represented as caller-supplied epoch seconds.
pub struct Timestamp(Int64) derive(Eq, Compare, Debug, ToJson, FromJson)

///|
pub fn Timestamp::from_seconds(value : Int64) -> Timestamp {
  if value < 0 {
    Timestamp(0)
  } else {
    Timestamp(value)
  }
}

///|
pub fn Timestamp::zero() -> Timestamp {
  Timestamp(0)
}

///|
pub fn Timestamp::seconds(self : Timestamp) -> Int64 {
  self.0
}

///|
/// Return a non-negative duration even when the supplied clock moved backward.
pub fn Timestamp::elapsed_since(
  self : Timestamp,
  earlier : Timestamp,
) -> DeltaSeconds {
  if self.0 <= earlier.0 {
    DeltaSeconds(0)
  } else {
    DeltaSeconds(self.0 - earlier.0)
  }
}

///|
pub fn Timestamp::saturating_add(
  self : Timestamp,
  delta : DeltaSeconds,
) -> Timestamp {
  if self.0 >= MAX_DELTA_SECONDS - delta.0 {
    Timestamp(MAX_DELTA_SECONDS)
  } else {
    Timestamp(self.0 + delta.0)
  }
}

///|
/// A non-negative number of seconds. Construction and arithmetic saturate
/// instead of wrapping into negative values.
pub struct DeltaSeconds(Int64) derive(Eq, Compare, Debug, ToJson, FromJson)

///|
pub fn DeltaSeconds::from_seconds(value : Int64) -> DeltaSeconds {
  if value < 0 {
    DeltaSeconds(0)
  } else {
    DeltaSeconds(value)
  }
}

///|
pub fn DeltaSeconds::zero() -> DeltaSeconds {
  DeltaSeconds(0)
}

///|
pub fn DeltaSeconds::max_value() -> DeltaSeconds {
  DeltaSeconds(MAX_DELTA_SECONDS)
}

///|
pub fn DeltaSeconds::seconds(self : DeltaSeconds) -> Int64 {
  self.0
}

///|
pub fn DeltaSeconds::saturating_add(
  self : DeltaSeconds,
  other : DeltaSeconds,
) -> DeltaSeconds {
  if self.0 >= MAX_DELTA_SECONDS - other.0 {
    DeltaSeconds(MAX_DELTA_SECONDS)
  } else {
    DeltaSeconds(self.0 + other.0)
  }
}

///|
pub fn DeltaSeconds::saturating_sub(
  self : DeltaSeconds,
  other : DeltaSeconds,
) -> DeltaSeconds {
  if self.0 <= other.0 {
    DeltaSeconds(0)
  } else {
    DeltaSeconds(self.0 - other.0)
  }
}

///|
/// Scale a duration with integer arithmetic. Invalid or non-positive factors
/// produce zero; multiplication is rearranged to avoid overflow.
pub fn DeltaSeconds::saturating_scale(
  self : DeltaSeconds,
  numerator : Int64,
  denominator : Int64,
) -> DeltaSeconds {
  if self.0 == 0 || numerator <= 0 || denominator <= 0 {
    return DeltaSeconds(0)
  }
  let whole = self.0 / denominator
  let remainder = self.0 % denominator
  if whole > MAX_DELTA_SECONDS / numerator {
    return DeltaSeconds(MAX_DELTA_SECONDS)
  }
  let base = whole * numerator
  if remainder > MAX_DELTA_SECONDS / numerator {
    return DeltaSeconds(MAX_DELTA_SECONDS)
  }
  let fraction = remainder * numerator / denominator
  DeltaSeconds(base).saturating_add(DeltaSeconds(fraction))
}

///|
pub fn DeltaSeconds::min(
  self : DeltaSeconds,
  other : DeltaSeconds,
) -> DeltaSeconds {
  if self.0 <= other.0 {
    self
  } else {
    other
  }
}

///|
pub fn DeltaSeconds::max(
  self : DeltaSeconds,
  other : DeltaSeconds,
) -> DeltaSeconds {
  if self.0 >= other.0 {
    self
  } else {
    other
  }
}