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

use super::{Attendee, TicketCategory, TicketId, TicketSection};

/// Dados do ingresso do evento
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Ticket {
    /// ID único do ticket (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<TicketId>,

    /// Categoria do ticket (obrigatório)
    pub category: TicketCategory,

    /// Seção do ticket (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub section: Option<TicketSection>,

    /// Indicador de ticket premium (obrigatório)
    pub premium: bool,

    /// Dados do participante (obrigatório)
    pub attendee: Attendee,
}

impl Ticket {
    /// Cria um builder para construir um ingresso
    pub fn builder() -> TicketBuilder {
        TicketBuilder::default()
    }
}

/// Builder para criar ingressos
#[derive(Default)]
pub struct TicketBuilder {
    id: Option<TicketId>,
    category: Option<TicketCategory>,
    section: Option<TicketSection>,
    premium: Option<bool>,
    attendee: Option<Attendee>,
}

impl TicketBuilder {
    pub fn id(mut self, id: TicketId) -> Self {
        self.id = Some(id);
        self
    }

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

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

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

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

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

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

    pub fn build(self) -> Result<Ticket, ValidationError> {
        Ok(Ticket {
            id: self.id,
            category: self
                .category
                .ok_or_else(|| ValidationError::EmptyField("ticket_category".to_string()))?,
            section: self.section,
            premium: self
                .premium
                .ok_or_else(|| ValidationError::EmptyField("ticket_premium".to_string()))?,
            attendee: self
                .attendee
                .ok_or_else(|| ValidationError::EmptyField("ticket_attendee".to_string()))?,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::types::events::AttendeeDocumentType;

    #[test]
    fn test_ticket_complete() {
        let attendee = Attendee::builder()
            .name_str("João Silva")
            .unwrap()
            .document_str("12345678900")
            .unwrap()
            .document_type(AttendeeDocumentType::Cpf)
            .build()
            .unwrap();

        let ticket = Ticket::builder()
            .id_str("TICKET123")
            .unwrap()
            .category(TicketCategory::Student)
            .section_str("A")
            .unwrap()
            .premium(false)
            .attendee(attendee)
            .build()
            .unwrap();

        assert_eq!(ticket.id.as_ref().unwrap().as_str(), "TICKET123");
        assert_eq!(ticket.category, TicketCategory::Student);
        assert_eq!(ticket.section.as_ref().unwrap().as_str(), "A");
        assert!(!ticket.premium);
    }

    #[test]
    fn test_ticket_minimal() {
        let attendee = Attendee::builder()
            .document_str("123")
            .unwrap()
            .build()
            .unwrap();

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

        assert!(ticket.id.is_none());
        assert!(ticket.section.is_none());
        assert_eq!(ticket.category, TicketCategory::Regular);
    }

    #[test]
    fn test_ticket_premium() {
        let attendee = Attendee::builder()
            .document_str("123")
            .unwrap()
            .build()
            .unwrap();

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

        assert!(ticket.premium);
    }

    #[test]
    fn test_ticket_missing_category() {
        let attendee = Attendee::builder()
            .document_str("123")
            .unwrap()
            .build()
            .unwrap();

        let result = Ticket::builder().premium(false).attendee(attendee).build();

        assert!(result.is_err());
    }

    #[test]
    fn test_ticket_missing_attendee() {
        let result = Ticket::builder()
            .category(TicketCategory::Regular)
            .premium(false)
            .build();

        assert!(result.is_err());
    }

    #[test]
    fn test_ticket_serialization() {
        let attendee = Attendee::builder()
            .name_str("Test")
            .unwrap()
            .document_str("123")
            .unwrap()
            .build()
            .unwrap();

        let ticket = Ticket::builder()
            .id_str("T001")
            .unwrap()
            .category(TicketCategory::Student)
            .section_str("VIP")
            .unwrap()
            .premium(true)
            .attendee(attendee)
            .build()
            .unwrap();

        let json = serde_json::to_string(&ticket).unwrap();
        assert!(json.contains("T001"));
        assert!(json.contains("student"));
        assert!(json.contains("VIP"));
        assert!(json.contains("true"));
    }
}

