//! Parsed `VerifiedPhone` credential type.

use serde::{Deserialize, Serialize};

use crate::error::LastIDError;
use crate::types::VerifiedCredential;

/// Parsed `LastID.VerifiedPhone` credential with typed fields.
///
/// # Required Fields
///
/// Unlike other parsed types, `phone_number` is a required field for
/// `VerifiedPhone` credentials since verification wouldn't exist without it.
///
/// # Example
///
/// ```rust,ignore
/// use lastid_sdk::types::parsed::ParsedVerifiedPhone;
///
/// let phone = ParsedVerifiedPhone::try_from(&credential)?;
/// println!("Verified phone: {}", phone.phone_number);
/// ```
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ParsedVerifiedPhone {
    /// Verified phone number (required).
    pub phone_number: String,
    /// Timestamp when phone was verified (Unix epoch seconds).
    pub verified_at: Option<i64>,
    /// Verification method (e.g., "`sms_otp`", "`voice_call`").
    pub verification_method: Option<String>,
    /// Verification provider (e.g., "twilio", "lastid").
    pub provider: Option<String>,
}

impl TryFrom<&VerifiedCredential> for ParsedVerifiedPhone {
    type Error = LastIDError;

    fn try_from(cred: &VerifiedCredential) -> Result<Self, Self::Error> {
        if cred.credential_type != "LastID.VerifiedPhone" {
            return Err(LastIDError::invalid_credential(format!(
                "Expected LastID.VerifiedPhone, got {}",
                cred.credential_type
            )));
        }

        let phone_number = cred
            .get_claim_str("phone_number")
            .ok_or_else(|| LastIDError::invalid_credential("Missing required field: phone_number"))?
            .to_string();

        Ok(Self {
            phone_number,
            verified_at: cred.get_claim_i64("verified_at"),
            verification_method: cred.get_claim_str("verification_method").map(String::from),
            provider: cred.get_claim_str("provider").map(String::from),
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::trust_registry::IssuerStatus;
    use chrono::Utc;

    fn test_credential(cred_type: &str, claims: serde_json::Value) -> VerifiedCredential {
        VerifiedCredential {
            subject_did: "did:lastid:user123".into(),
            issuer_did: "did:lastid:issuer456".into(),
            credential_type: cred_type.into(),
            claims,
            issued_at: Utc::now(),
            expires_at: Utc::now() + chrono::Duration::hours(24),
            issuer_status: IssuerStatus::Authorized,
            signature_verified: true,
        }
    }

    #[test]
    fn test_parse_verified_phone() {
        let cred = test_credential(
            "LastID.VerifiedPhone",
            serde_json::json!({
                "phone_number": "+1234567890",
                "provider": "twilio",
                "verification_method": "sms_otp"
            }),
        );

        let phone = ParsedVerifiedPhone::try_from(&cred).unwrap();
        assert_eq!(phone.phone_number, "+1234567890");
        assert_eq!(phone.provider, Some("twilio".to_string()));
        assert_eq!(phone.verification_method, Some("sms_otp".to_string()));
    }

    #[test]
    fn test_parse_verified_phone_missing_phone() {
        let cred = test_credential("LastID.VerifiedPhone", serde_json::json!({}));

        let result = ParsedVerifiedPhone::try_from(&cred);
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_verified_phone_wrong_type() {
        let cred = test_credential(
            "LastID.Persona",
            serde_json::json!({"phone_number": "+1234567890"}),
        );

        let result = ParsedVerifiedPhone::try_from(&cred);
        assert!(result.is_err());
    }
}
