// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use rialo_cdk::{
    constants::ConfigHashPrefix,
    rpc::types::Pubkey,
    transaction::builder::{deserialize_message, TransactionBuilder},
};

#[test]
fn test_message_serialization_deserialization_roundtrip() {
    // Create test data with valid base58 keys (32 bytes when decoded)
    let payer = Pubkey::new_from_array([1; 32]);
    let valid_from = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .expect("Time went backwards")
        .as_millis() as i64;
    let from = Pubkey::new_from_array([3; 32]);
    let to = Pubkey::new_from_array([4; 32]);
    let amount = 1000000000u64;

    // Build a transaction with transfer instruction
    let config_hash_prefix = ConfigHashPrefix::new(1);
    let mut builder = TransactionBuilder::new(payer, valid_from, config_hash_prefix);
    builder.add_transfer_instruction(&from, &to, amount);

    // Build the message
    let message_bytes = builder.build().unwrap();

    // Deserialize the message
    let deserialized = deserialize_message(&message_bytes).unwrap();

    // Verify header
    assert!(deserialized.header.num_required_signatures > 0);

    // Verify accounts contain payer, from, to
    assert!(deserialized.account_keys.contains(&payer));
    assert!(deserialized.account_keys.contains(&from));
    assert!(deserialized.account_keys.contains(&to));

    // Verify instructions
    assert_eq!(deserialized.instructions.len(), 1);
    let instruction = &deserialized.instructions[0];

    // Verify the instruction accounts contain from and to
    assert!(instruction.accounts.contains(&from));
    assert!(instruction.accounts.contains(&to));

    // Verify instruction data (should contain the amount)
    assert!(!instruction.data.is_empty());

    println!("✅ Message deserialization test passed!");
    println!("  Header: {:?}", deserialized.header);
    println!(
        "  Account keys: {} accounts",
        deserialized.account_keys.len()
    );
    println!(
        "  Instructions: {} instructions",
        deserialized.instructions.len()
    );
    println!(
        "  Instruction 0: program={}, accounts={}, data_len={}",
        instruction.program_id,
        instruction.accounts.len(),
        instruction.data.len()
    );
}

#[test]
fn test_transaction_deserialization_method() {
    // Create test data with valid keys
    let payer = Pubkey::new_from_array([5; 32]);
    let valid_from = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .expect("Time went backwards")
        .as_millis() as i64;
    let from = Pubkey::new_from_array([7; 32]);
    let to = Pubkey::new_from_array([8; 32]);

    // Build a transaction
    let config_hash_prefix = ConfigHashPrefix::new(1);
    let mut builder = TransactionBuilder::new(payer, valid_from, config_hash_prefix);
    builder.add_transfer_instruction(&from, &to, 500000000);
    let transaction = builder.build_transaction().unwrap();

    // Use the new deserialize_message method on Transaction
    let deserialized = transaction.deserialize_message().unwrap();

    // Verify we can access instruction data
    assert!(!deserialized.instructions.is_empty());
    for (i, instruction) in deserialized.instructions.iter().enumerate() {
        println!(
            "Instruction {}: program={}, accounts={:?}, data_len={}",
            i,
            instruction.program_id,
            instruction.accounts,
            instruction.data.len()
        );
        // User can now inspect instruction.data to show transaction side effects
    }

    println!("✅ Transaction.deserialize_message() test passed!");
}
