use crate::types::validation_errors::ValidationError;
use serde::{Deserialize, Serialize};
use std::fmt;

/// SLA de entrega em minutos
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(transparent)]
pub struct DeliverySlaInMinutes(u32);

impl DeliverySlaInMinutes {
    /// Cria um novo SLA de entrega validado
    pub fn new(minutes: u32) -> Result<Self, ValidationError> {
        if minutes == 0 {
            return Err(ValidationError::InvalidFormat {
                field: "delivery_sla_in_minutes".to_string(),
                message: "delivery SLA must be greater than 0 minutes".to_string(),
            });
        }

        Ok(Self(minutes))
    }

    pub fn minutes(&self) -> u32 {
        self.0
    }

    /// Converte minutos para horas (arredondado para cima)
    pub fn hours(&self) -> u32 {
        self.0.div_ceil(60)
    }

    /// Converte minutos para dias (arredondado para cima)
    pub fn days(&self) -> u32 {
        self.0.div_ceil(1440)
    }
}

impl fmt::Display for DeliverySlaInMinutes {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} minutes", self.0)
    }
}

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

    #[test]
    fn test_delivery_sla_valid() {
        let sla = DeliverySlaInMinutes::new(50).unwrap();
        assert_eq!(sla.minutes(), 50);
    }

    #[test]
    fn test_delivery_sla_zero() {
        let result = DeliverySlaInMinutes::new(0);
        assert!(result.is_err());
    }

    #[test]
    fn test_delivery_sla_hours() {
        let sla = DeliverySlaInMinutes::new(120).unwrap();
        assert_eq!(sla.hours(), 2);
    }

    #[test]
    fn test_delivery_sla_hours_round_up() {
        let sla = DeliverySlaInMinutes::new(61).unwrap();
        assert_eq!(sla.hours(), 2);
    }

    #[test]
    fn test_delivery_sla_days() {
        let sla = DeliverySlaInMinutes::new(1440).unwrap(); // 24 horas
        assert_eq!(sla.days(), 1);
    }

    #[test]
    fn test_delivery_sla_days_round_up() {
        let sla = DeliverySlaInMinutes::new(1441).unwrap();
        assert_eq!(sla.days(), 2);
    }

    #[test]
    fn test_delivery_sla_display() {
        let sla = DeliverySlaInMinutes::new(50).unwrap();
        assert_eq!(format!("{}", sla), "50 minutes");
    }
}

