use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata};
use miden_protocol::account::{AccountComponent, AccountComponentName};

use crate::account::account_component_code;

account_component_code!(NO_AUTH_CODE, "auth/no_auth.masl");

/// An [`AccountComponent`] implementing a no-authentication scheme.
///
/// This component provides **no authentication**! It only checks if the account
/// state has actually changed during transaction execution by comparing the initial
/// account commitment with the current commitment and increments the nonce if
/// they differ. This avoids unnecessary nonce increments for transactions that don't
/// modify the account state.
///
/// It exports the procedure `auth_no_auth`, which:
/// - Checks if the account state has changed by comparing initial and final commitments
/// - Only increments the nonce if the account state has actually changed
/// - Provides no cryptographic authentication
pub struct NoAuth;

impl NoAuth {
    /// The name of the component.
    pub const NAME: &'static str = "miden::standards::components::auth::no_auth";

    /// Returns the canonical [`AccountComponentName`] of this component.
    pub const fn name() -> AccountComponentName {
        AccountComponentName::from_static_str(Self::NAME)
    }

    /// Returns the [`AccountComponentCode`] of this component.
    pub fn code() -> &'static AccountComponentCode {
        &NO_AUTH_CODE
    }

    /// Creates a new [`NoAuth`] component.
    pub fn new() -> Self {
        Self
    }

    /// Returns the [`AccountComponentMetadata`] for this component.
    pub fn component_metadata() -> AccountComponentMetadata {
        AccountComponentMetadata::new(Self::NAME).with_description("No authentication component")
    }
}

impl Default for NoAuth {
    fn default() -> Self {
        Self::new()
    }
}

impl From<NoAuth> for AccountComponent {
    fn from(_: NoAuth) -> Self {
        let metadata = NoAuth::component_metadata();

        AccountComponent::new(NoAuth::code().clone(), vec![], metadata)
            .expect("NoAuth component should satisfy the requirements of a valid account component")
    }
}

// TESTS
// ================================================================================================

#[cfg(test)]
mod tests {
    use miden_protocol::account::AccountBuilder;

    use super::*;
    use crate::account::wallets::BasicWallet;

    #[test]
    fn test_no_auth_component() {
        // Create an account using the NoAuth component
        let _account = AccountBuilder::new([0; 32])
            .with_auth_component(NoAuth)
            .with_component(BasicWallet)
            .build()
            .expect("account building failed");
    }
}
