//! Issuer info fixture builder.

use crate::trust_registry::{ES256PublicKey, IssuerInfo, IssuerStatus};

/// Test public key for fixtures (valid P-256 key).
pub const TEST_PUBLIC_KEY_X: &str = "WbbXWlY0Sdw6eVKiJGnFFAJnGDHVjdVRLWbZGIgn3Go";
pub const TEST_PUBLIC_KEY_Y: &str = "bfIuXkJHLZvVMZ96ekEqhyuSoVVbWBzWqcAzSvhp2gs";

/// Base IDP DID for production environment.
pub const BASE_IDP_DID_PROD: &str = "did:lastid:human.lastid.co";
/// Base IDP DID for dev environment.
pub const BASE_IDP_DID_DEV: &str = "did:lastid:human.dev.lastid.co";
/// Base IDP DID for test environment.
pub const BASE_IDP_DID_TEST: &str = "did:lastid:human.test.lastid.co";

/// All credential types that the base IDP can issue.
pub const BASE_IDP_CREDENTIAL_TYPES: &[&str] = &[
    "LastID.Base",
    "LastID.Persona",
    "LastID.VerifiedEmail",
    "LastID.VerifiedPhone",
    "LastID.VerifiedPersona",
    "LastID.Employment",
    "LastID.Trust",
    "LastID.AgeProof",
];

/// Create a test ES256 public key.
#[must_use]
pub fn test_public_key() -> ES256PublicKey {
    ES256PublicKey {
        kty: "EC".into(),
        crv: "P-256".into(),
        x: TEST_PUBLIC_KEY_X.into(),
        y: TEST_PUBLIC_KEY_Y.into(),
    }
}

/// Builder for creating `IssuerInfo` test fixtures.
///
/// # Example
///
/// ```rust
/// use lastid_sdk::test_utils::fixtures::IssuerInfoBuilder;
///
/// let issuer = IssuerInfoBuilder::new("did:lastid:test-issuer")
///     .with_name("Test Issuer")
///     .authorized()
///     .with_credential_type("LastID.Base")
///     .with_credential_type("LastID.VerifiedEmail")
///     .build();
/// ```
#[derive(Debug, Clone)]
pub struct IssuerInfoBuilder {
    enterprise_did: String,
    organization_name: String,
    endpoint_url: String,
    status: IssuerStatus,
    permitted_types: Vec<String>,
    public_key: ES256PublicKey,
}

impl IssuerInfoBuilder {
    /// Create a new builder with the issuer DID.
    #[must_use]
    pub fn new(enterprise_did: impl Into<String>) -> Self {
        let did = enterprise_did.into();
        let did_suffix = did.split(':').next_back().unwrap_or("test");
        let endpoint = format!("https://{did_suffix}.example.com");
        Self {
            enterprise_did: did,
            organization_name: "Default Organization".to_string(),
            endpoint_url: endpoint,
            status: IssuerStatus::Authorized,
            permitted_types: Vec::new(),
            public_key: test_public_key(),
        }
    }

    /// Create a builder configured as the base IDP (`LastID`).
    ///
    /// Uses the production DID by default. Use `base_idp_dev()` or
    /// `base_idp_test()` for other environments.
    ///
    /// # Example
    ///
    /// ```rust
    /// use lastid_sdk::test_utils::fixtures::IssuerInfoBuilder;
    ///
    /// let base_idp = IssuerInfoBuilder::base_idp().build();
    /// assert_eq!(base_idp.enterprise_did, "did:lastid:human.lastid.co");
    /// assert_eq!(base_idp.organization_name, "LastID");
    /// ```
    #[must_use]
    pub fn base_idp() -> Self {
        Self::base_idp_for_env(BASE_IDP_DID_PROD, "https://human.lastid.co")
    }

    /// Create a builder configured as the base IDP for dev environment.
    #[must_use]
    pub fn base_idp_dev() -> Self {
        Self::base_idp_for_env(BASE_IDP_DID_DEV, "https://human.dev.lastid.co")
    }

    /// Create a builder configured as the base IDP for test environment.
    #[must_use]
    pub fn base_idp_test() -> Self {
        Self::base_idp_for_env(BASE_IDP_DID_TEST, "https://human.test.lastid.co")
    }

    /// Internal helper for creating base IDP fixtures.
    fn base_idp_for_env(did: &str, endpoint: &str) -> Self {
        Self {
            enterprise_did: did.to_string(),
            organization_name: "LastID".to_string(),
            endpoint_url: endpoint.to_string(),
            status: IssuerStatus::Authorized,
            permitted_types: BASE_IDP_CREDENTIAL_TYPES
                .iter()
                .map(|s| (*s).to_string())
                .collect(),
            public_key: test_public_key(),
        }
    }

    /// Set a custom public key.
    #[must_use]
    pub fn with_public_key(mut self, key: ES256PublicKey) -> Self {
        self.public_key = key;
        self
    }

    /// Set the organization name.
    #[must_use]
    pub fn with_name(mut self, name: impl Into<String>) -> Self {
        self.organization_name = name.into();
        self
    }

    /// Set the endpoint URL.
    #[must_use]
    pub fn with_endpoint(mut self, url: impl Into<String>) -> Self {
        self.endpoint_url = url.into();
        self
    }

    /// Set the issuer status to registered.
    #[must_use]
    pub const fn registered(mut self) -> Self {
        self.status = IssuerStatus::Registered;
        self
    }

    /// Set the issuer status to authorized.
    #[must_use]
    pub const fn authorized(mut self) -> Self {
        self.status = IssuerStatus::Authorized;
        self
    }

    /// Set the issuer status to suspended.
    #[must_use]
    pub const fn suspended(mut self) -> Self {
        self.status = IssuerStatus::Suspended;
        self
    }

    /// Set the issuer status to revoked.
    #[must_use]
    pub const fn revoked(mut self) -> Self {
        self.status = IssuerStatus::Revoked;
        self
    }

    /// Add a credential type that this issuer is permitted to issue.
    #[must_use]
    pub fn with_credential_type(mut self, credential_type: impl Into<String>) -> Self {
        self.permitted_types.push(credential_type.into());
        self
    }

    /// Add multiple credential types.
    #[must_use]
    pub fn with_credential_types(mut self, types: &[&str]) -> Self {
        for t in types {
            self.permitted_types.push((*t).to_string());
        }
        self
    }

    /// Build the `IssuerInfo` instance.
    #[must_use]
    pub fn build(self) -> IssuerInfo {
        IssuerInfo {
            enterprise_did: self.enterprise_did,
            organization_name: self.organization_name,
            endpoint_url: self.endpoint_url,
            status: self.status,
            permitted_types: self.permitted_types,
            public_key: self.public_key,
        }
    }
}

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

    #[test]
    fn test_builder_basic() {
        let issuer = IssuerInfoBuilder::new("did:lastid:test").build();

        assert_eq!(issuer.enterprise_did, "did:lastid:test");
        assert!(matches!(issuer.status, IssuerStatus::Authorized));
    }

    #[test]
    fn test_builder_full() {
        let issuer = IssuerInfoBuilder::new("did:lastid:issuer-1")
            .with_name("Test Issuer")
            .suspended()
            .with_credential_types(&["LastID.Base", "LastID.VerifiedEmail"])
            .with_endpoint("https://test.example.com")
            .build();

        assert_eq!(issuer.enterprise_did, "did:lastid:issuer-1");
        assert_eq!(issuer.organization_name, "Test Issuer");
        assert!(matches!(issuer.status, IssuerStatus::Suspended));
        assert_eq!(issuer.permitted_types.len(), 2);
        assert_eq!(issuer.endpoint_url, "https://test.example.com");
    }

    #[test]
    fn test_can_issue() {
        let issuer = IssuerInfoBuilder::new("did:lastid:test")
            .with_credential_type("LastID.Base")
            .build();

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

    #[test]
    fn test_base_idp_builder() {
        let base_idp = IssuerInfoBuilder::base_idp().build();

        assert_eq!(base_idp.enterprise_did, "did:lastid:human.lastid.co");
        assert_eq!(base_idp.organization_name, "LastID");
        assert_eq!(base_idp.endpoint_url, "https://human.lastid.co");
        assert!(matches!(base_idp.status, IssuerStatus::Authorized));
        assert!(base_idp.can_issue("LastID.Base"));
        assert!(base_idp.can_issue("LastID.Persona"));
        assert!(base_idp.can_issue("LastID.VerifiedEmail"));
        assert!(base_idp.can_issue("LastID.Trust"));
    }

    #[test]
    fn test_base_idp_dev_builder() {
        let base_idp = IssuerInfoBuilder::base_idp_dev().build();

        assert_eq!(base_idp.enterprise_did, "did:lastid:human.dev.lastid.co");
        assert_eq!(base_idp.endpoint_url, "https://human.dev.lastid.co");
    }

    #[test]
    fn test_base_idp_test_builder() {
        let base_idp = IssuerInfoBuilder::base_idp_test().build();

        assert_eq!(base_idp.enterprise_did, "did:lastid:human.test.lastid.co");
        assert_eq!(base_idp.endpoint_url, "https://human.test.lastid.co");
    }
}
