use crate::{AccountFactory, PreparedAccountDeployment, RawAccountDeployment};
use async_trait::async_trait;
use starknet_core::types::FieldElement;
use starknet_providers::Provider;
use starknet_signers::Signer;
const SELECTOR_INITIALIZE: FieldElement = FieldElement::from_mont([
    14382173896205878522,
    7380089477680411368,
    4404362358337226556,
    132905214994424316,
]);
pub struct ArgentAccountFactory<S, P> {
    proxy_class_hash: FieldElement,
    impl_class_hash: FieldElement,
    chain_id: FieldElement,
    signer_public_key: FieldElement,
    guardian_public_key: FieldElement,
    signer: S,
    provider: P,
}
impl<S, P> ArgentAccountFactory<S, P>
where
    S: Signer,
{
    pub async fn new(
        proxy_class_hash: FieldElement,
        impl_class_hash: FieldElement,
        chain_id: FieldElement,
        guardian_public_key: FieldElement,
        signer: S,
        provider: P,
    ) -> Result<Self, S::GetPublicKeyError> {
        let signer_public_key = signer.get_public_key().await?;
        Ok(Self {
            proxy_class_hash,
            impl_class_hash,
            chain_id,
            signer_public_key: signer_public_key.scalar(),
            guardian_public_key,
            signer,
            provider,
        })
    }
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl<S, P> AccountFactory for ArgentAccountFactory<S, P>
where
    S: Signer + Sync + Send,
    P: Provider + Sync + Send,
{
    type Provider = P;
    type SignError = S::SignError;
    fn class_hash(&self) -> FieldElement {
        self.proxy_class_hash
    }
    fn calldata(&self) -> Vec<FieldElement> {
        vec![
            self.impl_class_hash,
            SELECTOR_INITIALIZE,
            FieldElement::TWO,
            self.signer_public_key,
            self.guardian_public_key,
        ]
    }
    fn chain_id(&self) -> FieldElement {
        self.chain_id
    }
    fn provider(&self) -> &Self::Provider {
        &self.provider
    }
    async fn sign_deployment(
        &self,
        deployment: &RawAccountDeployment,
    ) -> Result<Vec<FieldElement>, Self::SignError> {
        let tx_hash =
            PreparedAccountDeployment::from_raw(deployment.clone(), self).transaction_hash();
        let signature = self.signer.sign_hash(&tx_hash).await?;
        Ok(vec![signature.r, signature.s])
    }
}