use crate::PaymentStatus;
use crate::bin_digits::BinDigits;
use crate::card_holder::CardholderName;
use crate::expiration_date::ExpirationDate;
use crate::last_digits::LastDigits;
use serde::{Deserialize, Serialize};

/// Dados de pagamento com cartão de débito
/// Possui os mesmos campos que cartão de crédito
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DebitCardPayment {
    /// Status do pagamento (obrigatório para cartões)
    pub status: PaymentStatus,

    /// BIN - Primeiros 6-10 dígitos do cartão (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub bin: Option<BinDigits>,

    /// Últimos 4 dígitos do cartão (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub last4: Option<LastDigits>,

    /// Data de validade no formato MMAAAA (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub expiration_date: Option<ExpirationDate>,

    /// Valor do pagamento (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub amount: Option<f64>,

    /// Nome do portador do cartão (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub holder: Option<CardholderName>,

    /// Nome do comprador (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,

    /// CPF do portador do cartão (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tax_id: Option<String>,

    /// Resultado da verificação CVV (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cvv_result: Option<String>,

    /// Resultado da verificação AVS (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub avs_result: Option<String>,

    /// Hash SHA-1 para integridade (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub sha1: Option<String>,

    /// Descrição do pagamento (opcional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

impl DebitCardPayment {
    /// Cria um novo pagamento com cartão de débito com status obrigatório
    pub fn new(status: PaymentStatus) -> Self {
        Self {
            status,
            bin: None,
            last4: None,
            expiration_date: None,
            amount: None,
            holder: None,
            name: None,
            tax_id: None,
            cvv_result: None,
            avs_result: None,
            sha1: None,
            description: None,
        }
    }

    pub fn with_bin(mut self, bin: BinDigits) -> Self {
        self.bin = Some(bin);
        self
    }

    pub fn with_last4(mut self, last4: LastDigits) -> Self {
        self.last4 = Some(last4);
        self
    }

    pub fn with_expiration_date(mut self, expiration_date: ExpirationDate) -> Self {
        self.expiration_date = Some(expiration_date);
        self
    }

    pub fn with_amount(mut self, amount: f64) -> Self {
        self.amount = Some(amount);
        self
    }

    pub fn with_holder(mut self, holder: CardholderName) -> Self {
        self.holder = Some(holder);
        self
    }

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

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

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

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

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

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

#[cfg(test)]
mod tests {
    use crate::PaymentStatus;
    use crate::debit_card::DebitCardPayment;

    #[test]
    fn test_debit_card_payment_builder() {
        let payment = DebitCardPayment::new(PaymentStatus::Approved)
            .with_amount(50.0)
            .with_description("Debit payment");

        assert_eq!(payment.status, PaymentStatus::Approved);
        assert_eq!(payment.amount, Some(50.0));
    }
}
