use dashmap::DashMap;
use dotenv::dotenv;
use futures_util::{SinkExt, StreamExt};
use log::{error, info};
use pyo3::prelude::*;
use pyo3::types::PyBytes;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use solana_client::{
    rpc_client::RpcClient,
    rpc_config::RpcSendTransactionConfig,
};
use solana_sdk::{
    commitment_config::CommitmentConfig,
    compute_budget::ComputeBudgetInstruction,
    instruction::{AccountMeta, Instruction},
    message::Message,
    pubkey::Pubkey,
    signature::Keypair,
    signer::Signer,
    transaction::Transaction,
};
use std::{
    collections::HashMap,
    env,
    str::FromStr,
    sync::Arc,
    time::{Duration, Instant}
};
use tokio::sync::{mpsc, Mutex};
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message as WSMessage};
use url::Url;
use bs58;
use base64::{Engine, engine::general_purpose::STANDARD as base64_engine};

// Constants 
const LAMPORTS_PER_SOL: u64 = 1_000_000_000;
const MIN_PRIORITY_FEE: u64 = 500_000;
const PRIORITY_FEE_INTERVAL: Duration = Duration::from_secs(30);

#[derive(Debug, Serialize, Deserialize)]
struct PriorityFeeResponse {
    jsonrpc: String,
    result: PriorityFeeResult,
    id: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct PriorityFeeResult {
    priority_fee_estimate: Option<f64>,
}

/// Pool state tracking
#[pyclass]
#[derive(Clone, Debug)]
pub struct PoolState {
    #[pyo3(get)]
    pub amm_id: String,
    #[pyo3(get)]
    pub authority: String,
    #[pyo3(get)]
    pub open_orders: String,
    #[pyo3(get)]
    pub target_orders: String,
    #[pyo3(get)]
    pub base_vault: String,
    #[pyo3(get)]
    pub quote_vault: String,
    #[pyo3(get)]
    pub market: String,
    #[pyo3(get)]
    pub bids: String,
    #[pyo3(get)]
    pub asks: String,
    #[pyo3(get)]
    pub event_queue: String,
    #[pyo3(get)]
    pub vault_signer: String,
}

/// Trade configuration
#[pyclass]
#[derive(Deserialize, Clone, Debug)]
pub struct TradeConfig {
    #[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: u32,
    #[pyo3(get, set)]
    pub commitment: String,
}

#[pymethods]
impl TradeConfig {
    #[new]
    fn new() -> Self {
        Self {
            compute_limit: 400_000,
            priority_fee: MIN_PRIORITY_FEE,
            skip_preflight: true,
            max_retries: 3,
            commitment: "confirmed".to_string(),
        }
    }
}

/// Trade parameters
#[pyclass]
#[derive(Deserialize, Clone, Debug)]
pub struct TradeParams {
    #[pyo3(get, set)]
    pub pool_address: String,
    #[pyo3(get, set)]
    pub amount_in: f64,
    #[pyo3(get, set)]
    pub min_amount_out: f64,
    #[pyo3(get, set)]
    pub wsol_account: String,
}

#[pymethods]
impl TradeParams {
    #[new]
    fn new(pool_address: String, amount_in: f64, min_amount_out: f64, wsol_account: String) -> Self {
        Self {
            pool_address,
            amount_in,
            min_amount_out,
            wsol_account,
        }
    }
}

/// Main trading core
#[pyclass]
pub struct TradingCore {
    client: Arc<RpcClient>,
    keypair: Arc<Keypair>,
    pool_cache: Arc<DashMap<String, PoolState>>,
    http_client: Arc<Client>,
    config: Arc<Mutex<TradeConfig>>,
    last_priority_update: Arc<Mutex<Instant>>,
    mempool_tx: Arc<Mutex<mpsc::Sender<Vec<u8>>>>,
    mempool_rx: Arc<Mutex<mpsc::Receiver<Vec<u8>>>>,
}

#[pymethods]
impl TradingCore {
    #[new]
    #[pyo3(signature = (private_key_bytes))]
    fn new(private_key_bytes: &[u8]) -> PyResult<Self> {
        info!("Initializing TradingCore...");
        dotenv().ok();

        // Create keypair from bytes passed from Python
        let keypair = Keypair::from_bytes(private_key_bytes)
            .map_err(|e| {
                error!("Failed to create keypair: {}", e);
                PyErr::new::<pyo3::exceptions::PyValueError, _>("Invalid keypair bytes")
            })?;
        
        info!("Created keypair with pubkey: {}", keypair.pubkey());
        let keypair = Arc::new(keypair);

        let rpc_url = env::var("RPC_URL").expect("RPC_URL not set");
        info!("Connecting to RPC: {}", rpc_url);
        let client = Arc::new(RpcClient::new_with_commitment(
            rpc_url,
            CommitmentConfig::confirmed(),
        ));

        info!("Initializing HTTP client...");
        let http_client = Arc::new(
            Client::builder()
                .timeout(Duration::from_secs(30))
                .build()
                .map_err(|e| {
                    error!("Failed to initialize HTTP client: {}", e);
                    PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string())
                })?,
        );

        let (tx, rx) = mpsc::channel(1000);
        let config = TradeConfig::new();

        Ok(Self {
            client,
            keypair,
            pool_cache: Arc::new(DashMap::new()),
            http_client,
            config: Arc::new(Mutex::new(config)),
            last_priority_update: Arc::new(Mutex::new(Instant::now())),
            mempool_tx: Arc::new(Mutex::new(tx)),
            mempool_rx: Arc::new(Mutex::new(rx)),
        })
    }

    fn get_wsol_balance(&self, token_account: String) -> PyResult<f64> {
        let wsol_pubkey = Pubkey::from_str(&token_account).map_err(|_| {
            PyErr::new::<pyo3::exceptions::PyValueError, _>("Invalid WSOL account")
        })?;

        match self.client.get_token_account_balance(&wsol_pubkey) {
            Ok(balance) => Ok(balance.ui_amount.unwrap_or(0.0)),
            Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))
        }
    }

    fn execute_trade(&self, params: TradeParams) -> PyResult<Option<String>> {
        info!("Executing trade with params: {:?}", params);

        let rt = tokio::runtime::Runtime::new().map_err(|e| {
            error!("Failed to create Tokio runtime: {}", e);
            PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string())
        })?;

        rt.block_on(async {
            let config = self.config.lock().await;
            
            // Get pool state
            let pool = self.pool_cache
                .get(&params.pool_address)
                .ok_or_else(|| {
                    error!("Pool not found: {}", params.pool_address);
                    PyErr::new::<pyo3::exceptions::PyValueError, _>("Pool not found")
                })?;

            // Get optimized priority fee
            let priority_fee = self.get_helius_priority_fee().await?;

            // Build instructions
            let mut instructions = vec![
                ComputeBudgetInstruction::set_compute_unit_limit(config.compute_limit),
                ComputeBudgetInstruction::set_compute_unit_price(priority_fee),
            ];

            let amount_in = (params.amount_in * LAMPORTS_PER_SOL as f64) as u64;
            let min_amount_out = (params.min_amount_out * LAMPORTS_PER_SOL as f64) as u64;

            // Add Raydium swap instruction
            instructions.push(Instruction {
                program_id: Pubkey::from_str(&env::var("RAYDIUM_PROGRAM_ID")
                    .expect("RAYDIUM_PROGRAM_ID not set")).unwrap(),
                accounts: self.get_swap_accounts(&pool, &params.wsol_account),
                data: self.create_swap_data(amount_in, min_amount_out),
            });

            // Get blockhash
            let blockhash = self.client
                .get_latest_blockhash()
                .map_err(|e| {
                    error!("Failed to get blockhash: {}", e);
                    PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string())
                })?;

            // Build and sign transaction
            let message = Message::new(&instructions, Some(&self.keypair.pubkey()));
            let mut transaction = Transaction::new_unsigned(message);
            transaction.sign(&[&*self.keypair], blockhash);

            // Send transaction
            match self.client.send_and_confirm_transaction_with_spinner_and_config(
                &transaction,
                CommitmentConfig::from_str(&config.commitment).unwrap(),
                RpcSendTransactionConfig {
                    skip_preflight: config.skip_preflight,
                    preflight_commitment: None,
                    encoding: None,
                    max_retries: Some(config.max_retries as usize),
                    min_context_slot: None,
                },
            ) {
                Ok(signature) => {
                    info!("Transaction successful: {}", signature);
                    Ok(Some(signature.to_string()))
                }
                Err(e) => {
                    error!("Transaction failed: {}", e);
                    Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))
                }
            }
        })
    }

    fn update_pool(&self, pool_data: HashMap<String, String>) -> PyResult<()> {
        let pool_state = PoolState {
            amm_id: pool_data["amm_id"].clone(),
            authority: pool_data["amm_authority"].clone(),
            open_orders: pool_data["amm_open_orders"].clone(),
            target_orders: pool_data["amm_target"].clone(),
            base_vault: pool_data["pool_coin_token_account"].clone(),
            quote_vault: pool_data["pool_pc_token_account"].clone(),
            market: pool_data["serum_market"].clone(),
            bids: pool_data["serum_bids"].clone(),
            asks: pool_data["serum_asks"].clone(),
            event_queue: pool_data["serum_events"].clone(),
            vault_signer: pool_data["vault_signer"].clone(),
        };

        self.pool_cache.insert(pool_data["amm_id"].clone(), pool_state);
        Ok(())
    }

    fn subscribe_to_mempool(&self, py: Python<'_>) -> PyResult<()> {
        info!("Starting mempool subscription...");
        
        let ws_url = env::var("HELIUS_WS_URL").expect("HELIUS_WS_URL not set");
        let mempool_tx = self.mempool_tx.clone();
        let raydium_program = env::var("RAYDIUM_PROGRAM_ID")
            .expect("RAYDIUM_PROGRAM_ID not set");

        py.allow_threads(move || {
            let rt = tokio::runtime::Runtime::new().unwrap();
            rt.block_on(async {
                loop {
                    match connect_async(Url::parse(&ws_url).unwrap()).await {
                        Ok((mut ws_stream, _)) => {
                            info!("Connected to Helius WebSocket");

                            let sub_msg = serde_json::json!({
                                "jsonrpc": "2.0",
                                "id": 1,
                                "method": "logsSubscribe",
                                "params": [
                                    {
                                        "mentions": [raydium_program]
                                    },
                                    {"commitment": "processed"}
                                ]
                            });

                            if let Err(e) = ws_stream.send(WSMessage::Text(sub_msg.to_string())).await {
                                error!("Failed to send subscription: {}", e);
                                continue;
                            }

                            while let Some(msg) = ws_stream.next().await {
                                match msg {
                                    Ok(WSMessage::Text(text)) => {
                                        if let Ok(value) = serde_json::from_str::<serde_json::Value>(&text) {
                                            if let Some(params) = value.get("params") {
                                                if let Some(result) = params.get("result") {
                                                    if let Some(data) = result.get("data") {
                                                        if let Some(raw_data) = data.as_str() {
                                                            if let Ok(decoded) = base64_engine.decode(raw_data) {
                                                                let _ = mempool_tx.lock().await.try_send(decoded);
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    Ok(WSMessage::Close(_)) => break,
                                    Err(e) => {
                                        error!("WebSocket error: {}", e);
                                        break;
                                    }
                                    _ => {}
                                }
                            }
                        }
                        Err(e) => error!("WebSocket connection error: {}", e),
                    }

                    tokio::time::sleep(Duration::from_secs(1)).await;
                }
            });
        });

        Ok(())
    }

    use dashmap::DashMap;
use dotenv::dotenv;
use futures_util::{SinkExt, StreamExt};
use log::{error, info};
use pyo3::prelude::*;
use pyo3::types::PyBytes;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use solana_client::{
    rpc_client::RpcClient,
    rpc_config::RpcSendTransactionConfig,
};
use solana_sdk::{
    commitment_config::CommitmentConfig,
    compute_budget::ComputeBudgetInstruction,
    instruction::{AccountMeta, Instruction},
    message::Message,
    pubkey::Pubkey,
    signature::Keypair,
    signer::Signer,
    transaction::Transaction,
};
use std::{
    collections::HashMap,
    env,
    str::FromStr,
    sync::Arc,
    time::{Duration, Instant}
};
use tokio::sync::{mpsc, Mutex};
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message as WSMessage};
use url::Url;
use bs58;
use base64::{Engine, engine::general_purpose::STANDARD as base64_engine};

// Constants 
const LAMPORTS_PER_SOL: u64 = 1_000_000_000;
const MIN_PRIORITY_FEE: u64 = 500_000;
const PRIORITY_FEE_INTERVAL: Duration = Duration::from_secs(30);

#[derive(Debug, Serialize, Deserialize)]
struct PriorityFeeResponse {
    jsonrpc: String,
    result: PriorityFeeResult,
    id: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct PriorityFeeResult {
    priority_fee_estimate: Option<f64>,
}

/// Pool state tracking
#[pyclass]
#[derive(Clone, Debug)]
pub struct PoolState {
    #[pyo3(get)]
    pub amm_id: String,
    #[pyo3(get)]
    pub authority: String,
    #[pyo3(get)]
    pub open_orders: String,
    #[pyo3(get)]
    pub target_orders: String,
    #[pyo3(get)]
    pub base_vault: String,
    #[pyo3(get)]
    pub quote_vault: String,
    #[pyo3(get)]
    pub market: String,
    #[pyo3(get)]
    pub bids: String,
    #[pyo3(get)]
    pub asks: String,
    #[pyo3(get)]
    pub event_queue: String,
    #[pyo3(get)]
    pub vault_signer: String,
}

/// Trade configuration
#[pyclass]
#[derive(Deserialize, Clone, Debug)]
pub struct TradeConfig {
    #[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: u32,
    #[pyo3(get, set)]
    pub commitment: String,
}

#[pymethods]
impl TradeConfig {
    #[new]
    fn new() -> Self {
        Self {
            compute_limit: 400_000,
            priority_fee: MIN_PRIORITY_FEE,
            skip_preflight: true,
            max_retries: 3,
            commitment: "confirmed".to_string(),
        }
    }
}

/// Trade parameters
#[pyclass]
#[derive(Deserialize, Clone, Debug)]
pub struct TradeParams {
    #[pyo3(get, set)]
    pub pool_address: String,
    #[pyo3(get, set)]
    pub amount_in: f64,
    #[pyo3(get, set)]
    pub min_amount_out: f64,
    #[pyo3(get, set)]
    pub wsol_account: String,
}

#[pymethods]
impl TradeParams {
    #[new]
    fn new(pool_address: String, amount_in: f64, min_amount_out: f64, wsol_account: String) -> Self {
        Self {
            pool_address,
            amount_in,
            min_amount_out,
            wsol_account,
        }
    }
}

/// Main trading core
#[pyclass]
pub struct TradingCore {
    client: Arc<RpcClient>,
    keypair: Arc<Keypair>,
    pool_cache: Arc<DashMap<String, PoolState>>,
    http_client: Arc<Client>,
    config: Arc<Mutex<TradeConfig>>,
    last_priority_update: Arc<Mutex<Instant>>,
    mempool_tx: Arc<Mutex<mpsc::Sender<Vec<u8>>>>,
    mempool_rx: Arc<Mutex<mpsc::Receiver<Vec<u8>>>>,
}

#[pymethods]
impl TradingCore {
    #[new]
    #[pyo3(signature = (private_key_bytes))]
    fn new(private_key_bytes: &[u8]) -> PyResult<Self> {
        info!("Initializing TradingCore...");
        dotenv().ok();

        // Create keypair from bytes passed from Python
        let keypair = Keypair::from_bytes(private_key_bytes)
            .map_err(|e| {
                error!("Failed to create keypair: {}", e);
                PyErr::new::<pyo3::exceptions::PyValueError, _>("Invalid keypair bytes")
            })?;
        
        info!("Created keypair with pubkey: {}", keypair.pubkey());
        let keypair = Arc::new(keypair);

        let rpc_url = env::var("RPC_URL").expect("RPC_URL not set");
        info!("Connecting to RPC: {}", rpc_url);
        let client = Arc::new(RpcClient::new_with_commitment(
            rpc_url,
            CommitmentConfig::confirmed(),
        ));

        info!("Initializing HTTP client...");
        let http_client = Arc::new(
            Client::builder()
                .timeout(Duration::from_secs(30))
                .build()
                .map_err(|e| {
                    error!("Failed to initialize HTTP client: {}", e);
                    PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string())
                })?,
        );

        let (tx, rx) = mpsc::channel(1000);
        let config = TradeConfig::new();

        Ok(Self {
            client,
            keypair,
            pool_cache: Arc::new(DashMap::new()),
            http_client,
            config: Arc::new(Mutex::new(config)),
            last_priority_update: Arc::new(Mutex::new(Instant::now())),
            mempool_tx: Arc::new(Mutex::new(tx)),
            mempool_rx: Arc::new(Mutex::new(rx)),
        })
    }

    fn get_wsol_balance(&self, token_account: String) -> PyResult<f64> {
        let wsol_pubkey = Pubkey::from_str(&token_account).map_err(|_| {
            PyErr::new::<pyo3::exceptions::PyValueError, _>("Invalid WSOL account")
        })?;

        match self.client.get_token_account_balance(&wsol_pubkey) {
            Ok(balance) => Ok(balance.ui_amount.unwrap_or(0.0)),
            Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))
        }
    }

    fn execute_trade(&self, params: TradeParams) -> PyResult<Option<String>> {
        info!("Executing trade with params: {:?}", params);

        let rt = tokio::runtime::Runtime::new().map_err(|e| {
            error!("Failed to create Tokio runtime: {}", e);
            PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string())
        })?;

        rt.block_on(async {
            let config = self.config.lock().await;
            
            // Get pool state
            let pool = self.pool_cache
                .get(&params.pool_address)
                .ok_or_else(|| {
                    error!("Pool not found: {}", params.pool_address);
                    PyErr::new::<pyo3::exceptions::PyValueError, _>("Pool not found")
                })?;

            // Get optimized priority fee
            let priority_fee = self.get_helius_priority_fee().await?;

            // Build instructions
            let mut instructions = vec![
                ComputeBudgetInstruction::set_compute_unit_limit(config.compute_limit),
                ComputeBudgetInstruction::set_compute_unit_price(priority_fee),
            ];

            let amount_in = (params.amount_in * LAMPORTS_PER_SOL as f64) as u64;
            let min_amount_out = (params.min_amount_out * LAMPORTS_PER_SOL as f64) as u64;

            // Add Raydium swap instruction
            instructions.push(Instruction {
                program_id: Pubkey::from_str(&env::var("RAYDIUM_PROGRAM_ID")
                    .expect("RAYDIUM_PROGRAM_ID not set")).unwrap(),
                accounts: self.get_swap_accounts(&pool, &params.wsol_account),
                data: self.create_swap_data(amount_in, min_amount_out),
            });

            // Get blockhash
            let blockhash = self.client
                .get_latest_blockhash()
                .map_err(|e| {
                    error!("Failed to get blockhash: {}", e);
                    PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string())
                })?;

            // Build and sign transaction
            let message = Message::new(&instructions, Some(&self.keypair.pubkey()));
            let mut transaction = Transaction::new_unsigned(message);
            transaction.sign(&[&*self.keypair], blockhash);

            // Send transaction
            match self.client.send_and_confirm_transaction_with_spinner_and_config(
                &transaction,
                CommitmentConfig::from_str(&config.commitment).unwrap(),
                RpcSendTransactionConfig {
                    skip_preflight: config.skip_preflight,
                    preflight_commitment: None,
                    encoding: None,
                    max_retries: Some(config.max_retries as usize),
                    min_context_slot: None,
                },
            ) {
                Ok(signature) => {
                    info!("Transaction successful: {}", signature);
                    Ok(Some(signature.to_string()))
                }
                Err(e) => {
                    error!("Transaction failed: {}", e);
                    Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))
                }
            }
        })
    }

    fn update_pool(&self, pool_data: HashMap<String, String>) -> PyResult<()> {
        let pool_state = PoolState {
            amm_id: pool_data["amm_id"].clone(),
            authority: pool_data["amm_authority"].clone(),
            open_orders: pool_data["amm_open_orders"].clone(),
            target_orders: pool_data["amm_target"].clone(),
            base_vault: pool_data["pool_coin_token_account"].clone(),
            quote_vault: pool_data["pool_pc_token_account"].clone(),
            market: pool_data["serum_market"].clone(),
            bids: pool_data["serum_bids"].clone(),
            asks: pool_data["serum_asks"].clone(),
            event_queue: pool_data["serum_events"].clone(),
            vault_signer: pool_data["vault_signer"].clone(),
        };

        self.pool_cache.insert(pool_data["amm_id"].clone(), pool_state);
        Ok(())
    }

    fn subscribe_to_mempool(&self, py: Python<'_>) -> PyResult<()> {
        info!("Starting mempool subscription...");
        
        let ws_url = env::var("HELIUS_WS_URL").expect("HELIUS_WS_URL not set");
        let mempool_tx = self.mempool_tx.clone();
        let raydium_program = env::var("RAYDIUM_PROGRAM_ID")
            .expect("RAYDIUM_PROGRAM_ID not set");

        py.allow_threads(move || {
            let rt = tokio::runtime::Runtime::new().unwrap();
            rt.block_on(async {
                loop {
                    match connect_async(Url::parse(&ws_url).unwrap()).await {
                        Ok((mut ws_stream, _)) => {
                            info!("Connected to Helius WebSocket");

                            let sub_msg = serde_json::json!({
                                "jsonrpc": "2.0",
                                "id": 1,
                                "method": "logsSubscribe",
                                "params": [
                                    {
                                        "mentions": [raydium_program]
                                    },
                                    {"commitment": "processed"}
                                ]
                            });

                            if let Err(e) = ws_stream.send(WSMessage::Text(sub_msg.to_string())).await {
                                error!("Failed to send subscription: {}", e);
                                continue;
                            }

                            while let Some(msg) = ws_stream.next().await {
                                match msg {
                                    Ok(WSMessage::Text(text)) => {
                                        if let Ok(value) = serde_json::from_str::<serde_json::Value>(&text) {
                                            if let Some(params) = value.get("params") {
                                                if let Some(result) = params.get("result") {
                                                    if let Some(data) = result.get("data") {
                                                        if let Some(raw_data) = data.as_str() {
                                                            if let Ok(decoded) = base64_engine.decode(raw_data) {
                                                                let _ = mempool_tx.lock().await.try_send(decoded);
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    Ok(WSMessage::Close(_)) => break,
                                    Err(e) => {
                                        error!("WebSocket error: {}", e);
                                        break;
                                    }
                                    _ => {}
                                }
                            }
                        }
                        Err(e) => error!("WebSocket connection error: {}", e),
                    }

                    tokio::time::sleep(Duration::from_secs(1)).await;
                }
            });
        });

        Ok(())
    }

    fn get_mempool_data<'a>(&self, py: Python<'a>) -> PyResult<Option<&'a PyBytes>> {
        let rx = self.mempool_rx.clone();
        
        match py.allow_threads(move || {
            let rt = tokio::runtime::Runtime::new().unwrap();
            rt.block_on(async { rx.lock().await.try_recv() })
        }) {
            Ok(data) => Ok(Some(PyBytes::new(py, &data))),
            Err(_) => Ok(None)
        }
    }

    fn update_config(&self, config: TradeConfig) -> PyResult<()> {
        let rt = tokio::runtime::Runtime::new().unwrap();
        rt.block_on(async {
            let mut current_config = self.config.lock().await;
            *current_config = config;
        });
        Ok(())
    }
}

impl TradingCore {
    async fn get_helius_priority_fee(&self) -> PyResult<u64> {
        let mut last_update = self.last_priority_update.lock().await;
        let now = Instant::now();

        if now.duration_since(*last_update) < PRIORITY_FEE_INTERVAL {
            return Ok(self.config.lock().await.priority_fee);
        }

        let helius_url = env::var("RPC_URL").expect("RPC_URL not set");
        let request = serde_json::json!({
            "jsonrpc": "2.0",
            "id": "helius-priority-fee",
            "method": "getPriorityFeeEstimate",
            "params": [{
                "accountKeys": [env::var("RAYDIUM_PROGRAM_ID").expect("RAYDIUM_PROGRAM_ID not set")],
                "options": {
                    "includeAllPriorityFeeLevels": false,
                    "priorityLevel": "High"
                }
            }]
        });

        let response = self.http_client
            .post(&helius_url)
            .json(&request)
            .send()
            .await
            .map_err(|e| {
                error!("Priority fee request failed: {}", e);
                PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string())
            })?;

        let fee_response: PriorityFeeResponse = response.json().await
            .map_err(|e| {
                error!("Failed to parse priority fee response: {}", e);
                PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string())
            })?;

        let fee = fee_response.result.priority_fee_estimate.unwrap_or(10000.0);
        *last_update = now;

        Ok((fee.max(MIN_PRIORITY_FEE as f64)) as u64)
    }

    fn get_swap_accounts(&self, pool: &PoolState, wsol_account: &str) -> Vec<AccountMeta> {
        vec![
            AccountMeta::new_readonly(
                Pubkey::from_str(&env::var("TOKEN_PROGRAM_ID")
                    .expect("TOKEN_PROGRAM_ID not set")).unwrap(),
                false
            ),
            AccountMeta::new(Pubkey::from_str(&pool.amm_id).unwrap(), false),
            AccountMeta::new_readonly(Pubkey::from_str(&pool.authority).unwrap(), false),
            AccountMeta::new(Pubkey::from_str(&pool.open_orders).unwrap(), false),
            AccountMeta::new(Pubkey::from_str(&pool.target_orders).unwrap(), false),
            AccountMeta::new(Pubkey::from_str(&pool.base_vault).unwrap(), false),
            AccountMeta::new(Pubkey::from_str(&pool.quote_vault).unwrap(), false),
            AccountMeta::new_readonly(Pubkey::from_str(&pool.market).unwrap(), false),
            AccountMeta::new(Pubkey::from_str(&pool.bids).unwrap(), false),
            AccountMeta::new(Pubkey::from_str(&pool.asks).unwrap(), false),
            AccountMeta::new(Pubkey::from_str(&pool.event_queue).unwrap(), false),
            AccountMeta::new(Pubkey::from_str(wsol_account).unwrap(), false),
            AccountMeta::new(self.keypair.pubkey(), true),
        ]
    }

    fn create_swap_data(&self, amount_in: u64, min_amount_out: u64) -> Vec<u8> {
        let mut data = Vec::with_capacity(17);
        data.push(9); // Raydium swap instruction discriminator
        data.extend_from_slice(&amount_in.to_le_bytes());
        data.extend_from_slice(&amount_in.to_le_bytes());
        data.extend_from_slice(&min_amount_out.to_le_bytes());
        data
    }
}

#[pymodule]
fn solana_rust_bot(_py: Python, m: &PyModule) -> PyResult<()> {
    dotenv().ok();
    env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));

    m.add_class::<TradingCore>()?;
    m.add_class::<TradeConfig>()?;
    m.add_class::<TradeParams>()?;
    m.add_class::<PoolState>()?;

    Ok(())
} fix the spacing please in here and put proper professional printing in terminal logging through the script absolute best professional debug logging printing u can put inside this script