use serde::{Deserialize, Serialize};

use crate::{BtError, Result};

pub const NANOS_PER_SECOND: i64 = 1_000_000_000;

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Timestamp(pub i64);

impl Timestamp {
    pub const fn from_nanos(nanos: i64) -> Self {
        Self(nanos)
    }

    pub const fn as_nanos(self) -> i64 {
        self.0
    }

    pub const fn is_second_aligned(self) -> bool {
        self.0 % NANOS_PER_SECOND == 0
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TimeRange {
    pub start: Timestamp,
    pub end: Timestamp,
}

impl TimeRange {
    pub fn new(start: Timestamp, end: Timestamp) -> Result<Self> {
        if start >= end {
            return Err(BtError::TimeRange(format!(
                "invalid range: start {} must be < end {}",
                start.as_nanos(),
                end.as_nanos()
            )));
        }

        Ok(Self { start, end })
    }

    pub fn contains(&self, ts: Timestamp) -> bool {
        ts >= self.start && ts < self.end
    }

    pub fn duration_nanos(&self) -> i64 {
        self.end.as_nanos() - self.start.as_nanos()
    }
}
