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

/// Latitude da loja física (-90 a 90)
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[repr(transparent)]
pub struct Latitude(f64);

impl Latitude {
    const MIN: f64 = -90.0;
    const MAX: f64 = 90.0;

    /// Cria uma nova latitude validada
    pub fn new(value: f64) -> Result<Self, ValidationError> {
        if !value.is_finite() {
            return Err(ValidationError::InvalidFormat {
                field: "latitude".to_string(),
                message: "latitude must be a finite number".to_string(),
            });
        }

        if !(Self::MIN..=Self::MAX).contains(&value) {
            return Err(ValidationError::InvalidFormat {
                field: "latitude".to_string(),
                message: format!(
                    "latitude must be between {} and {}, received: {}",
                    Self::MIN,
                    Self::MAX,
                    value
                ),
            });
        }

        Ok(Self(value))
    }

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

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

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

    #[test]
    fn test_latitude_valid() {
        let lat = Latitude::new(-23.5677666).unwrap();
        assert_eq!(lat.value(), -23.5677666);
    }

    #[test]
    fn test_latitude_zero() {
        let lat = Latitude::new(0.0).unwrap();
        assert_eq!(lat.value(), 0.0);
    }

    #[test]
    fn test_latitude_min() {
        let lat = Latitude::new(-90.0).unwrap();
        assert_eq!(lat.value(), -90.0);
    }

    #[test]
    fn test_latitude_max() {
        let lat = Latitude::new(90.0).unwrap();
        assert_eq!(lat.value(), 90.0);
    }

    #[test]
    fn test_latitude_too_low() {
        let result = Latitude::new(-90.1);
        assert!(result.is_err());
    }

    #[test]
    fn test_latitude_too_high() {
        let result = Latitude::new(90.1);
        assert!(result.is_err());
    }

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

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

