#!/usr/bin/env python3
# Copyright (c) Subzero Labs, Inc.
# SPDX-License-Identifier: Apache-2.0

"""
Transaction operations example demonstrating complete transaction building functionality.

This example shows how to use the TransactionBuilder to create, sign, and send transactions
on the Rialo blockchain, including transfer instructions and custom instructions.
"""

from rialo_py_cdk import (
    generate_keypair,
    Wallet,
    PublicKey,
    Hash,
    HttpRpcClient,
    TransactionBuilder,
    transfer_instruction,
    rlo_to_kelvin,
    kelvin_to_rlo,
    get_localnet_url,
)
import time


def transaction_operations_example():
    """Run transaction operations example demonstrating transaction-related functionality."""
    print('📝 Starting Rialo CDK Transaction Operations Example\n')

    try:
        # 1. Create a wallet for transaction operations
        print('1. Creating wallet...')
        keypair = generate_keypair()
        wallet = Wallet('transaction-wallet', keypair)
        print(f'   Wallet address: {wallet.get_public_key_string()}')

        # 2. Create a mock recipient address
        print('2. Creating recipient address...')
        recipient_keypair = generate_keypair()
        recipient_wallet = Wallet('recipient-wallet', recipient_keypair)
        recipient_pubkey = recipient_wallet.get_public_key()
        print(f'   Recipient address: {recipient_pubkey}')

        # 3. Create RPC client for transaction operations
        print('3. Creating RPC client...')
        client = HttpRpcClient(get_localnet_url())
        print(f'   RPC client created for: {get_localnet_url()}')

        # 4. Demonstrate account balance checking
        print('4. Checking account balances...')
        try:
            sender_balance = client.get_balance(wallet.get_public_key())
            print(f'   Sender balance: {sender_balance} kelvin')
        except Exception as error:
            print(f'   Sender balance: 0 kelvin (account may not exist: {error})')

        try:
            recipient_balance = client.get_balance(recipient_pubkey)
            print(f'   Recipient balance: {recipient_balance} kelvin')
        except Exception as error:
            print(f'   Recipient balance: 0 kelvin (account may not exist: {error})')

        # 5. Demonstrate account info retrieval
        print('5. Getting account information...')
        try:
            account_info = client.get_account_info(wallet.get_public_key())
            print(f'   Account info retrieved: {type(account_info)}')
            print(f'   Account data available: {len(account_info.get("data", []))} bytes')
        except Exception as error:
            print(f'   Account info not available: {error}')

        # 6. Demonstrate transaction count and slot information
        print('6. Getting blockchain state information...')
        try:
            tx_count = client.get_transaction_count()
            print(f'   Transaction count: {tx_count}')
        except Exception as error:
            print(f'   Could not get transaction count: {error}')

        # 7. Demonstrate rent exemption calculation (useful for transaction fees)
        print('7. Calculating rent exemption...')
        try:
            data_size = 1024  # 1KB of data
            min_balance = client.get_minimum_balance_for_rent_exemption(data_size)
            print(f'   Minimum balance for {data_size} bytes: {min_balance} kelvin')
        except Exception as error:
            print(f'   Could not calculate rent exemption: {error}')

        # 8. Demonstrate message signing (core to transactions)
        print('8. Demonstrating message signing...')
        transaction_message = b'Mock transaction data for signing'
        signature = wallet.sign(transaction_message)
        print(f'   Transaction message signed')
        print(f'   Signature: {signature}')
        print(f'   Signature length: {len(signature)} bytes')

        # 9. Create real transaction using TransactionBuilder
        print('9. Building real transaction with TransactionBuilder...')
        
        # Create TransactionBuilder with payer and blockhash
        payer_pubkey = wallet.get_public_key()
        valid_from = int(time.time() * 1000)  # Current time in milliseconds
        builder = TransactionBuilder(payer_pubkey, valid_from)
        print(f'   TransactionBuilder created with payer: {payer_pubkey}')
        
        # Add a transfer instruction (small amount for demonstration)
        transfer_amount = rlo_to_kelvin(0.001)  # 0.001 RLO = 1,000,000 kelvin
        builder.add_transfer_instruction(
            payer_pubkey,     # from (sender)
            recipient_pubkey, # to (recipient) 
            transfer_amount   # amount in kelvin
        )
        print(f'   Transfer instruction added: {kelvin_to_rlo(transfer_amount):.6f} RLO')
        
        # Build the transaction message without signing
        try:
            message_bytes = builder.build()
            print(f'   Transaction message built: {len(message_bytes)} bytes')
        except Exception as error:
            print(f'   Transaction building failed: {error}')
            # Continue with demonstration using mock bytes
            message_bytes = b'mock_transaction_bytes'

        # 10. Sign the transaction 
        print('10. Signing transaction with wallet...')
        try:
            signed_tx_bytes = builder.sign(wallet)
            print(f'   ✅ Transaction signed successfully: {len(signed_tx_bytes)} bytes')
        except Exception as error:
            print(f'   Transaction signing failed: {error}')
            signed_tx_bytes = b'mock_signed_transaction'

        # 11. Demonstrate transaction sending
        print('11. Attempting to send signed transaction...')
        try:
            tx_signature = client.send_transaction(signed_tx_bytes)
            print(f'   ✅ Transaction sent successfully! Signature: {tx_signature}')
        except Exception as error:
            print(f'   ⚠️  Transaction send failed (expected without funded account): {error}')
            print('   This is expected behavior - accounts need funding for transfers')

        # 12. Custom instruction demonstration
        print('12. Creating custom instruction...')
        try:
            # Create a custom instruction using the transfer_instruction helper
            custom_instruction = transfer_instruction(payer_pubkey, recipient_pubkey, rlo_to_kelvin(0.002))
            print(f'   ✅ Custom transfer instruction created')
            print(f'   Program ID: {custom_instruction.program_id}')
            print(f'   Accounts: {len(custom_instruction.accounts)}')
            print(f'   Data length: {len(custom_instruction.data)} bytes')
            
            # Create a new builder and add the custom instruction
            valid_from = int(time.time() * 1000)  # Current time in milliseconds
            custom_builder = TransactionBuilder(payer_pubkey, valid_from)
            custom_builder.add_instruction(custom_instruction)
            print(f'   ✅ Custom instruction added to new transaction builder')
            
        except Exception as error:
            print(f'   Custom instruction creation failed: {error}')

        # 13. Transaction operations summary
        print('13. Transaction operations summary...')
        print('    📚 This example demonstrates:')
        print('    - Creating wallets for transaction participants')
        print('    - Getting blockchain state (blockhash, slot, transaction count)')
        print('    - Checking account balances and information')
        print('    - Calculating rent exemptions for transaction fees')
        print('    - Message signing for transaction authentication')
        print('    - ✅ REAL TransactionBuilder usage with transfer instructions')
        print('    - ✅ Building, signing, and sending actual transactions')
        print('    - ✅ Custom instruction creation and usage')
        print('    - Unit conversions between RLO and kelvin')
        print('    - Proper error handling for transaction failures')

        # 14. TransactionBuilder API reference
        print('14. TransactionBuilder API reference...')
        print('    📖 Available TransactionBuilder methods:')
        print('    - TransactionBuilder(payer_pubkey, valid_from)')
        print('    - builder.add_transfer_instruction(from, to, amount)')
        print('    - builder.add_instruction(custom_instruction)')
        print('    - builder.build() → unsigned_transaction_bytes')
        print('    - builder.sign(wallet) → signed_transaction_bytes')
        print('    - builder.sign_with_account(wallet, account_index)')
        print('    - client.send_transaction(signed_transaction_bytes)')
        print('    📖 Helper functions:')
        print('    - transfer_instruction(from, to, amount) → Instruction')
        print('    - rlo_to_kelvin(rlo_amount) → kelvin_amount')
        print('    - kelvin_to_rlo(kelvin_amount) → rlo_amount')

        print('\n✅ Transaction operations completed successfully!')

    except Exception as error:
        print(f'❌ Error during transaction operations: {error}')
        raise error


def main():
    """Run the transaction operations example."""
    try:
        transaction_operations_example()
        print('🎉 Transaction operations example finished!')
    except Exception as error:
        print(f'💥 Transaction operations example failed: {error}')
        import traceback
        traceback.print_exc()
        exit(1)


if __name__ == "__main__":
    main()