use crate::v4::error::Result;
use serde::{Deserialize, Serialize};

/// The lowest valid value for lease_time (in seconds)
const MIN_LEASE_TIME: u32 = 60;
/// Used to adjust for clock drift between client and server (in seconds)
const DRIFT: u32 = 10;

/// The time, in seconds, before a lease expires.
/// A lower value will increase dhcp traffic between client and server.
/// A higher value will increase the chances that all ip addresses are assigned.
///
/// Lease time must be at least a minute because:
/// 1. The server must subtract some time to account for drift.
/// 2. The default value for T1 (renewal time) is half of the lease_time.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct LeaseTime(u32);

impl LeaseTime {
    /// DHCP reserves the maximum value of 4,294,967,295 to represent a lease that never expires.
    ///
    /// This is more performant than `LeaseTime::new`
    pub const INFINITY: Self = Self(u32::MAX);

    /// The number of seconds in one day (24 hours).
    /// This is currently used as the default in `LeaseConfig`.
    pub const ONE_DAY: Self = Self(86_400);

    /// Construct a valid lease_time field.
    pub fn new(lease_time: u32) -> Result<Self> {
        if lease_time < MIN_LEASE_TIME {
            return Err("Lease time cant be less than the minimum lease time (60 seconds)");
        }

        Ok(Self(lease_time))
    }

    /// The actual lease_time, not adjusted for drift.
    pub fn as_server(&self) -> u32 {
        self.0
    }

    /// The lease_time, with a small amount subtracted to adjust for drift
    pub fn as_client(&self) -> u32 {
        self.0 - DRIFT
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_min_lease_time_greater_than_drift() {
        assert!(MIN_LEASE_TIME > DRIFT);
    }
}
