use log::{debug, info};
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3_log;

use base58::FromBase58;
use serde::{Deserialize, Serialize};

use solana_client::nonblocking::rpc_client::RpcClient;
use solana_client::rpc_config::RpcSendTransactionConfig;
use solana_sdk::{
    commitment_config::{CommitmentConfig, CommitmentLevel},
    compute_budget::ComputeBudgetInstruction,
    instruction::{AccountMeta, Instruction},
    pubkey::Pubkey,
    signature::{Keypair, Signer},
    system_instruction,
    transaction::Transaction,
};
use spl_associated_token_account::{
    get_associated_token_address, instruction::create_associated_token_account_idempotent,
};
use spl_token::instruction as token_instruction;

use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::Path;
use std::str::FromStr;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::{Arc, RwLock};
use std::time::{SystemTime, UNIX_EPOCH};

// Constants
const COMPUTE_UNITS: u32 = 50_000;
const PRIORITY_FEE: u64 = 750_000;
const LAMPORTS_PER_SOL: u64 = 1_000_000_000;
const DEFAULT_RPC_RATE_LIMIT: u64 = 5; // 5 RPC calls per second
const MAX_RETRY_COUNT: u8 = 3;
const RETRY_DELAY_MS: u64 = 100;

// Rate limiter for RPC calls
struct RateLimiter {
    call_count: AtomicU64,
    last_reset: AtomicU64,
    limit_per_second: AtomicU64,
}

impl RateLimiter {
    fn new(limit_per_second: u64) -> Self {
        Self {
            call_count: AtomicU64::new(0),
            last_reset: AtomicU64::new(
                SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .unwrap()
                    .as_secs(),
            ),
            limit_per_second: AtomicU64::new(limit_per_second),
        }
    }

    fn check_and_increment(&self) -> bool {
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs();
        let last_reset = self.last_reset.load(Ordering::Relaxed);

        if now > last_reset {
            // Reset counter if we're in a new second
            self.call_count.store(0, Ordering::Relaxed);
            self.last_reset.store(now, Ordering::Relaxed);
        }

        let count = self.call_count.fetch_add(1, Ordering::Relaxed);
        let limit = self.limit_per_second.load(Ordering::Relaxed);

        count < limit
    }

    fn set_limit(&self, limit: u64) {
        self.limit_per_second.store(limit, Ordering::Relaxed);
    }
}

// Define TokenPairSetting first before it's used in TradingConfig
#[pyclass]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TokenPairSetting {
    #[pyo3(get, set)]
    pub token_mint: String,
    #[pyo3(get, set)]
    pub amm_id: String,
    #[pyo3(get, set)]
    pub amm_authority: String,
    #[pyo3(get, set)]
    pub amm_open_orders: String,
    #[pyo3(get, set)]
    pub amm_target: String,
    #[pyo3(get, set)]
    pub pool_token_account: String,
    #[pyo3(get, set)]
    pub pool_pc_account: String,
    #[pyo3(get, set)]
    pub min_liquidity_pct: f64,
    #[pyo3(get, set)]
    pub min_exit_liquidity_sol: f64,
    #[pyo3(get, set)]
    pub auth_revoked: bool,
    #[pyo3(get, set)]
    pub buyer_seller_ratio: f64,
    #[pyo3(get, set)]
    pub min_volume_5m: f64,
    #[pyo3(get, set)]
    pub enabled: bool,
}

#[pymethods]
impl TokenPairSetting {
    #[new]
    fn new(
        token_mint: String,
        amm_id: String,
        amm_authority: String,
        amm_open_orders: String,
        amm_target: String,
        pool_token_account: String,
        pool_pc_account: String,
        min_liquidity_pct: Option<f64>,
        min_exit_liquidity_sol: Option<f64>,
        auth_revoked: Option<bool>,
        buyer_seller_ratio: Option<f64>,
        min_volume_5m: Option<f64>,
        enabled: Option<bool>,
    ) -> Self {
        Self {
            token_mint,
            amm_id,
            amm_authority,
            amm_open_orders,
            amm_target,
            pool_token_account,
            pool_pc_account,
            min_liquidity_pct: min_liquidity_pct.unwrap_or(95.0),
            min_exit_liquidity_sol: min_exit_liquidity_sol.unwrap_or(5.0),
            auth_revoked: auth_revoked.unwrap_or(true),
            buyer_seller_ratio: buyer_seller_ratio.unwrap_or(1.0),
            min_volume_5m: min_volume_5m.unwrap_or(10.0),
            enabled: enabled.unwrap_or(true),
        }
    }
}

// Dynamic configuration structure
#[pyclass]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TradingConfig {
    #[pyo3(get, set)]
    pub rpc_url: String,
    #[pyo3(get, set)]
    pub ws_url: String,
    #[pyo3(get, set)]
    pub api_key: String,

    #[pyo3(get, set)]
    pub sol_mint: String,
    #[pyo3(get, set)]
    pub rpc_rate_limit: u64,

    // Additional fields from Python code
    #[pyo3(get, set)]
    pub token_mint: Option<String>,
    #[pyo3(get, set)]
    pub amm_program: Option<String>,

    #[pyo3(get, set)]
    pub compute_limit: u32,
    #[pyo3(get, set)]
    pub priority_fee: u64,
    #[pyo3(get, set)]
    pub skip_preflight: bool,
    #[pyo3(get, set)]
    pub max_retries: u8,

    #[pyo3(get, set)]
    pub front_run_amount: f64,
    #[pyo3(get, set)]
    pub min_victim_size: f64,
    #[pyo3(get, set)]
    pub max_victim_size: f64,
    #[pyo3(get, set)]
    pub min_profit: f64,
    #[pyo3(get, set)]
    pub slippage_bps: u16,

    #[pyo3(get, set)]
    pub min_sol_balance: f64,
    #[pyo3(get, set)]
    pub min_wsol_balance: f64,

    // Additional market parameters from Python code
    #[pyo3(get, set)]
    pub amm_id: Option<String>,
    #[pyo3(get, set)]
    pub market_amm_authority: Option<String>,
    #[pyo3(get, set)]
    pub market_amm_open_orders: Option<String>,
    #[pyo3(get, set)]
    pub market_amm_target: Option<String>,
    #[pyo3(get, set)]
    pub market_pool_token_account: Option<String>,
    #[pyo3(get, set)]
    pub market_pool_pc_token_account: Option<String>,

    #[pyo3(get, set)]
    pub raydium_program_id: String,
    #[pyo3(get, set)]
    pub token_program_id: String,
    #[pyo3(get, set)]
    pub system_program_id: String,
    #[pyo3(get, set)]
    pub associated_token_program_id: String,

    // For storing token pair specific settings
    #[pyo3(get)]
    pub token_pair_settings: HashMap<String, TokenPairSetting>,
}

#[pymethods]
impl TradingConfig {
    #[new]
    fn new(
        rpc_url: Option<String>,
        ws_url: Option<String>,
        api_key: Option<String>,
        sol_mint: Option<String>,
        rpc_rate_limit: Option<u64>,
        compute_limit: Option<u32>,
        priority_fee: Option<u64>,
        skip_preflight: Option<bool>,
        max_retries: Option<u8>,
        front_run_amount: Option<f64>,
        min_victim_size: Option<f64>,
        max_victim_size: Option<f64>,
        min_profit: Option<f64>,
        slippage_bps: Option<u16>,
        min_sol_balance: Option<f64>,
        min_wsol_balance: Option<f64>,
        raydium_program_id: Option<String>,
        token_program_id: Option<String>,
        system_program_id: Option<String>,
        associated_token_program_id: Option<String>,
        // Additional parameters from Python code
        token_mint: Option<String>,
        amm_program: Option<String>,
        amm_id: Option<String>,
        market_amm_authority: Option<String>,
        market_amm_open_orders: Option<String>,
        market_amm_target: Option<String>,
        market_pool_token_account: Option<String>,
        market_pool_pc_token_account: Option<String>,
    ) -> Self {
        Self {
            rpc_url: rpc_url.unwrap_or_else(|| {
                env::var("RPC_URL")
                    .unwrap_or_else(|_| "https://api.mainnet-beta.solana.com".to_string())
            }),
            ws_url: ws_url.unwrap_or_else(|| {
                env::var("WS_URL")
                    .unwrap_or_else(|_| "wss://api.mainnet-beta.solana.com".to_string())
            }),
            api_key: api_key
                .unwrap_or_else(|| env::var("API_KEY").unwrap_or_else(|_| "".to_string())),
            sol_mint: sol_mint.unwrap_or_else(|| {
                env::var("SOL_MINT")
                    .unwrap_or_else(|_| "So11111111111111111111111111111111111111112".to_string())
            }),
            rpc_rate_limit: rpc_rate_limit.unwrap_or_else(|| {
                env::var("RPC_RATE_LIMIT")
                    .map(|v| v.parse().unwrap_or(DEFAULT_RPC_RATE_LIMIT))
                    .unwrap_or(DEFAULT_RPC_RATE_LIMIT)
            }),
            // Store additional fields
            token_mint,
            amm_program,
            compute_limit: compute_limit.unwrap_or_else(|| {
                env::var("COMPUTE_LIMIT")
                    .map(|v| v.parse().unwrap_or(COMPUTE_UNITS))
                    .unwrap_or(COMPUTE_UNITS)
            }),
            priority_fee: priority_fee.unwrap_or_else(|| {
                env::var("PRIORITY_FEE")
                    .map(|v| v.parse().unwrap_or(PRIORITY_FEE))
                    .unwrap_or(PRIORITY_FEE)
            }),
            skip_preflight: skip_preflight.unwrap_or_else(|| {
                env::var("SKIP_PREFLIGHT")
                    .map(|v| v.parse().unwrap_or(true))
                    .unwrap_or(true)
            }),
            max_retries: max_retries.unwrap_or_else(|| {
                env::var("MAX_RETRIES")
                    .map(|v| v.parse().unwrap_or(MAX_RETRY_COUNT))
                    .unwrap_or(MAX_RETRY_COUNT)
            }),
            front_run_amount: front_run_amount.unwrap_or_else(|| {
                env::var("FRONT_RUN_AMOUNT")
                    .map(|v| v.parse().unwrap_or(0.35))
                    .unwrap_or(0.35)
            }),
            min_victim_size: min_victim_size.unwrap_or_else(|| {
                env::var("MIN_VICTIM_SIZE")
                    .map(|v| v.parse().unwrap_or(5.0))
                    .unwrap_or(5.0)
            }),
            max_victim_size: max_victim_size.unwrap_or_else(|| {
                env::var("MAX_VICTIM_SIZE")
                    .map(|v| v.parse().unwrap_or(320.0))
                    .unwrap_or(320.0)
            }),
            min_profit: min_profit.unwrap_or_else(|| {
                env::var("MIN_PROFIT")
                    .map(|v| v.parse().unwrap_or(0.002))
                    .unwrap_or(0.002)
            }),
            slippage_bps: slippage_bps.unwrap_or_else(|| {
                env::var("SLIPPAGE_BPS")
                    .map(|v| v.parse().unwrap_or(1000))
                    .unwrap_or(1000)
            }),
            min_sol_balance: min_sol_balance.unwrap_or_else(|| {
                env::var("MIN_SOL_BALANCE")
                    .map(|v| v.parse().unwrap_or(0.03))
                    .unwrap_or(0.03)
            }),
            min_wsol_balance: min_wsol_balance.unwrap_or_else(|| {
                env::var("MIN_WSOL_BALANCE")
                    .map(|v| v.parse().unwrap_or(0.02))
                    .unwrap_or(0.02)
            }),
            // Store additional market parameters
            amm_id,
            market_amm_authority,
            market_amm_open_orders,
            market_amm_target,
            market_pool_token_account,
            market_pool_pc_token_account,
            raydium_program_id: raydium_program_id.unwrap_or_else(|| {
                // If amm_program is provided, use that instead
                amm_program.clone().unwrap_or_else(|| {
                    env::var("RAYDIUM_PROGRAM_ID")
                        .unwrap_or_else(|_| "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string())
                })
            }),
            token_program_id: token_program_id.unwrap_or_else(|| {
                env::var("TOKEN_PROGRAM_ID")
                    .unwrap_or_else(|_| "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA".to_string())
            }),
            system_program_id: system_program_id.unwrap_or_else(|| {
                env::var("SYSTEM_PROGRAM_ID")
                    .unwrap_or_else(|_| "11111111111111111111111111111111".to_string())
            }),
            associated_token_program_id: associated_token_program_id.unwrap_or_else(|| {
                env::var("ASSOCIATED_TOKEN_PROGRAM_ID")
                    .unwrap_or_else(|_| "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL".to_string())
            }),
            token_pair_settings: HashMap::new(),
        }
    }

    // Add a token pair setting
    fn add_token_pair_setting(&mut self, token_pair: TokenPairSetting) -> PyResult<()> {
        // Use token mint as key
        self.token_pair_settings
            .insert(token_pair.token_mint.clone(), token_pair);
        Ok(())
    }

    // Remove a token pair setting
    fn remove_token_pair_setting(&mut self, token_mint: &str) -> PyResult<bool> {
        Ok(self.token_pair_settings.remove(token_mint).is_some())
    }

    // Get a token pair setting
    fn get_token_pair_setting(&self, token_mint: &str) -> PyResult<Option<TokenPairSetting>> {
        Ok(self.token_pair_settings.get(token_mint).cloned())
    }

    // Get all active token mints
    fn get_active_token_mints(&self) -> PyResult<Vec<String>> {
        Ok(self
            .token_pair_settings
            .iter()
            .filter(|(_, v)| v.enabled)
            .map(|(k, _)| k.clone())
            .collect())
    }

    // Save config to file
    fn save_to_file(&self, path: &str) -> PyResult<()> {
        let json = serde_json::to_string_pretty(&self)
            .map_err(|e| PyValueError::new_err(format!("Failed to serialize config: {}", e)))?;

        fs::write(path, json)
            .map_err(|e| PyValueError::new_err(format!("Failed to write config file: {}", e)))?;

        Ok(())
    }

    // Load config from file
    #[staticmethod]
    fn load_from_file(path: &str) -> PyResult<Self> {
        let json = fs::read_to_string(path)
            .map_err(|e| PyValueError::new_err(format!("Failed to read config file: {}", e)))?;

        let config: Self = serde_json::from_str(&json)
            .map_err(|e| PyValueError::new_err(format!("Failed to parse config file: {}", e)))?;

        Ok(config)
    }

    // Load from environment variables
    #[staticmethod]
    fn from_env() -> PyResult<Self> {
        Ok(Self::new(
            None, None, None, None, None, None, None, None, None, None, None, None, None, None,
            None, None, None, None, None, None, None, None, None, None, None, None, None, None,
        ))
    }
}

// Structure to hold swap parameters
#[pyclass]
#[derive(Clone)]
pub struct SwapParams {
    #[pyo3(get, set)]
    pub token_mint: String,
    #[pyo3(get, set)]
    pub amount_in: f64,
    #[pyo3(get, set)]
    pub is_buy: bool,
    #[pyo3(get, set)]
    pub slippage_bps: u16,
    #[pyo3(get, set)]
    pub compute_limit: u32,
    #[pyo3(get, set)]
    pub priority_fee: u64,
}

#[pymethods]
impl SwapParams {
    #[new]
    fn new(
        token_mint: String,
        amount_in: f64,
        is_buy: bool,
        slippage_bps: Option<u16>,
        compute_limit: Option<u32>,
        priority_fee: Option<u64>,
    ) -> Self {
        Self {
            token_mint,
            amount_in,
            is_buy,
            slippage_bps: slippage_bps.unwrap_or(1000),
            compute_limit: compute_limit.unwrap_or(COMPUTE_UNITS),
            priority_fee: priority_fee.unwrap_or(PRIORITY_FEE),
        }
    }
}

// Structure for transaction status tracking
#[pyclass]
#[derive(Clone)]
pub struct TransactionStatus {
    #[pyo3(get)]
    pub signature: String,
    #[pyo3(get)]
    pub success: bool,
    #[pyo3(get)]
    pub error: Option<String>,
    #[pyo3(get)]
    pub timestamp: u64,
    #[pyo3(get)]
    pub simulation_only: bool,
}

#[pymethods]
impl TransactionStatus {
    #[new]
    fn new(
        signature: String,
        success: bool,
        error: Option<String>,
        timestamp: Option<u64>,
        simulation_only: Option<bool>,
    ) -> Self {
        Self {
            signature,
            success,
            error,
            timestamp: timestamp.unwrap_or_else(|| {
                SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .unwrap()
                    .as_secs()
            }),
            simulation_only: simulation_only.unwrap_or(false),
        }
    }
}

// Main trading core class
#[pyclass]
pub struct RaydiumTradingCore {
    client: Arc<RpcClient>,
    keypair: Arc<Keypair>,
    config: Arc<RwLock<TradingConfig>>,
    balances: Arc<RwLock<(f64, HashMap<String, f64>)>>, // (SOL, token balances by mint)
    rate_limiter: Arc<RateLimiter>,
    pending_transaction: Arc<AtomicBool>, // Changed from AtomicBool to Arc<AtomicBool>
    last_trade_time: Arc<AtomicU64>,      // Changed from AtomicU64 to Arc<AtomicU64>
    public_key: String,
}

// Helper function to get observed accounts for a token based on a transaction
fn get_observed_accounts_for_token(token_mint: &str, config: &TradingConfig) -> Vec<Pubkey> {
    // Default to known account structure for this token (if available)
    let mut observed_accounts = Vec::new();
    
    if let Some(token_pair) = config.token_pair_settings.get(token_mint) {
        // Try to parse these as Pubkeys and add them to our list
        if let Ok(authority) = Pubkey::from_str(&token_pair.amm_authority) {
            observed_accounts.push(authority);
        }
        
        if let Ok(open_orders) = Pubkey::from_str(&token_pair.amm_open_orders) {
            observed_accounts.push(open_orders);
        }
        
        if let Ok(target) = Pubkey::from_str(&token_pair.amm_target) {
            observed_accounts.push(target);
        }
        
        if let Ok(pool_token) = Pubkey::from_str(&token_pair.pool_token_account) {
            observed_accounts.push(pool_token);
        }
        
        if let Ok(pool_pc) = Pubkey::from_str(&token_pair.pool_pc_account) {
            observed_accounts.push(pool_pc);
        }
        
        // Add placeholders for Serum accounts
        // In a real implementation, these would come from observed transactions
        for _ in observed_accounts.len()..17 {
            observed_accounts.push(Pubkey::new_unique()); // Random pubkeys for placeholders
        }
    }
    
    // If no token_pair, but market data available in config, use it
    else if let (Some(amm_auth), Some(amm_open), Some(amm_target), Some(pool_token), Some(pool_pc)) = (
        &config.market_amm_authority,
        &config.market_amm_open_orders,
        &config.market_amm_target,
        &config.market_pool_token_account,
        &config.market_pool_pc_token_account
    ) {
        // Try to parse these from config
        if let (Ok(auth), Ok(open), Ok(target), Ok(token), Ok(pc)) = (
            Pubkey::from_str(amm_auth),
            Pubkey::from_str(amm_open),
            Pubkey::from_str(amm_target),
            Pubkey::from_str(pool_token),
            Pubkey::from_str(pool_pc)
        ) {
            observed_accounts.push(auth);
            observed_accounts.push(open);
            observed_accounts.push(target);
            observed_accounts.push(token);
            observed_accounts.push(pc);
            
            // Add placeholders for other accounts
            for _ in observed_accounts.len()..17 {
                observed_accounts.push(Pubkey::new_unique());
            }
        }
    }
    
    observed_accounts
}

// Create swap instruction for Raydium
fn create_raydium_swap_instruction(
    raydium_program_id: &Pubkey,
    source_token_account: &Pubkey, 
    destination_token_account: &Pubkey,
    observed_accounts: Vec<Pubkey>, 
    amount: u64,
    is_buy: bool,
    wallet_pubkey: &Pubkey,
) -> Instruction {
    // Use instruction code 9 (0x09) for Raydium swap
    let mut data = vec![0x09];

    // Append amount as little-endian u64
    data.extend_from_slice(&amount.to_le_bytes());

    // Append minimum amount out (0 for simplicity) as little-endian u64
    let min_amount_out: u64 = 0;
    data.extend_from_slice(&min_amount_out.to_le_bytes());

    // Append swap direction (1 for buy, 0 for sell) as a single byte
    data.push(if is_buy { 1 } else { 0 });

    // Standard Raydium Swap V4 account layout:
    // 1. AMM Authority 
    // 2. AMM Open Orders
    // 3. AMM Target Orders
    // 4. Pool Coin Token Account
    // 5. Pool PC Token Account
    // 6. Source Token Account
    // 7. Destination Token Account
    // 8. Serum Program
    // 9. Serum Market
    // 10. Serum Bids
    // ... etc
    
    // Create account metas
    let mut account_metas = Vec::new();
    
    // Handle differently based on how many observed accounts we have
    if observed_accounts.len() >= 10 {
        // We have enough observed accounts to build a proper instruction
        
        // Start with Raydium program ID
        account_metas.push(AccountMeta::new_readonly(*raydium_program_id, false));
        
        // Use the first 5 observed accounts (AMM accounts)
        for (i, account) in observed_accounts.iter().take(5).enumerate() {
            if i == 0 {
                // AMM Authority is readonly
                account_metas.push(AccountMeta::new_readonly(*account, false));
            } else {
                // Other AMM accounts are writable
                account_metas.push(AccountMeta::new(*account, false));
            }
        }
        
        // Add our source and destination token accounts
        account_metas.push(AccountMeta::new(*source_token_account, false));
        account_metas.push(AccountMeta::new(*destination_token_account, false));
        
        // Add our wallet as signer
        account_metas.push(AccountMeta::new_readonly(*wallet_pubkey, true));
        
        // Add token program
        account_metas.push(AccountMeta::new_readonly(spl_token::id(), false));
        
        // Optionally add more accounts if we have them
        if observed_accounts.len() >= 10 {
            for account in observed_accounts.iter().skip(5).take(5) {
                account_metas.push(AccountMeta::new(*account, false));
            }
        }
    } else {
        // Fallback to minimal setup
        account_metas = vec![
            AccountMeta::new_readonly(*raydium_program_id, false),
            AccountMeta::new(*source_token_account, false),
            AccountMeta::new(*destination_token_account, false),
            AccountMeta::new_readonly(*wallet_pubkey, true),
            AccountMeta::new_readonly(spl_token::id(), false),
        ];
    }

    Instruction {
        program_id: *raydium_program_id,
        accounts: account_metas,
        data,
    }
}

// Python-exposed methods
#[pymethods]
impl RaydiumTradingCore {
    #[new]
fn new(
    rpc_url: Option<String>,
    private_key: Option<String>,
    keypair_path: Option<String>,
    config: Option<TradingConfig>,
) -> PyResult<Self> {
    // Use provided config or create default
    let config_obj = config.unwrap_or_else(|| {
        TradingConfig::new(
            rpc_url.clone(),
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
        )
    });

    // Create RPC client
    let rpc_url = rpc_url.unwrap_or_else(|| config_obj.rpc_url.clone());

    let client = Arc::new(RpcClient::new_with_commitment(
        rpc_url,
        CommitmentConfig::confirmed(),
    ));

    // Load keypair
    let keypair = if let Some(pk) = private_key {
        // Load from base58 string
        let bytes = pk
            .from_base58()
            .map_err(|e| PyValueError::new_err(format!("Invalid private key: {:?}", e)))?;

        Keypair::from_bytes(&bytes)
            .map_err(|e| PyValueError::new_err(format!("Invalid keypair: {}", e)))?
    } else if let Some(path) = keypair_path {
        // Load from file
        if !Path::new(&path).exists() {
            return Err(PyValueError::new_err(format!(
                "Keypair file not found: {}",
                path
            )));
        }

        let keypair = if path.ends_with(".json") {
            let file_content = std::fs::read_to_string(&path).map_err(|e| {
                PyValueError::new_err(format!("Failed to read keypair file: {}", e))
            })?;

            let bytes: Vec<u8> = serde_json::from_str(&file_content)
                .map_err(|e| PyValueError::new_err(format!("Invalid JSON keypair: {}", e)))?;

            Keypair::from_bytes(&bytes)
                .map_err(|e| PyValueError::new_err(format!("Invalid keypair: {}", e)))?
        } else {
            let bytes = std::fs::read(&path).map_err(|e| {
                PyValueError::new_err(format!("Failed to read keypair file: {}", e))
            })?;

            Keypair::from_bytes(&bytes)
                .map_err(|e| PyValueError::new_err(format!("Invalid keypair: {}", e)))?
        };

        keypair
    } else {
        // Try from environment
        let private_key = env::var("SOLANA_PRIVATE_KEY").map_err(|_| {
            PyValueError::new_err("SOLANA_PRIVATE_KEY not found in environment")
        })?;

        let secret_key_bytes = private_key.from_base58().map_err(|e| {
            PyValueError::new_err(format!("Invalid private key encoding: {:?}", e))
        })?;

        Keypair::from_bytes(&secret_key_bytes)
            .map_err(|e| PyValueError::new_err(format!("Invalid keypair: {}", e)))?
    };

    let rate_limiter = Arc::new(RateLimiter::new(config_obj.rpc_rate_limit));
    let public_key = keypair.pubkey().to_string();

    Ok(Self {
        client,
        keypair: Arc::new(keypair),
        config: Arc::new(RwLock::new(config_obj)),
        balances: Arc::new(RwLock::new((0.0, HashMap::new()))),
        rate_limiter,
        pending_transaction: Arc::new(AtomicBool::new(false)),
        last_trade_time: Arc::new(AtomicU64::new(0)),
        public_key,
    })
}

// Get the public key for logging/display
fn get_public_key(&self) -> String {
self.public_key.clone()
}

// Static method to get common keypair paths
#[staticmethod]
fn get_keypair_paths() -> Vec<String> {
vec![
    "keypair.bin".to_string(),
    "id.json".to_string(),
    "../id.json".to_string(),
    "wallet.json".to_string(),
    "wallet.bin".to_string(),
    format!(
        "{}/.config/solana/id.json",
        env::var("HOME").unwrap_or_else(|_| ".".to_string())
    ),
    format!(
        "{}/.config/solana/wallet.json",
        env::var("HOME").unwrap_or_else(|_| ".".to_string())
    ),
]
}

// Update configuration
fn update_config(&self, config: TradingConfig) -> PyResult<()> {
// Update rate limiter
self.rate_limiter.set_limit(config.rpc_rate_limit);

// Update config
match self.config.write() {
    Ok(mut current_config) => {
        *current_config = config;
        Ok(())
    }
    Err(_) => Err(PyValueError::new_err(
        "Failed to update config - lock error",
    )),
}
}

// ML signal update method for use from Python
fn update_ml_signal(&self, key: &str, value: f64) -> PyResult<()> {
debug!("Update ML signal: {} = {}", key, value);
// In a full implementation, this would store the signal
// For now, we'll just log it
Ok(())
}

// Get SOL and token balances - Fixed for the lifetime issue
fn get_balances<'py>(
&self,
py: Python<'py>,
token_mints: Option<Vec<String>>,
) -> PyResult<&'py PyAny> {
// Create strong clones of all needed fields
let client = self.client.clone();
let keypair_pubkey = self.keypair.pubkey();
let balances_arc = self.balances.clone();
let rate_limiter = self.rate_limiter.clone();

// Extract SOL mint from config
let sol_mint_str = match self.config.read() {
    Ok(config) => config.sol_mint.clone(),
    Err(_) => return Err(PyValueError::new_err("Failed to read config")),
};

// Convert to owned values
let token_mints_owned = token_mints.unwrap_or_else(|| vec![]);

pyo3_asyncio::tokio::future_into_py(py, async move {
    // Check rate limit
    if !rate_limiter.check_and_increment() {
        return Err(PyValueError::new_err("RPC rate limit exceeded"));
    }

    // Get SOL balance
    let sol_balance = match client.get_balance(&keypair_pubkey).await {
        Ok(balance) => balance,
        Err(e) => {
            return Err(PyValueError::new_err(format!(
                "Failed to get SOL balance: {}",
                e
            )))
        }
    };

    let sol_balance_f64 = sol_balance as f64 / LAMPORTS_PER_SOL as f64;

    // Get token balances
    let mut token_balances: HashMap<String, f64> = HashMap::new();

    for token_mint_str in token_mints_owned.iter() {
        // Parse token mint
        let token_mint = match Pubkey::from_str(token_mint_str) {
            Ok(pubkey) => pubkey,
            Err(e) => {
                return Err(PyValueError::new_err(format!(
                    "Invalid token mint {}: {}",
                    token_mint_str, e
                )))
            }
        };

        // Get ATA
        let token_ata = get_associated_token_address(&keypair_pubkey, &token_mint);

        // Check rate limit before each RPC call
        if !rate_limiter.check_and_increment() {
            return Err(PyValueError::new_err("RPC rate limit exceeded"));
        }

        // Get token balance
        let token_balance = match client.get_token_account_balance(&token_ata).await {
            Ok(balance) => {
                match balance.amount.parse::<u64>() {
                    Ok(amount) => {
                        // Get token decimals (usually 9 for most SPL tokens, 6 for USDC, etc.)
                        let decimals = balance
                            .ui_amount_string
                            .len()
                            .saturating_sub(balance.amount.len() + 1);
                        let divisor = 10u64.pow(decimals as u32) as f64;
                        amount as f64 / divisor
                    }
                    Err(_) => 0.0,
                }
            }
            Err(_) => 0.0, // ATA might not exist yet
        };

        token_balances.insert(token_mint_str.clone(), token_balance);
    }

    // Don't forget WSOL
    let wsol_pubkey = match Pubkey::from_str(&sol_mint_str) {
        Ok(pk) => pk,
        Err(e) => return Err(PyValueError::new_err(format!("Invalid WSOL pubkey: {}", e))),
    };

    let wsol_ata = get_associated_token_address(&keypair_pubkey, &wsol_pubkey);

    // Check rate limit before RPC call
    if !rate_limiter.check_and_increment() {
        return Err(PyValueError::new_err("RPC rate limit exceeded"));
    }

    // Get WSOL balance
    let wsol_balance = match client.get_token_account_balance(&wsol_ata).await {
        Ok(balance) => match balance.amount.parse::<u64>() {
            Ok(amount) => amount as f64 / LAMPORTS_PER_SOL as f64,
            Err(_) => 0.0,
        },
        Err(_) => 0.0, // ATA might not exist yet
    };

    token_balances.insert(sol_mint_str.clone(), wsol_balance);

    // Update stored balances
    if let Ok(mut balances) = balances_arc.write() {
        *balances = (sol_balance_f64, token_balances.clone());
    }

    // Return as tuple (SOL balance, token balances hashmap)
    Ok((sol_balance_f64, token_balances))
})
}

// Create or ensure Associated Token Account exists - Fixed for the lifetime issue
fn ensure_ata<'py>(&self, py: Python<'py>, token_mint: String) -> PyResult<&'py PyAny> {
let client = self.client.clone();
let keypair = self.keypair.clone();
let rate_limiter = self.rate_limiter.clone();
let token_mint_clone = token_mint.clone();

// Parse token mint
let token_mint_pubkey = match Pubkey::from_str(&token_mint) {
    Ok(pubkey) => pubkey,
    Err(e) => return Err(PyValueError::new_err(format!("Invalid token mint: {}", e))),
};

// Extract program IDs from config
let token_program_id_str = match self.config.read() {
    Ok(config) => config.token_program_id.clone(),
    Err(_) => return Err(PyValueError::new_err("Failed to read config")),
};

pyo3_asyncio::tokio::future_into_py(py, async move {
    // Parse program IDs
    let token_program = match Pubkey::from_str(&token_program_id_str) {
        Ok(pubkey) => pubkey,
        Err(e) => {
            return Err(PyValueError::new_err(format!(
                "Invalid token program ID: {}",
                e
            )))
        }
    };

    // Calculate ATA address
    let ata = get_associated_token_address(&keypair.pubkey(), &token_mint_pubkey);

    // Check if ATA already exists
    if !rate_limiter.check_and_increment() {
        return Err(PyValueError::new_err("RPC rate limit exceeded"));
    }

    match client.get_account(&ata).await {
        Ok(_) => {
            // ATA already exists
            debug!("ATA already exists for token {}: {}", token_mint_clone, ata);
            return Ok(ata.to_string());
        }
        Err(_) => {
            // Need to create ATA
            info!("Creating ATA for token {}", token_mint_clone);

            // Create instruction for ATA creation
            let create_ata_ix = create_associated_token_account_idempotent(
                &keypair.pubkey(),  // Funding address (payer)
                &keypair.pubkey(),  // Wallet address
                &token_mint_pubkey, // Token mint
                &token_program,     // Token program
            );

            // Check rate limit before getting blockhash
            if !rate_limiter.check_and_increment() {
                return Err(PyValueError::new_err("RPC rate limit exceeded"));
            }

            // Get recent blockhash
            let blockhash = match client.get_latest_blockhash().await {
                Ok(blockhash) => blockhash,
                Err(e) => {
                    return Err(PyValueError::new_err(format!(
                        "Failed to get latest blockhash: {}",
                        e
                    )))
                }
            };

            // Create transaction
            let mut tx =
                Transaction::new_with_payer(&[create_ata_ix], Some(&keypair.pubkey()));

            // Sign transaction
            tx.sign(&[&*keypair], blockhash);

            // Send transaction
            if !rate_limiter.check_and_increment() {
                return Err(PyValueError::new_err("RPC rate limit exceeded"));
            }

            match client
                .send_transaction_with_config(
                    &tx,
                    RpcSendTransactionConfig {
                        skip_preflight: true,
                        preflight_commitment: Some(CommitmentLevel::Confirmed),
                        encoding: None,
                        max_retries: Some(3),
                        min_context_slot: None,
                    },
                )
                .await
            {
                Ok(sig) => {
                    info!(
                        "Created ATA for token {}: {} (tx: {})",
                        token_mint_clone, ata, sig
                    );
                    Ok(ata.to_string())
                }
                Err(e) => {
                    // Check if ATA exists now (could be created by another transaction)
                    if e.to_string().contains("already in use") {
                        Ok(ata.to_string())
                    } else {
                        Err(PyValueError::new_err(format!(
                            "Failed to create ATA: {}",
                            e
                        )))
                    }
                }
            }
        }
    }
})
}

// Execute a Raydium swap transaction - Fixed for the lifetime issue
fn execute_swap<'py>(&self, py: Python<'py>, params: SwapParams) -> PyResult<&'py PyAny> {
let client = self.client.clone();
let keypair = self.keypair.clone();
let config_arc = self.config.clone();
let rate_limiter = self.rate_limiter.clone();
let pending_transaction = self.pending_transaction.clone();

// Check if a transaction is already pending
if pending_transaction.load(Ordering::Relaxed) {
    return Err(PyValueError::new_err(
        "A transaction is already in progress",
    ));
}

let params_clone = params.clone();

pyo3_asyncio::tokio::future_into_py(py, async move {
    // Set pending transaction flag
    pending_transaction.store(true, Ordering::Relaxed);

    // Get config values
    let config = match config_arc.read() {
        Ok(config) => config.clone(),
        Err(_) => {
            pending_transaction.store(false, Ordering::Relaxed);
            return Err(PyValueError::new_err("Failed to read config"));
        }
    };

    // Get the token pair settings
    let token_pair = match config.token_pair_settings.get(&params_clone.token_mint) {
        Some(settings) => settings.clone(),
        None => {
            // If the token is not in the token pair settings, check if we have it directly in the config
            if Some(params_clone.token_mint.clone()) == config.token_mint {
                // Create a synthetic token pair from config market values
                if let (Some(amm_id), Some(auth), Some(open), Some(target), Some(token), Some(pc)) = (
                    &config.amm_id,
                    &config.market_amm_authority,
                    &config.market_amm_open_orders,
                    &config.market_amm_target,
                    &config.market_pool_token_account,
                    &config.market_pool_pc_token_account
                ) {
                    TokenPairSetting {
                        token_mint: params_clone.token_mint.clone(),
                        amm_id: amm_id.clone(),
                        amm_authority: auth.clone(),
                        amm_open_orders: open.clone(),
                        amm_target: target.clone(),
                        pool_token_account: token.clone(),
                        pool_pc_account: pc.clone(),
                        min_liquidity_pct: 95.0,
                        min_exit_liquidity_sol: 5.0,
                        auth_revoked: true,
                        buyer_seller_ratio: 1.0,
                        min_volume_5m: 10.0,
                        enabled: true,
                    }
                } else {
                    pending_transaction.store(false, Ordering::Relaxed);
                    return Err(PyValueError::new_err(format!(
                        "Token pair settings not found for {}",
                        params_clone.token_mint
                    )));
                }
            } else {
                pending_transaction.store(false, Ordering::Relaxed);
                return Err(PyValueError::new_err(format!(
                    "Token pair settings not found for {}",
                    params_clone.token_mint
                )));
            }
        }
    };

    // Parse all the pubkeys
    let token_mint_pubkey = match Pubkey::from_str(&params_clone.token_mint) {
        Ok(pubkey) => pubkey,
        Err(e) => {
            pending_transaction.store(false, Ordering::Relaxed);
            return Err(PyValueError::new_err(format!("Invalid token mint: {}", e)));
        }
    };

    let sol_mint_pubkey = match Pubkey::from_str(&config.sol_mint) {
        Ok(pubkey) => pubkey,
        Err(e) => {
            pending_transaction.store(false, Ordering::Relaxed);
            return Err(PyValueError::new_err(format!("Invalid SOL mint: {}", e)));
        }
    };

    let raydium_program_id = match Pubkey::from_str(&config.raydium_program_id) {
        Ok(pubkey) => pubkey,
        Err(e) => {
            pending_transaction.store(false, Ordering::Relaxed);
            return Err(PyValueError::new_err(format!(
                "Invalid Raydium program ID: {}",
                e
            )));
        }
    };

    let token_program_id = match Pubkey::from_str(&config.token_program_id) {
        Ok(pubkey) => pubkey,
        Err(e) => {
            pending_transaction.store(false, Ordering::Relaxed);
            return Err(PyValueError::new_err(format!(
                "Invalid token program ID: {}",
                e
            )));
        }
    };

    // Get associated token accounts
    let user_wsol_ata = get_associated_token_address(&keypair.pubkey(), &sol_mint_pubkey);
    let user_token_ata =
        get_associated_token_address(&keypair.pubkey(), &token_mint_pubkey);

    // Prepare instructions for creating ATAs if needed
    let mut instructions = Vec::new();

    // Check if ATAs exist and add creation instructions if needed
    if !rate_limiter.check_and_increment() {
        pending_transaction.store(false, Ordering::Relaxed);
        return Err(PyValueError::new_err("RPC rate limit exceeded"));
    }

    let wsol_account_exists = client.get_account(&user_wsol_ata).await.is_ok();
    if !wsol_account_exists {
        let create_wsol_ata_ix = create_associated_token_account_idempotent(
            &keypair.pubkey(),
            &keypair.pubkey(),
            &sol_mint_pubkey,
            &token_program_id,
        );
        instructions.push(create_wsol_ata_ix);
    }

    if !rate_limiter.check_and_increment() {
        pending_transaction.store(false, Ordering::Relaxed);
        return Err(PyValueError::new_err("RPC rate limit exceeded"));
    }

    let token_account_exists = client.get_account(&user_token_ata).await.is_ok();
    if !token_account_exists {
        let create_token_ata_ix = create_associated_token_account_idempotent(
            &keypair.pubkey(),
            &keypair.pubkey(),
            &token_mint_pubkey,
            &token_program_id,
        );
        instructions.push(create_token_ata_ix);
    }

    // Convert amount to lamports
    let amount_lamports = (params_clone.amount_in * LAMPORTS_PER_SOL as f64) as u64;

    // If buying and amount > 0, we need to wrap SOL first
    if params_clone.is_buy && amount_lamports > 0 {
        // Transfer SOL to WSOL ATA
        let transfer_ix = system_instruction::transfer(
            &keypair.pubkey(),
            &user_wsol_ata,
            amount_lamports,
        );
        instructions.push(transfer_ix);

        // Synchronize WSOL
        let sync_ix =
            match token_instruction::sync_native(&token_program_id, &user_wsol_ata) {
                Ok(ix) => ix,
                Err(e) => {
                    pending_transaction.store(false, Ordering::Relaxed);
                    return Err(PyValueError::new_err(format!(
                        "Failed to create sync instruction: {}",
                        e
                    )));
                }
            };
        instructions.push(sync_ix);
    }

    // For sells with amount_in == 0, we need to get current token balance
    let actual_amount = if !params_clone.is_buy && params_clone.amount_in == 0.0 {
        if !rate_limiter.check_and_increment() {
            pending_transaction.store(false, Ordering::Relaxed);
            return Err(PyValueError::new_err("RPC rate limit exceeded"));
        }

        match client.get_token_account_balance(&user_token_ata).await {
            Ok(balance) => match balance.amount.parse::<u64>() {
                Ok(amount) => amount,
                Err(_) => {
                    pending_transaction.store(false, Ordering::Relaxed);
                    return Err(PyValueError::new_err("Failed to parse token balance"));
                }
            },
            Err(e) => {
                pending_transaction.store(false, Ordering::Relaxed);
                return Err(PyValueError::new_err(format!(
                    "Failed to get token balance: {}",
                    e
                )));
            }
        }
    } else {
        amount_lamports
    };

    // Get observed accounts for this token
    let observed_accounts = get_observed_accounts_for_token(&params_clone.token_mint, &config);

    // Create the Raydium swap instruction
    let swap_instruction = create_raydium_swap_instruction(
        &raydium_program_id,
        if params_clone.is_buy {
            &user_wsol_ata
        } else {
            &user_token_ata
        },
        if params_clone.is_buy {
            &user_token_ata
        } else {
            &user_wsol_ata
        },
        observed_accounts,
        actual_amount,
        params_clone.is_buy,
        &keypair.pubkey(),
    );

    instructions.push(swap_instruction);

    // Add compute budget instructions
    let compute_budget_ix =
        ComputeBudgetInstruction::set_compute_unit_limit(params_clone.compute_limit);
    let priority_fee_ix =
        ComputeBudgetInstruction::set_compute_unit_price(params_clone.priority_fee);

    instructions.insert(0, priority_fee_ix);
    instructions.insert(0, compute_budget_ix);

    // Get recent blockhash
    if !rate_limiter.check_and_increment() {
        pending_transaction.store(false, Ordering::Relaxed);
        return Err(PyValueError::new_err("RPC rate limit exceeded"));
    }

    let blockhash = match client.get_latest_blockhash().await {
        Ok(blockhash) => blockhash,
        Err(e) => {
            pending_transaction.store(false, Ordering::Relaxed);
            return Err(PyValueError::new_err(format!(
                "Failed to get latest blockhash: {}",
                e
            )));
        }
    };

    // Create transaction
    let mut tx = Transaction::new_with_payer(&instructions, Some(&keypair.pubkey()));

    // Sign transaction
    tx.sign(&[keypair.as_ref()], blockhash);

    // Send transaction
    if !rate_limiter.check_and_increment() {
        pending_transaction.store(false, Ordering::Relaxed);
        return Err(PyValueError::new_err("RPC rate limit exceeded"));
    }

    let result = client
        .send_transaction_with_config(
            &tx,
            RpcSendTransactionConfig {
                skip_preflight: config.skip_preflight,
                preflight_commitment: Some(CommitmentLevel::Processed),
                encoding: None,
                max_retries: Some(config.max_retries as usize),
                min_context_slot: None,
            },
        )
        .await;

    // Reset pending transaction flag
    pending_transaction.store(false, Ordering::Relaxed);

    match result {
        Ok(signature) => {
            let status =
                TransactionStatus::new(signature.to_string(), true, None, None, None);
            Ok(status)
        }
        Err(e) => {
            let status = TransactionStatus::new(
                "failed".to_string(),
                false,
                Some(e.to_string()),
                None,
                None,
            );
            Ok(status)
        }
    }
})
}

// Execute front-run and back-run trade sequence - Fixed for the lifetime issue
fn execute_front_run_trade<'py>(
&self,
py: Python<'py>,
token_mint: String,
amount: f64,
slippage_bps: Option<u16>,
) -> PyResult<&'py PyAny> {
let client = self.client.clone();
let keypair = self.keypair.clone();
let config_arc = self.config.clone();
let rate_limiter = self.rate_limiter.clone();
let pending_transaction = self.pending_transaction.clone();

// Check if a transaction is already pending
if pending_transaction.load(Ordering::Relaxed) {
    return Err(PyValueError::new_err(
        "A transaction is already in progress",
    ));
}

// Clone parameters for async block
let token_mint_clone = token_mint.clone();
let slippage = slippage_bps.unwrap_or(1000);

pyo3_asyncio::tokio::future_into_py(py, async move {
    // Set pending transaction flag
    pending_transaction.store(true, Ordering::Relaxed);

    // Get config values
    let config = match config_arc.read() {
        Ok(config) => config.clone(),
        Err(_) => {
            pending_transaction.store(false, Ordering::Relaxed);
            return Err(PyValueError::new_err("Failed to read config"));
        }
    };

    // Create buy params
    let buy_params = SwapParams {
        token_mint: token_mint_clone.clone(),
        amount_in: amount,
        is_buy: true,
        slippage_bps: slippage,
        compute_limit: config.compute_limit,
        priority_fee: config.priority_fee,
    };

    // Execute buy transaction
    let buy_result =
        execute_swap_internal(&client, &keypair, &config, &rate_limiter, &buy_params).await;

    // Check if buy was successful
    match buy_result {
        Ok(status) => {
            if !status.success {
                pending_transaction.store(false, Ordering::Relaxed);
                return Ok(status);
            }

            // Small delay to allow chain to process
            std::thread::sleep(std::time::Duration::from_millis(500));

            // Create sell params (sell all tokens)
            let sell_params = SwapParams {
                token_mint: token_mint_clone,
                amount_in: 0.0, // Sell all tokens
                is_buy: false,
                slippage_bps: slippage,
                compute_limit: config.compute_limit,
                priority_fee: config.priority_fee,
            };

            // Execute sell transaction
            let sell_result = execute_swap_internal(
                &client,
                &keypair,
                &config,
                &rate_limiter,
                &sell_params,
            )
            .await;

            // Reset pending transaction flag
            pending_transaction.store(false, Ordering::Relaxed);

            // Return sell result
            match sell_result {
                Ok(sell_status) => Ok(sell_status),
                Err(e) => {
                    // Create a failed status
                    let failed_status = TransactionStatus::new(
                        "sell_failed".to_string(),
                        false,
                        Some(format!("Buy succeeded but sell failed: {}", e)),
                        None,
                        None,
                    );
                    Ok(failed_status)
                }
            }
        }
        Err(e) => {
            // Reset pending transaction flag
            pending_transaction.store(false, Ordering::Relaxed);

            // Return the error
            Err(e)
        }
    }
})
}   // Get the market state for a token pair - Fixed for the lifetime issue
fn get_market_state<'py>(&self, py: Python<'py>, token_mint: String) -> PyResult<&'py PyAny> {
    let client = self.client.clone();
    let config_arc = self.config.clone();
    let rate_limiter = self.rate_limiter.clone();
    let token_mint_clone = token_mint.clone();

    pyo3_asyncio::tokio::future_into_py(py, async move {
        // Get config
        let config = match config_arc.read() {
            Ok(config) => config.clone(),
            Err(_) => return Err(PyValueError::new_err("Failed to read config")),
        };

        // Get the token pair settings
        let token_pair = match config.token_pair_settings.get(&token_mint_clone) {
            Some(settings) => settings.clone(),
            None => {
                return Err(PyValueError::new_err(format!(
                    "Token pair settings not found for {}",
                    token_mint_clone
                )))
            }
        };

        // Parse pubkeys
        let pool_token_account = match Pubkey::from_str(&token_pair.pool_token_account) {
            Ok(pubkey) => pubkey,
            Err(e) => {
                return Err(PyValueError::new_err(format!(
                    "Invalid pool token account: {}",
                    e
                )))
            }
        };

        let pool_pc_account = match Pubkey::from_str(&token_pair.pool_pc_account) {
            Ok(pubkey) => pubkey,
            Err(e) => {
                return Err(PyValueError::new_err(format!(
                    "Invalid pool PC account: {}",
                    e
                )))
            }
        };

        // Check rate limit
        if !rate_limiter.check_and_increment() {
            return Err(PyValueError::new_err("RPC rate limit exceeded"));
        }

        // Get pool token account balance
        let token_pool_balance =
            match client.get_token_account_balance(&pool_token_account).await {
                Ok(balance) => match balance.amount.parse::<u64>() {
                    Ok(amount) => amount,
                    Err(_) => 0,
                },
                Err(e) => {
                    return Err(PyValueError::new_err(format!(
                        "Failed to get pool token balance: {}",
                        e
                    )))
                }
            };

        // Check rate limit
        if !rate_limiter.check_and_increment() {
            return Err(PyValueError::new_err("RPC rate limit exceeded"));
        }

        // Get pool SOL account balance
        let sol_pool_balance = match client.get_token_account_balance(&pool_pc_account).await {
            Ok(balance) => match balance.amount.parse::<u64>() {
                Ok(amount) => amount,
                Err(_) => 0,
            },
            Err(e) => {
                return Err(PyValueError::new_err(format!(
                    "Failed to get pool SOL balance: {}",
                    e
                )))
            }
        };

        // Calculate liquidity percentage
        let token_pool_balance_f64 = token_pool_balance as f64;
        let sol_pool_balance_f64 = sol_pool_balance as f64 / LAMPORTS_PER_SOL as f64;

        // Return as HashMap
        let mut result = HashMap::new();
        result.insert("token_mint".to_string(), token_mint_clone);
        result.insert(
            "token_pool_balance".to_string(),
            token_pool_balance_f64.to_string(),
        );
        result.insert(
            "sol_pool_balance".to_string(),
            sol_pool_balance_f64.to_string(),
        );
        result.insert(
            "exit_liquidity".to_string(),
            sol_pool_balance_f64.to_string(),
        );

        Ok(result)
    })
}
}

// Full corrected version of execute_swap_internal function
async fn execute_swap_internal(
client: &RpcClient,
keypair: &Arc<Keypair>,
config: &TradingConfig,
rate_limiter: &RateLimiter,
params: &SwapParams,
) -> PyResult<TransactionStatus> {
// Get the token pair settings
let token_pair = match config.token_pair_settings.get(&params.token_mint) {
    Some(settings) => settings.clone(),
    None => {
        // If the token is not in the token pair settings, check if we have it directly in the config
        if Some(params.token_mint.clone()) == config.token_mint {
            // Create a synthetic token pair from config market values
            if let (Some(amm_id), Some(auth), Some(open), Some(target), Some(token), Some(pc)) = (
                &config.amm_id,
                &config.market_amm_authority,
                &config.market_amm_open_orders,
                &config.market_amm_target,
                &config.market_pool_token_account,
                &config.market_pool_pc_token_account
            ) {
                TokenPairSetting {
                    token_mint: params.token_mint.clone(),
                    amm_id: amm_id.clone(),
                    amm_authority: auth.clone(),
                    amm_open_orders: open.clone(),
                    amm_target: target.clone(),
                    pool_token_account: token.clone(),
                    pool_pc_account: pc.clone(),
                    min_liquidity_pct: 95.0,
                    min_exit_liquidity_sol: 5.0,
                    auth_revoked: true,
                    buyer_seller_ratio: 1.0,
                    min_volume_5m: 10.0,
                    enabled: true,
                }
            } else {
                return Err(PyValueError::new_err(format!(
                    "Token pair settings not found for {}",
                    params.token_mint
                )));
            }
        } else {
            return Err(PyValueError::new_err(format!(
                "Token pair settings not found for {}",
                params.token_mint
            )));
        }
    }
};

// Check if token is enabled
if !token_pair.enabled {
    return Err(PyValueError::new_err(format!(
        "Token {} is disabled",
        params.token_mint
    )));
}

// Parse all the pubkeys
let token_mint_pubkey = match Pubkey::from_str(&params.token_mint) {
    Ok(pubkey) => pubkey,
    Err(e) => return Err(PyValueError::new_err(format!("Invalid token mint: {}", e))),
};

let sol_mint_pubkey = match Pubkey::from_str(&config.sol_mint) {
    Ok(pubkey) => pubkey,
    Err(e) => return Err(PyValueError::new_err(format!("Invalid SOL mint: {}", e))),
};

let raydium_program_id = match Pubkey::from_str(&config.raydium_program_id) {
    Ok(pubkey) => pubkey,
    Err(e) => {
        return Err(PyValueError::new_err(format!(
            "Invalid Raydium program ID: {}",
            e
        )))
    }
};

let token_program_id = match Pubkey::from_str(&config.token_program_id) {
    Ok(pubkey) => pubkey,
    Err(e) => {
        return Err(PyValueError::new_err(format!(
            "Invalid token program ID: {}",
            e
        )))
    }
};

// Get associated token accounts
let user_wsol_ata = get_associated_token_address(&keypair.pubkey(), &sol_mint_pubkey);
let user_token_ata = get_associated_token_address(&keypair.pubkey(), &token_mint_pubkey);

// Prepare instructions for creating ATAs if needed
let mut instructions = Vec::new();

// Check if ATAs exist and add creation instructions if needed
if !rate_limiter.check_and_increment() {
    return Err(PyValueError::new_err("RPC rate limit exceeded"));
}

let wsol_account_exists = client.get_account(&user_wsol_ata).await.is_ok();
if !wsol_account_exists {
    let create_wsol_ata_ix = create_associated_token_account_idempotent(
        &keypair.pubkey(),
        &keypair.pubkey(),
        &sol_mint_pubkey,
        &token_program_id,
    );
    instructions.push(create_wsol_ata_ix);
}

if !rate_limiter.check_and_increment() {
    return Err(PyValueError::new_err("RPC rate limit exceeded"));
}

let token_account_exists = client.get_account(&user_token_ata).await.is_ok();
if !token_account_exists {
    let create_token_ata_ix = create_associated_token_account_idempotent(
        &keypair.pubkey(),
        &keypair.pubkey(),
        &token_mint_pubkey,
        &token_program_id,
    );
    instructions.push(create_token_ata_ix);
}

// Convert amount to lamports
let amount_lamports = (params.amount_in * LAMPORTS_PER_SOL as f64) as u64;

// If buying and amount > 0, we need to wrap SOL first
if params.is_buy && amount_lamports > 0 {
    // Transfer SOL to WSOL ATA
    let transfer_ix =
        system_instruction::transfer(&keypair.pubkey(), &user_wsol_ata, amount_lamports);
    instructions.push(transfer_ix);

    // Synchronize WSOL
    let sync_ix = match token_instruction::sync_native(&token_program_id, &user_wsol_ata) {
        Ok(ix) => ix,
        Err(e) => {
            return Err(PyValueError::new_err(format!(
                "Failed to create sync instruction: {}",
                e
            )))
        }
    };
    instructions.push(sync_ix);
}

// For sells with amount_in == 0, we need to get current token balance
let actual_amount = if !params.is_buy && params.amount_in == 0.0 {
    if !rate_limiter.check_and_increment() {
        return Err(PyValueError::new_err("RPC rate limit exceeded"));
    }

    match client.get_token_account_balance(&user_token_ata).await {
        Ok(balance) => match balance.amount.parse::<u64>() {
            Ok(amount) => amount,
            Err(_) => return Err(PyValueError::new_err("Failed to parse token balance")),
        },
        Err(e) => {
            return Err(PyValueError::new_err(format!(
                "Failed to get token balance: {}",
                e
            )))
        }
    }
} else {
    amount_lamports
};

// Get observed accounts for this token
let observed_accounts = get_observed_accounts_for_token(&params.token_mint, config);

// Create the Raydium swap instruction
let swap_instruction = create_raydium_swap_instruction(
    &raydium_program_id,
    if params.is_buy {
        &user_wsol_ata
    } else {
        &user_token_ata
    },
    if params.is_buy {
        &user_token_ata
    } else {
        &user_wsol_ata
    },
    observed_accounts,
    actual_amount,
    params.is_buy,
    &keypair.pubkey(),
);

instructions.push(swap_instruction);

// Add compute budget instructions
let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(params.compute_limit);
let priority_fee_ix = ComputeBudgetInstruction::set_compute_unit_price(params.priority_fee);

instructions.insert(0, priority_fee_ix);
instructions.insert(0, compute_budget_ix);

// Get recent blockhash
if !rate_limiter.check_and_increment() {
    return Err(PyValueError::new_err("RPC rate limit exceeded"));
}

let blockhash = match client.get_latest_blockhash().await {
    Ok(blockhash) => blockhash,
    Err(e) => {
        return Err(PyValueError::new_err(format!(
            "Failed to get latest blockhash: {}",
            e
        )))
    }
};

// Create transaction
let mut tx = Transaction::new_with_payer(&instructions, Some(&keypair.pubkey()));

// Sign transaction - FIXED: Proper way to access Arc<Keypair>
tx.sign(&[keypair.as_ref()], blockhash);

// Send transaction
if !rate_limiter.check_and_increment() {
    return Err(PyValueError::new_err("RPC rate limit exceeded"));
}

let result = client
    .send_transaction_with_config(
        &tx,
        RpcSendTransactionConfig {
            skip_preflight: config.skip_preflight,
            preflight_commitment: Some(CommitmentLevel::Processed),
            encoding: None,
            max_retries: Some(config.max_retries as usize),
            min_context_slot: None,
        },
    )
    .await;

match result {
    Ok(signature) => {
        let status = TransactionStatus::new(
            signature.to_string(),
            true,
            None,
            Some(
                SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .unwrap()
                    .as_secs(),
            ),
            None,
        );
        Ok(status)
    }
    Err(e) => {
        let status = TransactionStatus::new(
            "failed".to_string(),
            false,
            Some(e.to_string()),
            Some(
                SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .unwrap()
                    .as_secs(),
            ),
            None,
        );
        Ok(status)
    }
}
}

// Module configuration
#[pymodule]
fn solana_rust_bot(_py: Python, m: &PyModule) -> PyResult<()> {
pyo3_log::init();

m.add_class::<TradingConfig>()?;
m.add_class::<TokenPairSetting>()?;
m.add_class::<SwapParams>()?;
m.add_class::<TransactionStatus>()?;
m.add_class::<RaydiumTradingCore>()?;

Ok(())
}   edit this into the script please #[pymethods]
impl TradingConfig {
    #[new]
    fn new(
        rpc_url: Option<String>,
        ws_url: Option<String>,
        api_key: Option<String>,
        sol_mint: Option<String>,
        rpc_rate_limit: Option<u64>,
        compute_limit: Option<u32>,
        priority_fee: Option<u64>,
        skip_preflight: Option<bool>,
        max_retries: Option<u8>,
        front_run_amount: Option<f64>,
        min_victim_size: Option<f64>,
        max_victim_size: Option<f64>,
        min_profit: Option<f64>,
        slippage_bps: Option<u16>,
        min_sol_balance: Option<f64>,
        min_wsol_balance: Option<f64>,
        raydium_program_id: Option<String>,
        token_program_id: Option<String>,
        system_program_id: Option<String>,
        associated_token_program_id: Option<String>,
        // Additional parameters from Python code
        token_mint: Option<String>,
        amm_program: Option<String>,
        amm_id: Option<String>,
        market_amm_authority: Option<String>,
        market_amm_open_orders: Option<String>,
        market_amm_target: Option<String>,
        market_pool_token_account: Option<String>,
        market_pool_pc_token_account: Option<String>,
    ) -> Self {
        // Clone amm_program first to avoid moved value error
        let amm_program_clone = amm_program.clone();
        
        Self {
            rpc_url: rpc_url.unwrap_or_else(|| {
                env::var("RPC_URL")
                    .unwrap_or_else(|_| "https://api.mainnet-beta.solana.com".to_string())
            }),
            ws_url: ws_url.unwrap_or_else(|| {
                env::var("WS_URL")
                    .unwrap_or_else(|_| "wss://api.mainnet-beta.solana.com".to_string())
            }),
            api_key: api_key
                .unwrap_or_else(|| env::var("API_KEY").unwrap_or_else(|_| "".to_string())),
            sol_mint: sol_mint.unwrap_or_else(|| {
                env::var("SOL_MINT")
                    .unwrap_or_else(|_| "So11111111111111111111111111111111111111112".to_string())
            }),
            rpc_rate_limit: rpc_rate_limit.unwrap_or_else(|| {
                env::var("RPC_RATE_LIMIT")
                    .map(|v| v.parse().unwrap_or(DEFAULT_RPC_RATE_LIMIT))
                    .unwrap_or(DEFAULT_RPC_RATE_LIMIT)
            }),
            // Store additional fields
            token_mint,
            amm_program: amm_program_clone,
            compute_limit: compute_limit.unwrap_or_else(|| {
                env::var("COMPUTE_LIMIT")
                    .map(|v| v.parse().unwrap_or(COMPUTE_UNITS))
                    .unwrap_or(COMPUTE_UNITS)
            }),
            priority_fee: priority_fee.unwrap_or_else(|| {
                env::var("PRIORITY_FEE")
                    .map(|v| v.parse().unwrap_or(PRIORITY_FEE))
                    .unwrap_or(PRIORITY_FEE)
            }),
            skip_preflight: skip_preflight.unwrap_or_else(|| {
                env::var("SKIP_PREFLIGHT")
                    .map(|v| v.parse().unwrap_or(true))
                    .unwrap_or(true)
            }),
            max_retries: max_retries.unwrap_or_else(|| {
                env::var("MAX_RETRIES")
                    .map(|v| v.parse().unwrap_or(MAX_RETRY_COUNT))
                    .unwrap_or(MAX_RETRY_COUNT)
            }),
            front_run_amount: front_run_amount.unwrap_or_else(|| {
                env::var("FRONT_RUN_AMOUNT")
                    .map(|v| v.parse().unwrap_or(0.35))
                    .unwrap_or(0.35)
            }),
            min_victim_size: min_victim_size.unwrap_or_else(|| {
                env::var("MIN_VICTIM_SIZE")
                    .map(|v| v.parse().unwrap_or(5.0))
                    .unwrap_or(5.0)
            }),
            max_victim_size: max_victim_size.unwrap_or_else(|| {
                env::var("MAX_VICTIM_SIZE")
                    .map(|v| v.parse().unwrap_or(320.0))
                    .unwrap_or(320.0)
            }),
            min_profit: min_profit.unwrap_or_else(|| {
                env::var("MIN_PROFIT")
                    .map(|v| v.parse().unwrap_or(0.002))
                    .unwrap_or(0.002)
            }),
            slippage_bps: slippage_bps.unwrap_or_else(|| {
                env::var("SLIPPAGE_BPS")
                    .map(|v| v.parse().unwrap_or(1000))
                    .unwrap_or(1000)
            }),
            min_sol_balance: min_sol_balance.unwrap_or_else(|| {
                env::var("MIN_SOL_BALANCE")
                    .map(|v| v.parse().unwrap_or(0.03))
                    .unwrap_or(0.03)
            }),
            min_wsol_balance: min_wsol_balance.unwrap_or_else(|| {
                env::var("MIN_WSOL_BALANCE")
                    .map(|v| v.parse().unwrap_or(0.02))
                    .unwrap_or(0.02)
            }),
            // Store additional market parameters
            amm_id,
            market_amm_authority,
            market_amm_open_orders,
            market_amm_target,
            market_pool_token_account,
            market_pool_pc_token_account,
            raydium_program_id: raydium_program_id.unwrap_or_else(|| {
                // If amm_program is provided, use that instead
                amm_program.clone().unwrap_or_else(|| {
                    env::var("RAYDIUM_PROGRAM_ID")
                        .unwrap_or_else(|_| "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string())
                })
            }),
            token_program_id: token_program_id.unwrap_or_else(|| {
                env::var("TOKEN_PROGRAM_ID")
                    .unwrap_or_else(|_| "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA".to_string())
            }),
            system_program_id: system_program_id.unwrap_or_else(|| {
                env::var("SYSTEM_PROGRAM_ID")
                    .unwrap_or_else(|_| "11111111111111111111111111111111".to_string())
            }),
            associated_token_program_id: associated_token_program_id.unwrap_or_else(|| {
                env::var("ASSOCIATED_TOKEN_PROGRAM_ID")
                    .unwrap_or_else(|_| "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL".to_string())
            }),
            token_pair_settings: HashMap::new(),
        }
    }
    
    // rest of the implementation...
} // Execute a Raydium swap transaction - Fixed for the lifetime issue
    fn execute_swap<'py>(&self, py: Python<'py>, params: SwapParams) -> PyResult<&'py PyAny> {
        let client = self.client.clone();
        let keypair = self.keypair.clone();
        let config_arc = self.config.clone();
        let rate_limiter = self.rate_limiter.clone();
        let pending_transaction = self.pending_transaction.clone();

        // Check if a transaction is already pending
        if pending_transaction.load(Ordering::Relaxed) {
            return Err(PyValueError::new_err(
                "A transaction is already in progress",
            ));
        }

        let params_clone = params.clone();

        pyo3_asyncio::tokio::future_into_py(py, async move {
            // Set pending transaction flag
            pending_transaction.store(true, Ordering::Relaxed);

            // Get config values
            let config = match config_arc.read() {
                Ok(config) => config.clone(),
                Err(_) => {
                    pending_transaction.store(false, Ordering::Relaxed);
                    return Err(PyValueError::new_err("Failed to read config"));
                }
            };

            // Get the token pair settings - use _token_pair to indicate it's intentionally unused
            // or remove if unused in this context
            let _token_pair = match config.token_pair_settings.get(&params_clone.token_mint) {
                Some(settings) => settings.clone(),
                None => {
                    // If the token is not in the token pair settings, check if we have it directly in the config
                    if Some(params_clone.token_mint.clone()) == config.token_mint {
                        // Create a synthetic token pair from config market values
                        if let (Some(amm_id), Some(auth), Some(open), Some(target), Some(token), Some(pc)) = (
                            &config.amm_id,
                            &config.market_amm_authority,
                            &config.market_amm_open_orders,
                            &config.market_amm_target,
                            &config.market_pool_token_account,
                            &config.market_pool_pc_token_account
                        ) {
                            TokenPairSetting {
                                token_mint: params_clone.token_mint.clone(),
                                amm_id: amm_id.clone(),
                                amm_authority: auth.clone(),
                                amm_open_orders: open.clone(),
                                amm_target: target.clone(),
                                pool_token_account: token.clone(),
                                pool_pc_account: pc.clone(),
                                min_liquidity_pct: 95.0,
                                min_exit_liquidity_sol: 5.0,
                                auth_revoked: true,
                                buyer_seller_ratio: 1.0,
                                min_volume_5m: 10.0,
                                enabled: true,
                            }
                        } else {
                            pending_transaction.store(false, Ordering::Relaxed);
                            return Err(PyValueError::new_err(format!(
                                "Token pair settings not found for {}",
                                params_clone.token_mint
                            )));
                        }
                    } else {
                        pending_transaction.store(false, Ordering::Relaxed);
                        return Err(PyValueError::new_err(format!(
                            "Token pair settings not found for {}",
                            params_clone.token_mint
                        )));
                    }
                }
            };

            // Rest of the function...
        })
    }There were two issues in your code that I've fixed:

Borrow of moved value: In the TradingConfig::new() method, you were using amm_program after it had been moved. The fix is to clone it first before using it:// Clone amm_program first to avoid moved value error
let amm_program_clone = amm_program.clone();

Self {
    // ...
    amm_program: amm_program_clone,
    // ...
}Unused variable warning: In the execute_swap method, there was an unused variable token_pair. The fix is to either:

Prefix it with an underscore to indicate it's intentionally unused: let _token_pair = ...
Or remove it if it's truly not needed



These changes should resolve both the error and the warning. The important points are:

In Rust, when you move a value into a struct, you can't use it again later unless:

The type implements the Copy trait (which Option<String> doesn't)
You clone it first (which is what we did)


Rust warns about unused variables to help avoid mistakes. If you intend not to use a variable, prefix it with an underscore, which tells the compiler it's intentional.

After making these changes, your code should compile successfully.