use crate::impl_nutype_error_conversion;
use nutype::nutype;

/// CEP/Código Postal (máximo 100 caracteres)
///
/// Aceita diversos formatos de códigos postais internacionais.
///
/// # Validações
/// - Não pode ser vazio (após trim)
/// - Máximo 100 caracteres
///
/// # Exemplos
/// ```
/// use konduto::ZipCode;
///
/// // CEP brasileiro
/// let zip = ZipCode::try_new("01234-567").unwrap();
/// assert_eq!(zip.as_str(), "01234-567");
///
/// // ZIP code americano
/// let zip = ZipCode::try_new("12345-6789").unwrap();
/// assert_eq!(zip.as_str(), "12345-6789");
///
/// // Simples
/// let zip = ZipCode::try_new("90210").unwrap();
/// assert_eq!(zip.as_str(), "90210");
/// ```
#[nutype(
    sanitize(trim),
    validate(not_empty, len_char_max = 100),
    derive(
        Debug,
        Clone,
        PartialEq,
        Eq,
        Display,
        AsRef,
        Deref,
        Serialize,
        Deserialize,
    )
)]
pub struct ZipCode(String);

impl ZipCode {
    /// Retorna o código postal como string slice (compatibilidade)
    pub fn as_str(&self) -> &str {
        self.as_ref()
    }
}

impl_nutype_error_conversion!(ZipCodeError);

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

    #[test]
    fn test_valid_zip_br() {
        let zip = ZipCode::try_new("01234-567").unwrap();
        assert_eq!(zip.as_str(), "01234-567");
    }

    #[test]
    fn test_valid_zip_us() {
        let zip = ZipCode::try_new("12345-6789").unwrap();
        assert_eq!(zip.as_str(), "12345-6789");
    }

    #[test]
    fn test_zip_with_whitespace() {
        let zip = ZipCode::try_new("  90210  ").unwrap();
        assert_eq!(zip.as_str(), "90210");
    }

    #[test]
    fn test_empty_zip() {
        let result = ZipCode::try_new("");
        assert!(result.is_err());
    }

    #[test]
    fn test_zip_too_long() {
        let long_zip = "a".repeat(101);
        let result = ZipCode::try_new(long_zip);
        assert!(result.is_err());
    }

    #[test]
    fn test_zip_max_length() {
        let zip = "a".repeat(100);
        let result = ZipCode::try_new(zip);
        assert!(result.is_ok());
    }
}
