use crate::supports::enums;
use serde::{Deserialize, Serialize};
use std::fmt::Display;

/// Status da camada de análise (Segunda Camada)
///
/// A Konduto trabalha com camadas de análise, o que permite agregar serviços terceiros
/// ao parecer de fraude e enriquecendo assim a base para a decisão de risco.
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum AnalysisLayerStatus {
    /// FRAUD: Sinaliza o recebimento de um chargeback ou fraude confirmada na primeira camada.
    /// (Primeira camada)
    Fraud,

    /// FRAUD_REVIEW: Em situações onde a primeira camada retorne a recomendação de REVIEW.
    /// (Segunda camada)
    FraudReview,

    /// FRAUD_APPROVE: Em situações onde a primeira camada retorne a recomendação de APPROVE.
    /// (Segunda camada)
    FraudApprove,

    /// FRAUD_DECLINE: Em situações onde a primeira camada retorne a recomendação de DECLINE.
    /// (Segunda camada)
    FraudDecline,
}

impl<'de> Deserialize<'de> for AnalysisLayerStatus {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        match s.to_uppercase().as_str() {
            "FRAUD" => Ok(AnalysisLayerStatus::Fraud),
            "FRAUD_REVIEW" => Ok(AnalysisLayerStatus::FraudReview),
            "FRAUD_APPROVE" => Ok(AnalysisLayerStatus::FraudApprove),
            "FRAUD_DECLINE" => Ok(AnalysisLayerStatus::FraudDecline),
            _ => Err(serde::de::Error::custom(format!(
                "Invalid analysis layer status: {}",
                s
            ))),
        }
    }
}

impl AnalysisLayerStatus {
    pub fn name(&self) -> String {
        enums::to_string_infallible(self)
    }

    /// Retorna true se o status é da primeira camada
    pub fn is_first_layer(&self) -> bool {
        matches!(self, AnalysisLayerStatus::Fraud)
    }

    /// Retorna true se o status é da segunda camada
    pub fn is_second_layer(&self) -> bool {
        !self.is_first_layer()
    }
}

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

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

    #[test]
    fn test_status_deserialization_case_insensitive() {
        // Testa uppercase
        let status: AnalysisLayerStatus = serde_json::from_value(json!("FRAUD")).unwrap();
        assert_eq!(status, AnalysisLayerStatus::Fraud);

        // Testa lowercase
        let status: AnalysisLayerStatus = serde_json::from_value(json!("fraud")).unwrap();
        assert_eq!(status, AnalysisLayerStatus::Fraud);

        // Testa mixed case
        let status: AnalysisLayerStatus = serde_json::from_value(json!("Fraud")).unwrap();
        assert_eq!(status, AnalysisLayerStatus::Fraud);
    }

    #[test]
    fn test_all_statuses() {
        let test_cases = vec![
            ("FRAUD", AnalysisLayerStatus::Fraud),
            ("FRAUD_REVIEW", AnalysisLayerStatus::FraudReview),
            ("FRAUD_APPROVE", AnalysisLayerStatus::FraudApprove),
            ("FRAUD_DECLINE", AnalysisLayerStatus::FraudDecline),
        ];

        for (input, expected) in test_cases {
            let status: AnalysisLayerStatus = serde_json::from_value(json!(input)).unwrap();
            assert_eq!(status, expected);
        }
    }

    #[test]
    fn test_status_serialization() {
        let status = AnalysisLayerStatus::Fraud;
        let json = serde_json::to_value(&status).unwrap();
        assert_eq!(json, json!("FRAUD"));

        let status = AnalysisLayerStatus::FraudReview;
        let json = serde_json::to_value(&status).unwrap();
        assert_eq!(json, json!("FRAUD_REVIEW"));
    }

    #[test]
    fn test_invalid_status() {
        let result: Result<AnalysisLayerStatus, _> =
            serde_json::from_value(json!("invalid_status"));
        assert!(result.is_err());
    }

    #[test]
    fn test_layer_detection() {
        assert!(AnalysisLayerStatus::Fraud.is_first_layer());
        assert!(!AnalysisLayerStatus::Fraud.is_second_layer());

        assert!(AnalysisLayerStatus::FraudReview.is_second_layer());
        assert!(!AnalysisLayerStatus::FraudReview.is_first_layer());

        assert!(AnalysisLayerStatus::FraudApprove.is_second_layer());
        assert!(AnalysisLayerStatus::FraudDecline.is_second_layer());
    }
}
