/// You can use account key pooling to use different keys for consecutive transactions
/// to avoid nonce-related issues.
///
/// This is an example of how to use account key pooling to send multiple transactions
/// using different keys.
use near_api::{
    signer::generate_secret_key,
    types::{AccessKeyPermission, AccountId, NearToken},
    Account, NetworkConfig, Signer, Tokens,
};
use near_sandbox::{
    config::{DEFAULT_GENESIS_ACCOUNT, DEFAULT_GENESIS_ACCOUNT_PRIVATE_KEY},
    GenesisAccount, SandboxConfig,
};
use testresult::TestResult;

use std::sync::Arc;

#[tokio::main]
async fn main() -> TestResult {
    let account: AccountId = DEFAULT_GENESIS_ACCOUNT.into();
    let second_account = GenesisAccount::generate_with_name("second_account".parse()?);

    let sandbox = near_sandbox::Sandbox::start_sandbox_with_config(SandboxConfig {
        additional_accounts: vec![second_account.clone()],
        ..Default::default()
    })
    .await?;
    let network = NetworkConfig::from_rpc_url("sandbox", sandbox.rpc_addr.parse()?);
    let signer = Signer::from_secret_key(DEFAULT_GENESIS_ACCOUNT_PRIVATE_KEY.parse()?)?;

    println!("Initial public key: {}", signer.get_public_key().await?);

    let secret_key = generate_secret_key()?;
    println!("New public key: {}", secret_key.public_key());

    Account(account.clone())
        .add_key(AccessKeyPermission::FullAccess, secret_key.public_key())
        .with_signer(Arc::clone(&signer))
        .send_to(&network)
        .await?
        .assert_success();

    signer.add_secret_key_to_pool(secret_key).await?;

    let txs = (0..2).map(|_| {
        Tokens::account(account.clone())
            .send_to(second_account.account_id.clone())
            .near(NearToken::from_millinear(1))
            .with_signer(Arc::clone(&signer))
            .send_to(&network)
    });
    let results = futures::future::join_all(txs)
        .await
        .into_iter()
        .collect::<Result<Vec<_>, _>>()?;

    assert_eq!(results.len(), 2);
    results.clone().into_iter().for_each(|e| {
        e.assert_success();
    });
    println!(
        "Transaction one public key: {}",
        results[0].transaction().public_key()
    );
    println!(
        "Transaction two public key: {}",
        results[1].transaction().public_key()
    );
    assert_ne!(
        results[0].transaction().public_key(),
        results[1].transaction().public_key()
    );

    println!("All transactions are successful");

    Ok(())
}
