//! Timer device utilities

use core::time::Duration;

use abi::{error::Error, time::SystemTime};
use device_api::{timer::RealTimeProviderDevice, Device};
use libk_util::sync::spin_rwlock::IrqSafeRwLock;

/// Centralized global time provider
pub struct GlobalTime {
    now: IrqSafeRwLock<Option<SystemTime>>,
}

/// Global real time provider
pub static GLOBAL_TIME: GlobalTime = GlobalTime::new();

impl Device for GlobalTime {
    fn display_name(&self) -> &'static str {
        "Global time"
    }
}

impl RealTimeProviderDevice for GlobalTime {
    fn real_timestamp(&self) -> Result<SystemTime, Error> {
        self.now.read().ok_or(Error::InvalidOperation)
    }
}

impl GlobalTime {
    const fn new() -> Self {
        Self {
            now: IrqSafeRwLock::new(None),
        }
    }

    /// Updates current time from the RTC time source
    pub fn update_from_rtc(&self, time: SystemTime, has_nanos: bool) {
        let mut now = self.now.write();
        let (seconds, nanoseconds) = if has_nanos {
            (time.seconds, time.nanoseconds)
        } else {
            (time.seconds, now.map(|t| t.nanoseconds).unwrap_or(0))
        };
        *now = Some(SystemTime {
            seconds,
            nanoseconds,
        });
    }

    /// Accumulates time delta from a monotonic timer source
    pub fn add_time(&self, delta: Duration) {
        let mut now = self.now.write();
        if let Some(now) = now.as_mut() {
            now.nanoseconds += delta.subsec_nanos() as u64;
            while now.nanoseconds > 1000000000 {
                now.seconds += 1;
                now.nanoseconds -= 1000000000;
            }
            now.seconds += delta.as_secs();
        }
    }
}
