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

use super::{EventName, EventSubtype, EventType, Ticket, Venue};

/// Dados do evento
///
/// Ref: <https://docs.konduto.com/reference/event>
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Event {
    /// Nome do evento (obrigatório)
    pub name: EventName,

    /// Data e hora do evento em UTC (obrigatório, formato ISO 8601: YYYY-MM-DDThh:mmZ)
    pub date: String,

    /// Tipo do evento (obrigatório)
    #[serde(rename = "type")]
    pub event_type: EventType,

    /// Subtipo/detalhe do evento (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub subtype: Option<EventSubtype>,

    /// Local do evento (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub venue: Option<Venue>,

    /// Lista de ingressos (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tickets: Option<Vec<Ticket>>,
}

impl Event {
    /// Cria um builder para construir um evento
    pub fn builder() -> EventBuilder {
        EventBuilder::default()
    }
}

/// Builder para criar eventos
#[derive(Default)]
pub struct EventBuilder {
    name: Option<EventName>,
    date: Option<String>,
    event_type: Option<EventType>,
    subtype: Option<EventSubtype>,
    venue: Option<Venue>,
    tickets: Vec<Ticket>,
}

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

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

    pub fn date(mut self, date: impl Into<String>) -> Self {
        self.date = Some(date.into());
        self
    }

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

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

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

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

    pub fn add_ticket(mut self, ticket: Ticket) -> Self {
        self.tickets.push(ticket);
        self
    }

    pub fn tickets(mut self, tickets: Vec<Ticket>) -> Self {
        self.tickets = tickets;
        self
    }

    pub fn build(self) -> Result<Event, ValidationError> {
        let date = self
            .date
            .ok_or_else(|| ValidationError::EmptyField("event_date".to_string()))?;

        // Validar formato da data (max 17 chars para YYYY-MM-DDThh:mmZ)
        if date.len() > 17 {
            return Err(ValidationError::TooLong {
                field: "event_date".to_string(),
                max: 17,
                actual: date.len(),
            });
        }

        let tickets = if self.tickets.is_empty() {
            None
        } else {
            Some(self.tickets)
        };

        Ok(Event {
            name: self
                .name
                .ok_or_else(|| ValidationError::EmptyField("event_name".to_string()))?,
            date,
            event_type: self
                .event_type
                .ok_or_else(|| ValidationError::EmptyField("event_type".to_string()))?,
            subtype: self.subtype,
            venue: self.venue,
            tickets,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::types::address::Country;
    use crate::types::events::{Attendee, TicketCategory};

    #[test]
    fn test_event_complete() {
        let venue = Venue::builder()
            .name_str("Teatro Municipal")
            .unwrap()
            .city_str("São Paulo")
            .unwrap()
            .country(Country::BR)
            .capacity(500)
            .build()
            .unwrap();

        let attendee = Attendee::builder()
            .name_str("João Silva")
            .unwrap()
            .document_str("12345678900")
            .unwrap()
            .build()
            .unwrap();

        let ticket = Ticket::builder()
            .category(TicketCategory::Regular)
            .premium(false)
            .attendee(attendee)
            .build()
            .unwrap();

        let event = Event::builder()
            .name_str("Peça de Teatro")
            .unwrap()
            .date("2025-12-01T20:00Z")
            .event_type(EventType::Theater)
            .subtype_str("drama")
            .unwrap()
            .venue(venue)
            .add_ticket(ticket)
            .build()
            .unwrap();

        assert_eq!(event.name.as_str(), "Peça de Teatro");
        assert_eq!(event.date, "2025-12-01T20:00Z");
        assert_eq!(event.event_type, EventType::Theater);
        assert!(event.venue.is_some());
        assert!(event.tickets.is_some());
    }

    #[test]
    fn test_event_minimal() {
        let event = Event::builder()
            .name_str("Show Simples")
            .unwrap()
            .date("2025-12-01T20:00Z")
            .event_type(EventType::Show)
            .build()
            .unwrap();

        assert_eq!(event.name.as_str(), "Show Simples");
        assert!(event.venue.is_none());
        assert!(event.tickets.is_none());
        assert!(event.subtype.is_none());
    }

    #[test]
    fn test_event_multiple_tickets() {
        let attendee1 = Attendee::builder()
            .document_str("111")
            .unwrap()
            .build()
            .unwrap();

        let attendee2 = Attendee::builder()
            .document_str("222")
            .unwrap()
            .build()
            .unwrap();

        let ticket1 = Ticket::builder()
            .category(TicketCategory::Student)
            .premium(false)
            .attendee(attendee1)
            .build()
            .unwrap();

        let ticket2 = Ticket::builder()
            .category(TicketCategory::Regular)
            .premium(true)
            .attendee(attendee2)
            .build()
            .unwrap();

        let event = Event::builder()
            .name_str("Festival")
            .unwrap()
            .date("2025-12-01T20:00Z")
            .event_type(EventType::Festival)
            .add_ticket(ticket1)
            .add_ticket(ticket2)
            .build()
            .unwrap();

        assert_eq!(event.tickets.as_ref().unwrap().len(), 2);
    }

    #[test]
    fn test_event_missing_name() {
        let result = Event::builder()
            .date("2025-12-01T20:00Z")
            .event_type(EventType::Show)
            .build();

        assert!(result.is_err());
    }

    #[test]
    fn test_event_missing_date() {
        let result = Event::builder()
            .name_str("Test")
            .unwrap()
            .event_type(EventType::Show)
            .build();

        assert!(result.is_err());
    }

    #[test]
    fn test_event_missing_type() {
        let result = Event::builder()
            .name_str("Test")
            .unwrap()
            .date("2025-12-01T20:00Z")
            .build();

        assert!(result.is_err());
    }

    #[test]
    fn test_event_serialization() {
        let event = Event::builder()
            .name_str("Rock Concert")
            .unwrap()
            .date("2025-12-01T20:00Z")
            .event_type(EventType::Show)
            .subtype_str("rock")
            .unwrap()
            .build()
            .unwrap();

        let json = serde_json::to_string_pretty(&event).unwrap();
        assert!(json.contains("Rock Concert"));
        assert!(json.contains("2025-12-01T20:00Z"));
        assert!(json.contains("show"));
        assert!(json.contains("rock"));
    }

    #[test]
    fn test_event_deserialization() {
        let json = r#"{
            "name": "Test Event",
            "date": "2025-12-01T20:00Z",
            "type": "theater"
        }"#;

        let event: Event = serde_json::from_str(json).unwrap();
        assert_eq!(event.name.as_str(), "Test Event");
        assert_eq!(event.event_type, EventType::Theater);
    }

    #[test]
    fn test_event_roundtrip() {
        let original = Event::builder()
            .name_str("Test")
            .unwrap()
            .date("2025-12-01T20:00Z")
            .event_type(EventType::Sports)
            .build()
            .unwrap();

        let json = serde_json::to_string(&original).unwrap();
        let deserialized: Event = serde_json::from_str(&json).unwrap();

        assert_eq!(original, deserialized);
    }

    #[test]
    fn test_event_all_types() {
        let types = vec![
            EventType::Show,
            EventType::Theater,
            EventType::Movies,
            EventType::Party,
            EventType::Festival,
            EventType::Course,
            EventType::Sports,
            EventType::Corporate,
        ];

        for event_type in types {
            let event = Event::builder()
                .name_str("Test Event")
                .unwrap()
                .date("2025-12-01T20:00Z")
                .event_type(event_type)
                .build()
                .unwrap();

            assert_eq!(event.event_type, event_type);
        }
    }
}

