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

/// Uso do veículo
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum VehicleUsage {
    Private,
    Commercial,
    Experimental,
    Government,
    Military,
    Instruction,
    /// todo maybe use untagged here
    Other(String),
}

impl VehicleUsage {
    /// Cria um uso de veículo 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("vehicle_usage".to_string()));
        }

        Ok(match trimmed.as_str() {
            "private" => Self::Private,
            "commercial" => Self::Commercial,
            "experimental" => Self::Experimental,
            "government" => Self::Government,
            "military" => Self::Military,
            "instruction" => Self::Instruction,
            other => Self::Other(other.to_string()),
        })
    }

    pub fn as_str(&self) -> &str {
        match self {
            Self::Private => "private",
            Self::Commercial => "commercial",
            Self::Experimental => "experimental",
            Self::Government => "government",
            Self::Military => "military",
            Self::Instruction => "instruction",
            Self::Other(s) => s,
        }
    }
}

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

impl Serialize for VehicleUsage {
    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 VehicleUsage {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        VehicleUsage::new(s).map_err(serde::de::Error::custom)
    }
}

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

    #[test]
    fn test_vehicle_usage_from_str() {
        assert_eq!(VehicleUsage::new("private").unwrap(), VehicleUsage::Private);
        assert_eq!(
            VehicleUsage::new("Commercial").unwrap(),
            VehicleUsage::Commercial
        );
        assert_eq!(
            VehicleUsage::new("MILITARY").unwrap(),
            VehicleUsage::Military
        );
    }

    #[test]
    fn test_vehicle_usage_other() {
        let custom = VehicleUsage::new("rental").unwrap();
        assert_eq!(custom.as_str(), "rental");
    }

    #[test]
    fn test_vehicle_usage_serialization() {
        let private = VehicleUsage::Private;
        let json = serde_json::to_string(&private).unwrap();
        assert_eq!(json, r#""private""#);
    }
}

