//! Example: Decoding a token and getting proofs using WalletRepository
//!
//! This example demonstrates how to:
//! 1. Create a WalletRepository
//! 2. Decode a cashu token
//! 3. Use `get_token_data` to extract mint URL and proofs in one call
//! 4. Alternatively, get keysets manually and extract proofs

use std::str::FromStr;
use std::sync::Arc;

use cdk::nuts::nut00::ProofsMethods;
use cdk::nuts::Token;
use cdk::wallet::WalletRepositoryBuilder;
use cdk_sqlite::wallet::memory;
use rand::random;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Generate a random seed for the wallet
    let seed = random::<[u8; 64]>();

    // Initialize the memory store
    let localstore = Arc::new(memory::empty().await?);

    // Create a new WalletRepository
    let wallet = WalletRepositoryBuilder::new()
        .localstore(localstore)
        .seed(seed)
        .build()
        .await?;

    // Example: A cashu token string (in practice, this would come from user input)
    let token = Token::from_str("cashuBo2FteB1odHRwczovL2Zha2UudGhlc2ltcGxla2lkLmRldmF1Y3NhdGF0gaJhaUgAlNWndMQKMmFwg6RhYRkIAGFzeEAwYjk0ZjU5ZjU0OTBkNTkzMzI4ZTIwNDllZTNlZmFjYjM5NzljZjU5NzA5ZTM3N2U5YzBmMDQyNDBmZTUyZTVhYWNYIQNGQCYyf1j996pS-LuP_7VsUE-uzRpAm-K4rZiDEFFc1GFko2FlWCBbuMkhvz39ytCzm7xPaY5vdTbqxlxTzXOsks_8S3sf1GFzWCBg22l0CXH5-QLcfJtUJZ2lfylNfC6_o9FTfKClLzthaGFyWCCP2nJ6Qzd8mwLa_85cu8TrwRIprElVgrhqJeoHJwXmSKRhYRkCAGFzeEBhNmMyODliMjMwMTdlMDhjYTFhOTc4ZjAwNGRiNjI4ZDk1NWI5ZTlmNjMwMjY0MjNjZDc4OGExNDBhOWJiYjgxYWNYIQPMXkT68L8Y0a6royMbkoUTbvxOUgsyDwvRZRNTvwUsWWFko2FlWCCj9BFXexBOrlUyUiY_1qEIEHvd1YphWA2l3YhdFwVRh2FzWCBTNgyGeXvGSFtvYKj3MnJCXA8qjI9fzZHFsIw-F_OAGmFyWCDRHiDbVysUuQZucifYx5zMvOKyVIz7zvcJcfd01FoI3KRhYQhhc3hAMWJjOWQ1MjE5ZTZhYzNjZmZhNTM0NTRkY2JjMzE1YzZjZjY5NmM5MDEzYTUzYTA1YzIzN2YwZTBiOTViZTkwMWFjWCEDXd5sxFgxYgUHctpLENYStcr50UtJ4QRojy0g7mkdvWRhZKNhZVggZzSifCUG692E2sW4L6DT_FuKwLZdUFoMnds3tQyMlAdhc1ggtIo0BS2-6arws5fJx_w0phOiCZZcHIFknlrDXSh3C0NhclggM2dDF0kQyuRoOqrOOMHFrmNnvtGiXWxuvqtD7HidR8I")?;

    // Get the mint URL from the token
    let mint_url = token.mint_url()?;
    println!("Token mint URL: {}", mint_url);

    // Get token value
    let value = token.value()?;
    println!("Token value: {} sats", value);

    // Get token memo if present
    if let Some(memo) = token.memo() {
        println!("Token memo: {}", memo);
    }

    // Add the mint to our wallet so we can fetch keysets
    wallet.add_wallet(mint_url.clone()).await?;

    // =========================================================================
    // Method 1: Use get_token_data() for a simple one-call approach
    // =========================================================================
    println!("\n--- Using get_token_data() ---");

    let token_data = wallet.get_token_data(&token).await?;
    println!("Mint URL: {}", token_data.mint_url);
    println!("Number of proofs: {}", token_data.proofs.len());

    for (i, proof) in token_data.proofs.iter().enumerate() {
        println!(
            "  Proof {}: {} sats, keyset: {}",
            i + 1,
            proof.amount,
            proof.keyset_id
        );
    }

    // =========================================================================
    // Method 2: Manual approach - get keysets first, then extract proofs
    // =========================================================================
    println!("\n--- Using manual keyset lookup ---");

    // Get the keysets for this mint using a wallet
    let mint_wallet = wallet
        .get_wallets_for_mint(&mint_url)
        .await
        .into_iter()
        .next()
        .ok_or("No wallet found for mint")?;
    let keysets: Vec<cdk::nuts::KeySetInfo> = mint_wallet.get_mint_keysets().await?;
    println!("Found {} keysets for mint", keysets.len());

    for keyset in &keysets {
        println!(
            "  - Keyset ID: {}, Unit: {:?}, Active: {}",
            keyset.id, keyset.unit, keyset.active
        );
    }

    // Extract proofs from the token using the keysets
    let proofs = token.proofs(&keysets)?;
    println!("\nToken contains {} proofs:", proofs.len());

    // Calculate total amount from proofs
    let total = proofs.total_amount()?;
    println!("Total amount from proofs: {} sats", total);

    // Verify total matches token value
    assert_eq!(total, value, "Proof total should match token value");

    println!("\nSuccessfully decoded token and extracted proofs!");

    Ok(())
}
