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

/// Custo unitário do produto
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
#[repr(transparent)]
pub struct UnitCost(f64);

impl UnitCost {
    /// Cria um novo custo unitário validado
    pub fn new(value: f64) -> Result<Self, ValidationError> {
        if value < 0.0 {
            return Err(ValidationError::InvalidFormat {
                field: "unit_cost".to_string(),
                message: "unit cost cannot be negative".to_string(),
            });
        }

        if !value.is_finite() {
            return Err(ValidationError::InvalidFormat {
                field: "unit_cost".to_string(),
                message: "unit cost must be a finite number".to_string(),
            });
        }

        Ok(Self(value))
    }

    pub fn value(&self) -> f64 {
        self.0
    }

    /// Retorna o valor formatado com 2 casas decimais
    pub fn formatted(&self) -> String {
        format!("{:.2}", self.0)
    }
}

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

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

    #[test]
    fn test_unit_cost_valid() {
        let cost = UnitCost::new(29.99).unwrap();
        assert_eq!(cost.value(), 29.99);
    }

    #[test]
    fn test_unit_cost_zero() {
        let cost = UnitCost::new(0.0).unwrap();
        assert_eq!(cost.value(), 0.0);
    }

    #[test]
    fn test_unit_cost_negative() {
        let result = UnitCost::new(-10.0);
        assert!(result.is_err());
    }

    #[test]
    fn test_unit_cost_infinity() {
        let result = UnitCost::new(f64::INFINITY);
        assert!(result.is_err());
    }

    #[test]
    fn test_unit_cost_nan() {
        let result = UnitCost::new(f64::NAN);
        assert!(result.is_err());
    }

    #[test]
    fn test_unit_cost_formatted() {
        let cost = UnitCost::new(29.99).unwrap();
        assert_eq!(cost.formatted(), "29.99");
    }

    #[test]
    fn test_unit_cost_display() {
        let cost = UnitCost::new(29.99).unwrap();
        assert_eq!(format!("{}", cost), "29.99");
    }
}

