//! Device security context type for credential verification.
//!
//! This module provides the `DeviceSecurity` struct representing high-level
//! security assessment for policy decisions.

use serde::{Deserialize, Serialize};

/// Device security context from KB-JWT.
///
/// Provides high-level security assessment for policy decisions, including
/// the overall security level, biometric authentication status, and platform.
///
/// # Security Levels
///
/// - **"high"**: Device has secure element or TEE, integrity passed
/// - **"medium"**: Device has some security features but not all
/// - **"low"**: Limited security features or potential compromise detected
///
/// # Example
///
/// ```rust
/// use lastid_sdk::types::DeviceSecurity;
///
/// let security = DeviceSecurity::default();
/// assert_eq!(security.security_level, "unknown");
/// assert!(!security.biometric_used);
/// ```
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub struct DeviceSecurity {
    /// Overall security level: "high", "medium", "low", "unknown".
    #[serde(default = "default_security_level")]
    pub security_level: String,

    /// Whether biometric authentication was used for this presentation.
    #[serde(default)]
    pub biometric_used: bool,

    /// Platform identifier: "ios", "android", "web".
    #[serde(default = "default_platform")]
    pub platform: String,
}

fn default_security_level() -> String {
    "unknown".to_string()
}

fn default_platform() -> String {
    "unknown".to_string()
}

impl Default for DeviceSecurity {
    fn default() -> Self {
        Self {
            security_level: default_security_level(),
            biometric_used: false,
            platform: default_platform(),
        }
    }
}

impl DeviceSecurity {
    /// Check if the security level is high.
    #[must_use]
    pub fn is_high_security(&self) -> bool {
        self.security_level == "high"
    }

    /// Check if the security level is at least medium.
    #[must_use]
    pub fn is_medium_or_higher(&self) -> bool {
        self.security_level == "high" || self.security_level == "medium"
    }

    /// Check if the device is a mobile platform (iOS or Android).
    #[must_use]
    pub fn is_mobile(&self) -> bool {
        self.platform == "ios" || self.platform == "android"
    }
}

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

    #[test]
    fn test_default() {
        let security = DeviceSecurity::default();
        assert_eq!(security.security_level, "unknown");
        assert!(!security.biometric_used);
        assert_eq!(security.platform, "unknown");
    }

    #[test]
    fn test_is_high_security() {
        let mut security = DeviceSecurity::default();
        assert!(!security.is_high_security());

        security.security_level = "high".to_string();
        assert!(security.is_high_security());

        security.security_level = "medium".to_string();
        assert!(!security.is_high_security());
    }

    #[test]
    fn test_is_medium_or_higher() {
        let mut security = DeviceSecurity::default();
        assert!(!security.is_medium_or_higher());

        security.security_level = "low".to_string();
        assert!(!security.is_medium_or_higher());

        security.security_level = "medium".to_string();
        assert!(security.is_medium_or_higher());

        security.security_level = "high".to_string();
        assert!(security.is_medium_or_higher());
    }

    #[test]
    fn test_is_mobile() {
        let mut security = DeviceSecurity::default();
        assert!(!security.is_mobile());

        security.platform = "ios".to_string();
        assert!(security.is_mobile());

        security.platform = "android".to_string();
        assert!(security.is_mobile());

        security.platform = "web".to_string();
        assert!(!security.is_mobile());
    }

    #[test]
    fn test_serialization() {
        let security = DeviceSecurity {
            security_level: "high".to_string(),
            biometric_used: true,
            platform: "ios".to_string(),
        };

        let json = serde_json::to_string(&security).unwrap();
        let deserialized: DeviceSecurity = serde_json::from_str(&json).unwrap();
        assert_eq!(security, deserialized);
    }

    #[test]
    fn test_deserialization_with_defaults() {
        let json = r#"{"biometric_used": true}"#;
        let security: DeviceSecurity = serde_json::from_str(json).unwrap();

        assert_eq!(security.security_level, "unknown");
        assert!(security.biometric_used);
        assert_eq!(security.platform, "unknown");
    }
}
