use crate::types::address::{City, Country, State};
use crate::types::validation_errors::ValidationError;
use serde::{Deserialize, Serialize};

use super::{VenueAddress, VenueName};

/// Dados do local do evento
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Venue {
    /// Nome do local (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<VenueName>,

    /// Endereço do local (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub address: Option<VenueAddress>,

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

    /// Estado (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state: Option<State>,

    /// País (opcional, ISO 3166-2)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub country: Option<Country>,

    /// Capacidade do local (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub capacity: Option<u32>,
}

impl Venue {
    /// Cria um builder para construir um local
    pub fn builder() -> VenueBuilder {
        VenueBuilder::default()
    }
}

/// Builder para criar locais de eventos
#[derive(Default)]
pub struct VenueBuilder {
    name: Option<VenueName>,
    address: Option<VenueAddress>,
    city: Option<City>,
    state: Option<State>,
    country: Option<Country>,
    capacity: Option<u32>,
}

impl VenueBuilder {
    pub fn name(mut self, name: VenueName) -> Self {
        self.name = Some(name);
        self
    }

    pub fn name_str(mut self, name: impl Into<String>) -> Result<Self, ValidationError> {
        self.name = Some(VenueName::try_new(name)?);
        Ok(self)
    }

    pub fn address(mut self, address: VenueAddress) -> Self {
        self.address = Some(address);
        self
    }

    pub fn address_str(mut self, address: impl Into<String>) -> Result<Self, ValidationError> {
        self.address = Some(VenueAddress::try_new(address)?);
        Ok(self)
    }

    pub fn city(mut self, city: City) -> Self {
        self.city = Some(city);
        self
    }

    pub fn city_str(mut self, city: impl Into<String>) -> Result<Self, ValidationError> {
        self.city = Some(City::try_new(city)?);
        Ok(self)
    }

    pub fn state(mut self, state: State) -> Self {
        self.state = Some(state);
        self
    }

    pub fn state_str(mut self, state: impl Into<String>) -> Result<Self, ValidationError> {
        self.state = Some(State::try_new(state)?);
        Ok(self)
    }

    pub fn country(mut self, country: Country) -> Self {
        self.country = Some(country);
        self
    }

    pub fn country_code(mut self, code: impl Into<String>) -> Result<Self, ValidationError> {
        self.country = Some(Country::from_code(code)?);
        Ok(self)
    }

    pub fn capacity(mut self, capacity: u32) -> Self {
        self.capacity = Some(capacity);
        self
    }

    pub fn build(self) -> Result<Venue, ValidationError> {
        Ok(Venue {
            name: self.name,
            address: self.address,
            city: self.city,
            state: self.state,
            country: self.country,
            capacity: self.capacity,
        })
    }
}

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

    #[test]
    fn test_venue_complete() {
        let venue = Venue::builder()
            .name_str("Teatro Municipal")
            .unwrap()
            .address_str("Rua das Flores, 123")
            .unwrap()
            .city_str("São Paulo")
            .unwrap()
            .state_str("SP")
            .unwrap()
            .country(Country::BR)
            .capacity(500)
            .build()
            .unwrap();

        assert_eq!(venue.name.as_ref().unwrap().as_str(), "Teatro Municipal");
        assert_eq!(venue.city.as_ref().unwrap().as_str(), "São Paulo");
        assert_eq!(venue.capacity, Some(500));
    }

    #[test]
    fn test_venue_minimal() {
        let venue = Venue::builder().build().unwrap();

        assert!(venue.name.is_none());
        assert!(venue.address.is_none());
        assert!(venue.capacity.is_none());
    }

    #[test]
    fn test_venue_serialization() {
        let venue = Venue::builder()
            .name_str("Arena")
            .unwrap()
            .city_str("Rio")
            .unwrap()
            .country(Country::BR)
            .capacity(10000)
            .build()
            .unwrap();

        let json = serde_json::to_string(&venue).unwrap();
        assert!(json.contains("Arena"));
        assert!(json.contains("Rio"));
        assert!(json.contains("10000"));
    }
}

