use std::fmt::Display;

use chrono::{DateTime, Duration, Utc};
use lazy_static::lazy_static;
use libesedb::systemtime_from_filetime;

use crate::{impl_timestamp, value::{StringOrStringSet, ToStringOrStringSet}, CDatabase};

#[derive(Eq, PartialEq)]
pub struct TruncatedWindowsFileTime(DateTime<Utc>);

impl_timestamp!(TruncatedWindowsFileTime);

lazy_static! {
    static ref BASE_TIME: DateTime<Utc> = systemtime_from_filetime(0).into();
}

impl From<u64> for TruncatedWindowsFileTime {
    fn from(value: u64) -> Self {
        let mut seconds: i64 = value.try_into().unwrap();
        if seconds > i64::MAX / 1_000 {
            seconds = i64::MAX / 1_000;
        } else if seconds < -i64::MAX / 1_000 {
            seconds = -i64::MAX / 1_000;
        }
        match BASE_TIME.checked_add_signed(Duration::seconds(seconds)) {
            Some(sum) => Self(sum),
            None => {
                // sum is out of range
                Self(if seconds > 0 {
                    DateTime::<Utc>::MAX_UTC
                } else {
                    DateTime::<Utc>::MIN_UTC
                })
            }
        }
    }
}
impl From<DateTime<Utc>> for TruncatedWindowsFileTime {
    fn from(value: DateTime<Utc>) -> Self {
        Self(value)
    }
}
impl From<TruncatedWindowsFileTime> for DateTime<Utc> {
    fn from(value: TruncatedWindowsFileTime) -> Self {
        value.0
    }
}

impl Display for TruncatedWindowsFileTime {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.to_rfc3339().fmt(f)
    }
}

impl ToStringOrStringSet for TruncatedWindowsFileTime
{
    fn to_string_or_stringset(&self, _database: &CDatabase<'_, '_>) -> StringOrStringSet {
        StringOrStringSet::String(self.to_string())
    }
}

#[cfg(test)]
mod tests {
    use crate::win32_types::TruncatedWindowsFileTime;

    #[test]
    fn convert_from_ntds() {
        let ds_record_time = 13390472401u64;
        let ts = TruncatedWindowsFileTime::from(ds_record_time);
        assert_eq!(ts.0.to_rfc3339(), "2025-04-30T07:40:01+00:00");
    }
}
