use serde::{Deserialize, Serialize};
mod address_line;
mod address_name;
mod city;
mod country_code;
mod state;
mod zip_code;

pub use address_line::AddressLine;
pub use address_name::AddressName;
pub use city::City;
pub use country_code::{Country, CountryCode};
pub use state::State;
pub use zip_code::ZipCode;

/// Dados de endereço com validação tipo-segura
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
pub struct Address {
    /// Nome completo do destinatário (max 100 chars)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<AddressName>,

    /// Endereço principal (max 255 chars)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub address1: Option<AddressLine>,

    /// Complemento adicional (max 255 chars)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub address2: Option<AddressLine>,

    /// Cidade (max 100 chars)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub city: Option<City>,

    /// Estado/Província (max 100 chars)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state: Option<State>,

    /// CEP (max 100 chars)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub zip: Option<ZipCode>,

    /// País - código ISO 3166-2 (exatamente 2 chars)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub country: Option<Country>,
}

impl Address {
    /// Cria um builder para construir um endereço
    pub fn builder() -> AddressBuilder {
        AddressBuilder::default()
    }
}

/// Builder para criar endereços
#[derive(Default)]
pub struct AddressBuilder {
    address: Address,
}

impl AddressBuilder {
    /// Define o nome do destinatário a partir de uma string
    pub fn name(
        mut self,
        name: impl Into<String>,
    ) -> Result<Self, crate::types::validation_errors::ValidationError> {
        self.address.name = Some(AddressName::try_new(name)?);
        Ok(self)
    }

    /// Define o endereço principal a partir de uma string
    pub fn address1(
        mut self,
        address: impl Into<String>,
    ) -> Result<Self, crate::types::validation_errors::ValidationError> {
        self.address.address1 = Some(AddressLine::try_new(address)?);
        Ok(self)
    }

    /// Define o complemento a partir de uma string
    pub fn address2(
        mut self,
        address: impl Into<String>,
    ) -> Result<Self, crate::types::validation_errors::ValidationError> {
        self.address.address2 = Some(AddressLine::try_new(address)?);
        Ok(self)
    }

    /// Define a cidade a partir de uma string
    pub fn city(
        mut self,
        city: impl Into<String>,
    ) -> Result<Self, crate::types::validation_errors::ValidationError> {
        self.address.city = Some(City::try_new(city)?);
        Ok(self)
    }

    /// Define o estado a partir de uma string
    pub fn state(
        mut self,
        state: impl Into<String>,
    ) -> Result<Self, crate::types::validation_errors::ValidationError> {
        self.address.state = Some(State::try_new(state)?);
        Ok(self)
    }

    /// Define o CEP a partir de uma string
    pub fn zip(
        mut self,
        zip: impl Into<String>,
    ) -> Result<Self, crate::types::validation_errors::ValidationError> {
        self.address.zip = Some(ZipCode::try_new(zip)?);
        Ok(self)
    }

    /// Define o país a partir de uma string
    pub fn country(mut self, country: Country) -> Self {
        self.address.country = Some(country);
        self
    }

    /// Constrói o endereço
    pub fn build(self) -> Address {
        self.address
    }
}

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

    #[test]
    fn test_address_builder() -> Result<(), Box<dyn std::error::Error>> {
        let address = Address::builder()
            .name("John Doe")?
            .address1("123 Main St")?
            .city("São Paulo")?
            .state("SP")?
            .zip("01234-567")?
            .country(Country::BR)
            .build();

        assert!(address.name.is_some());
        assert!(address.address1.is_some());
        assert!(address.city.is_some());
        assert_eq!(address.country, Some(Country::BR));
        Ok(())
    }

    #[test]
    fn test_address_serialization() -> Result<(), Box<dyn std::error::Error>> {
        let address = Address::builder()
            .name("Jane Doe")?
            .address1("456 Oak Ave")?
            .city("Rio de Janeiro")?
            .state("RJ")?
            .zip("20000-000")?
            .country(Country::BR)
            .build();

        let json = serde_json::to_string(&address).unwrap();
        assert!(json.contains("Jane Doe"));
        assert!(json.contains("Rio de Janeiro"));
        Ok(())
    }

    #[test]
    fn test_address_default() {
        let address = Address::default();
        assert!(address.name.is_none());
        assert!(address.address1.is_none());
    }

    #[test]
    fn test_invalid_country_code() {
        let result = Country::from_code("USA"); // 3 chars instead of 2
        assert!(result.is_err());
    }

    #[test]
    fn test_name_too_long() {
        let long_name = "a".repeat(101);
        let result = AddressName::try_new(long_name);
        assert!(result.is_err());
    }

    #[test]
    fn test_address_line_too_long() {
        let long_address = "a".repeat(256);
        let result = AddressLine::try_new(long_address);
        assert!(result.is_err());
    }
}
