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

/// Status de um pedido na Konduto
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum OrderStatus {
    /// Aprovado: pedido é considerado legítimo para o algoritmo. Baixa possibilidade de fraude.
    /// Se houver saldo no cartão, a compra pode ser liberada.
    Approved,

    /// Pendente: esse status quer dizer que o pedido está aguardando a revisão manual
    /// da equipe, pois o algoritmo não tinha certeza sobre a aprovação.
    Pending,

    /// Negado: pedido foi rejeitado por suspeita de fraude e deve ser considerado
    /// negativamente pelo algoritmo.
    Declined,

    /// Não Aprovado: pedido teve o pagamento negado pela operadora de cartão e deve
    /// ser ignorado pelo algoritmo.
    /// Esse pedido não será analisado pela Konduto desde que ao enviá-lo, adicione a flag
    /// analyze=false no corpo da sua integração.
    NotAuthorized,

    /// Cancelado: pedido foi cancelado por questões operacionais e deve ser ignorado
    /// pelo algoritmo.
    /// Ofereça ao seu cliente refazer o pedido ou outra forma de pagamento.
    Canceled,

    /// Fraude: pedido teve fraude confirmada e deve ser considerado negativamente
    /// pelo algoritmo.
    /// Esse status sinaliza que você recebeu um chargeback.
    Fraud,

    /// Não Analisado: pedido não foi analisado pelo algoritmo e não há recomendação de
    /// risco (exemplo: outros meios de pagamento - débito, boleto, etc).
    /// Todos os pedidos enviados com a flag analyze=false ou com formas de pagamento
    /// diferentes de Cartão de crédito, terão esse status na API de Pedidos.
    NotAnalyzed,
}

impl<'de> Deserialize<'de> for OrderStatus {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        match s.to_lowercase().as_str() {
            "approved" => Ok(OrderStatus::Approved),
            "pending" => Ok(OrderStatus::Pending),
            "declined" => Ok(OrderStatus::Declined),
            "not_authorized" => Ok(OrderStatus::NotAuthorized),
            "canceled" => Ok(OrderStatus::Canceled),
            "fraud" => Ok(OrderStatus::Fraud),
            "not_analyzed" => Ok(OrderStatus::NotAnalyzed),
            _ => Err(serde::de::Error::custom(format!("Invalid status: {}", s))),
        }
    }
}

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

impl Display for OrderStatus {
    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() {
        let status: OrderStatus = serde_json::from_value(json!("approved")).unwrap();
        assert_eq!(status, OrderStatus::Approved);
        let status: OrderStatus = serde_json::from_value(json!("APPROVED")).unwrap();
        assert_eq!(status, OrderStatus::Approved);
        let status: OrderStatus = serde_json::from_value(json!("Approved")).unwrap();
        assert_eq!(status, OrderStatus::Approved);
    }

    #[test]
    fn test_all_statuses() {
        let test_cases = vec![
            ("approved", OrderStatus::Approved),
            ("pending", OrderStatus::Pending),
            ("declined", OrderStatus::Declined),
            ("not_authorized", OrderStatus::NotAuthorized),
            ("canceled", OrderStatus::Canceled),
            ("fraud", OrderStatus::Fraud),
            ("not_analyzed", OrderStatus::NotAnalyzed),
        ];

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

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

        let status = OrderStatus::NotAuthorized;
        let json = serde_json::to_value(&status).unwrap();
        assert_eq!(json, json!("not_authorized"));
    }

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