//! Card: number, holder, expiry (MonthYear), CVV, PIN, kind.

use serde::{Deserialize, Serialize};
use zeroize::Zeroizing;

use crate::time::MonthYear;

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CardCore {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub number: Option<Zeroizing<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub holder: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub expiry: Option<MonthYear>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cvv: Option<Zeroizing<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub pin: Option<Zeroizing<String>>,
    #[serde(default)]
    pub kind: CardKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum CardKind {
    #[default]
    Credit,
    Debit,
    Gift,
    Loyalty,
    Other,
}

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

    #[test]
    fn card_full_round_trip() {
        let card = CardCore {
            number: Some(Zeroizing::new("4111111111111111".into())),
            holder: Some("Alice Doe".into()),
            expiry: Some(MonthYear::new(12, 2030).unwrap()),
            cvv: Some(Zeroizing::new("123".into())),
            pin: Some(Zeroizing::new("0000".into())),
            kind: CardKind::Credit,
        };
        let json = serde_json::to_string(&card).unwrap();
        let parsed: CardCore = serde_json::from_str(&json).unwrap();
        assert_eq!(parsed.holder.as_deref(), Some("Alice Doe"));
        assert_eq!(parsed.kind, CardKind::Credit);
        assert_eq!(parsed.expiry, Some(MonthYear::new(12, 2030).unwrap()));
    }

    #[test]
    fn card_kind_default_is_credit() {
        let json = "{}";
        let card: CardCore = serde_json::from_str(json).unwrap();
        assert_eq!(card.kind, CardKind::Credit);
    }

    #[test]
    fn card_kind_serializes_snake_case() {
        let json = serde_json::to_string(&CardKind::Loyalty).unwrap();
        assert_eq!(json, "\"loyalty\"");
    }
}
