//! Trust registry type definitions.

use serde::{Deserialize, Serialize};

/// ES256 (P-256) public key in JWK format.
///
/// Used for cryptographic signature verification of credentials.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ES256PublicKey {
    /// Key type - always "EC" for elliptic curve
    pub kty: String,
    /// Curve - always "P-256" for ES256
    pub crv: String,
    /// X coordinate (base64url-encoded)
    pub x: String,
    /// Y coordinate (base64url-encoded)
    pub y: String,
}

/// Issuer registration information from trust registry.
///
/// Supports two types of issuers:
/// - **Enterprise Issuers**: `did:lastid:ent:{64 hex chars}` - Third-party
///   organizations
/// - **Base IDP**: `did:lastid:human.{env}.lastid.co` - The `LastID` identity
///   provider itself
///
/// The base IDP issues foundational credentials (Base, Persona,
/// `VerifiedEmail`, etc.) and is always authorized.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct IssuerInfo {
    /// Issuer DID. Can be either:
    /// - Enterprise DID: `did:lastid:ent:{64 hex chars}` (e.g.,
    ///   "did:lastid:ent:abc123...")
    /// - Base IDP DID: `did:lastid:human.{env}.lastid.co` (e.g.,
    ///   "did:lastid:human.lastid.co")
    ///
    /// Named `enterpriseDid` in JSON to match the IDP API response format.
    pub enterprise_did: String,

    /// Organization display name
    pub organization_name: String,

    /// IDP endpoint URL
    pub endpoint_url: String,

    /// Current issuer status
    pub status: IssuerStatus,

    /// Credential types this issuer is permitted to issue
    pub permitted_types: Vec<String>,

    /// Issuer's public key for signature verification (ES256/P-256)
    pub public_key: ES256PublicKey,
}

impl IssuerInfo {
    /// Check if the issuer can issue a specific credential type.
    #[must_use]
    pub fn can_issue(&self, credential_type: &str) -> bool {
        self.permitted_types.iter().any(|t| t == credential_type)
    }
}

/// Issuer status in trust registry.
///
/// # State Machine
///
/// ```text
/// Registered ──► Authorized ──► Suspended ──► Authorized (reactivation)
///     │              │              │
///     └──────────────┴──────────────┴──► Revoked (terminal)
/// ```
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum IssuerStatus {
    /// Initial status after trust registry registration
    #[default]
    Registered,

    /// Authorized to issue all permitted credential types
    Authorized,

    /// Temporarily suspended (reversible)
    Suspended,

    /// Permanently revoked (irreversible)
    Revoked,
}

impl IssuerStatus {
    /// Check if this status is valid for credential issuance.
    ///
    /// Returns `true` for `Registered` and `Authorized` statuses.
    #[must_use]
    pub const fn is_valid(&self) -> bool {
        matches!(self, Self::Registered | Self::Authorized)
    }

    /// Check if this status is terminal (cannot change).
    #[must_use]
    pub const fn is_terminal(&self) -> bool {
        matches!(self, Self::Revoked)
    }
}

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

    #[test]
    fn test_issuer_status_is_valid() {
        assert!(IssuerStatus::Registered.is_valid());
        assert!(IssuerStatus::Authorized.is_valid());
        assert!(!IssuerStatus::Suspended.is_valid());
        assert!(!IssuerStatus::Revoked.is_valid());
    }

    #[test]
    fn test_issuer_status_is_terminal() {
        assert!(!IssuerStatus::Registered.is_terminal());
        assert!(!IssuerStatus::Authorized.is_terminal());
        assert!(!IssuerStatus::Suspended.is_terminal());
        assert!(IssuerStatus::Revoked.is_terminal());
    }

    #[test]
    fn test_issuer_info_can_issue() {
        let issuer = IssuerInfo {
            enterprise_did: "did:lastid:test".into(),
            organization_name: "Test Org".into(),
            endpoint_url: "https://test.com".into(),
            status: IssuerStatus::Authorized,
            permitted_types: vec!["LastID.Base".into(), "LastID.Persona".into()],
            public_key: ES256PublicKey {
                kty: "EC".into(),
                crv: "P-256".into(),
                x: "WbbXWlY0Sdw6eVKiJGnFFAJnGDHVjdVRLWbZGIgn3Go".into(),
                y: "bfIuXkJHLZvVMZ96ekEqhyuSoVVbWBzWqcAzSvhp2gs".into(),
            },
        };

        assert!(issuer.can_issue("LastID.Base"));
        assert!(issuer.can_issue("LastID.Persona"));
        assert!(!issuer.can_issue("LastID.VerifiedEmail"));
    }

    #[test]
    fn test_issuer_status_serialization() {
        assert_eq!(
            serde_json::to_string(&IssuerStatus::Authorized).unwrap(),
            "\"authorized\""
        );
        assert_eq!(
            serde_json::from_str::<IssuerStatus>("\"suspended\"").unwrap(),
            IssuerStatus::Suspended
        );
    }

    #[test]
    fn test_issuer_info_deserialization() {
        let json = r#"{
            "enterpriseDid": "did:lastid:acmecorp.com",
            "organizationName": "ACME Corp",
            "endpointUrl": "https://acmecorp.com",
            "status": "authorized",
            "permittedTypes": ["LastID.Base", "LastID.Persona"],
            "publicKey": {
                "kty": "EC",
                "crv": "P-256",
                "x": "WbbXWlY0Sdw6eVKiJGnFFAJnGDHVjdVRLWbZGIgn3Go",
                "y": "bfIuXkJHLZvVMZ96ekEqhyuSoVVbWBzWqcAzSvhp2gs"
            }
        }"#;

        let issuer: IssuerInfo = serde_json::from_str(json).unwrap();
        assert_eq!(issuer.enterprise_did, "did:lastid:acmecorp.com");
        assert_eq!(issuer.status, IssuerStatus::Authorized);
        assert_eq!(issuer.permitted_types.len(), 2);
        assert_eq!(issuer.public_key.kty, "EC");
        assert_eq!(issuer.public_key.crv, "P-256");
    }

    #[test]
    fn test_base_idp_info_deserialization() {
        // Test that base IDP DID format deserializes correctly
        let json = r#"{
            "enterpriseDid": "did:lastid:human.lastid.co",
            "organizationName": "LastID",
            "endpointUrl": "https://human.lastid.co",
            "status": "authorized",
            "permittedTypes": ["LastID.Base", "LastID.Persona", "LastID.VerifiedEmail", "LastID.Trust"],
            "publicKey": {
                "kty": "EC",
                "crv": "P-256",
                "x": "WbbXWlY0Sdw6eVKiJGnFFAJnGDHVjdVRLWbZGIgn3Go",
                "y": "bfIuXkJHLZvVMZ96ekEqhyuSoVVbWBzWqcAzSvhp2gs"
            }
        }"#;

        let issuer: IssuerInfo = serde_json::from_str(json).unwrap();
        assert_eq!(issuer.enterprise_did, "did:lastid:human.lastid.co");
        assert_eq!(issuer.organization_name, "LastID");
        assert_eq!(issuer.status, IssuerStatus::Authorized);
        assert!(issuer.can_issue("LastID.Base"));
        assert!(issuer.can_issue("LastID.Trust"));
    }

    #[test]
    fn test_base_idp_dev_info_deserialization() {
        // Test dev environment DID format
        let json = r#"{
            "enterpriseDid": "did:lastid:human.dev.lastid.co",
            "organizationName": "LastID",
            "endpointUrl": "https://human.dev.lastid.co",
            "status": "authorized",
            "permittedTypes": ["LastID.Base"],
            "publicKey": {
                "kty": "EC",
                "crv": "P-256",
                "x": "WbbXWlY0Sdw6eVKiJGnFFAJnGDHVjdVRLWbZGIgn3Go",
                "y": "bfIuXkJHLZvVMZ96ekEqhyuSoVVbWBzWqcAzSvhp2gs"
            }
        }"#;

        let issuer: IssuerInfo = serde_json::from_str(json).unwrap();
        assert_eq!(issuer.enterprise_did, "did:lastid:human.dev.lastid.co");
        assert_eq!(issuer.endpoint_url, "https://human.dev.lastid.co");
    }
}
