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

/// Programa de fidelidade do passageiro
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LoyaltyProgram {
    /// Nome do programa (ex: "smiles", "multiplus")
    pub program: String,

    /// Categoria no programa (ex: "gold", "silver", "platinum")
    pub category: String,
}

impl LoyaltyProgram {
    /// Cria um novo programa de fidelidade
    pub fn new(program: impl Into<String>, category: impl Into<String>) -> Self {
        Self {
            program: program.into(),
            category: category.into(),
        }
    }

    /// Cria um builder para construir um programa de fidelidade
    pub fn builder() -> LoyaltyProgramBuilder {
        LoyaltyProgramBuilder::default()
    }
}

/// Builder para criar programa de fidelidade
#[derive(Default)]
pub struct LoyaltyProgramBuilder {
    program: Option<String>,
    category: Option<String>,
}

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

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

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

        let category = self
            .category
            .ok_or_else(|| ValidationError::EmptyField("loyalty_category".to_string()))?;

        if program.trim().is_empty() {
            return Err(ValidationError::EmptyField("loyalty_program".to_string()));
        }

        if category.trim().is_empty() {
            return Err(ValidationError::EmptyField("loyalty_category".to_string()));
        }

        Ok(LoyaltyProgram { program, category })
    }
}

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

    #[test]
    fn test_loyalty_program_new() {
        let loyalty = LoyaltyProgram::new("smiles", "gold");
        assert_eq!(loyalty.program, "smiles");
        assert_eq!(loyalty.category, "gold");
    }

    #[test]
    fn test_loyalty_program_builder() {
        let loyalty = LoyaltyProgram::builder()
            .program("multiplus")
            .category("silver")
            .build()
            .unwrap();

        assert_eq!(loyalty.program, "multiplus");
        assert_eq!(loyalty.category, "silver");
    }

    #[test]
    fn test_loyalty_program_serialization() {
        let loyalty = LoyaltyProgram::new("smiles", "gold");
        let json = serde_json::to_string(&loyalty).unwrap();
        assert!(json.contains("smiles"));
        assert!(json.contains("gold"));
    }
}

