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

/// Classe de viagem
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TravelClass {
    /// Classe econômica
    Economy,
    /// Classe executiva
    Business,
    /// Primeira classe
    First,
    /// Outra classe
    Other(String),
}

impl TravelClass {
    const MAX_LENGTH: usize = 8;

    /// Cria uma classe de viagem a partir de uma string
    pub fn new(value: impl Into<String>) -> Result<Self, ValidationError> {
        let input = value.into();
        let trimmed = input.trim().to_lowercase();

        if trimmed.is_empty() {
            return Err(ValidationError::EmptyField("travel_class".to_string()));
        }

        if trimmed.len() > Self::MAX_LENGTH {
            return Err(ValidationError::TooLong {
                field: "travel_class".to_string(),
                max: Self::MAX_LENGTH,
                actual: trimmed.len(),
            });
        }

        Ok(match trimmed.as_str() {
            "economy" => Self::Economy,
            "business" => Self::Business,
            "first" => Self::First,
            other => Self::Other(other.to_string()),
        })
    }

    pub fn as_str(&self) -> &str {
        match self {
            Self::Economy => "economy",
            Self::Business => "business",
            Self::First => "first",
            Self::Other(s) => s,
        }
    }
}

impl fmt::Display for TravelClass {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

impl Serialize for TravelClass {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_str(self.as_str())
    }
}

impl<'de> Deserialize<'de> for TravelClass {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        TravelClass::new(s).map_err(serde::de::Error::custom)
    }
}

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

    #[test]
    fn test_travel_class_from_str() {
        let economy = TravelClass::new("economy").unwrap();
        assert_eq!(economy, TravelClass::Economy);

        let business = TravelClass::new("Business").unwrap();
        assert_eq!(business, TravelClass::Business);

        let first = TravelClass::new("FIRST").unwrap();
        assert_eq!(first, TravelClass::First);
    }

    #[test]
    fn test_travel_class_other() {
        let premium = TravelClass::new("premium").unwrap();
        assert_eq!(premium.as_str(), "premium");
    }

    #[test]
    fn test_travel_class_empty() {
        let result = TravelClass::new("");
        assert!(result.is_err());
    }

    #[test]
    fn test_travel_class_too_long() {
        let result = TravelClass::new("very_long_class_name");
        assert!(result.is_err());
    }
}

