do me a huge huge huge favor just rewrite this word for word line for line but just fix the spacing please use anyhow::{anyhow, Result};
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
use dashmap::DashMap;
use futures::future::{BoxFuture, FutureExt};
use pyo3::{exceptions::PyRuntimeError, prelude::*};
use pyo3_asyncio::tokio::future_into_py;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{
    compute_budget::ComputeBudgetInstruction,
    instruction::Instruction,
    message::Message,
    pubkey::Pubkey,
    signature::{Keypair, Signer},
    transaction::Transaction,
};
use std::{
    collections::HashMap,
    fs::File,
    io::Read,
    str::FromStr,
    sync::{Arc, Once},
    time::{Duration, SystemTime, UNIX_EPOCH},
};
use tokio::{runtime::Runtime, sync::RwLock};

// Constants
pub const JUPITER_API: &str = "https://quote-api.jupiter.money/v6";
pub const SOL_MINT: &str = "So11111111111111111111111111111111111111112";
pub const HELIUS_API_HEADER: &str = "Bearer ";
pub const JUPITER_PROGRAM_ID: &str = "JUP4bFbhX7S6JCGQqVfJk3sNpZbG6ZoAyu73f5fJxw3";
pub const MAX_RETRIES: u32 = 3;
pub const RETRY_DELAY_MS: u64 = 500;

// Runtime management
static RUNTIME_INIT: Once = Once::new();
static mut RUNTIME: Option<Runtime> = None;

fn get_runtime() -> PyResult<&'static Runtime> {
    unsafe {
        RUNTIME_INIT.call_once(|| {
            RUNTIME = Some(Runtime::new().unwrap());
        });

        RUNTIME.as_ref().ok_or_else(|| PyRuntimeError::new_err("Critical error: Runtime not initialized"))
    }
}

// Configuration structures
#[derive(Serialize, Deserialize, Debug)]
pub struct NetworkConfig {
    pub api_key: String,
    pub rpc_url: String,
    pub ws_url: String,
    pub backup_rpc: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct SnipingConfig {
    pub buy_amount: f64,
    pub max_slippage: f64,
    pub priority_fee: u64,
    pub min_liquidity: f64,
    pub min_market_cap: f64,
    pub min_volume: f64,
    pub buyer_seller_ratio: f64,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ScalpingConfig {
    pub position_size: f64,
    pub take_profit: f64,
    pub stop_loss: f64,
    pub max_position_size: f64,
    pub scaling_threshold: u64,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PerformanceConfig {
    pub max_concurrent_trades: usize,
    pub price_impact_threshold: f64,
    pub volatility_threshold: f64,
    pub update_interval_ms: usize,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PoolConfig {
    pub token: String,
    pub raydium_pool: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
    pub network: NetworkConfig,
    pub sniping: SnipingConfig,
    pub scalping: ScalpingConfig,
    pub performance: PerformanceConfig,
    pub pools: Vec<PoolConfig>,
}

#[pyclass]
#[derive(Clone, Debug)]
pub struct ScalperSettings {
    #[pyo3(get, set)]
    pub min_price_change: f64,
    #[pyo3(get, set)]
    pub max_position_size: f64,
    pub take_profit: f64,
    pub stop_loss: f64,
    pub max_slippage: f64,
    pub min_volume: f64,
    pub priority_fee: u64,
}

#[pymethods]
impl ScalperSettings {
    #[new]
    fn new() -> Self {
        Self {
            min_price_change: 0.5,
            max_position_size: 0.1,
            take_profit: 1.0,
            stop_loss: -0.5,
            max_slippage: 0.5,
            min_volume: 1000.0,
            priority_fee: 15000,
        }
    }
}

#[pyclass]
#[derive(Clone, Debug)]
pub struct Trade {
    #[pyo3(get)]
    pub token: String,
    #[pyo3(get)]
    pub entry_price: f64,
    #[pyo3(get)]
    pub current_price: f64,
    #[pyo3(get)]
    pub size: f64,
    #[pyo3(get)]
    pub profit_loss: f64,
    #[pyo3(get)]
    pub timestamp: i64,
    #[pyo3(get)]
    pub status: String,
}

#[pyclass]
#[derive(Clone, Debug)]
pub struct MarketData {
    #[pyo3(get)]
    pub price: f64,
    #[pyo3(get)]
    pub volume_24h: f64,
    #[pyo3(get)]
    pub liquidity: f64,
    #[pyo3(get)]
    pub price_change_24h: f64,
    #[pyo3(get)]
    pub timestamp: i64,
}

impl Default for MarketData {
    fn default() -> Self {
        Self {
            price: 0.0,
            volume_24h: 0.0,
            liquidity: 0.0,
            price_change_24h: 0.0,
            timestamp: SystemTime::now()
               .duration_since(UNIX_EPOCH)
               .unwrap_or_default()
               .as_secs() as i64,
        }
    }
}

// Load Configuration
fn load_config(file_path: &str) -> Result<Config> {
    let mut file = File::open(file_path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    let config: Config = serde_json::from_str(&contents)?;
    Ok(config)
}

// Main trader
#[pyclass]
pub struct SolanaTrader {
    settings: Arc<RwLock<ScalperSettings>>,
    http_client: Arc<Client>,
    rpc_client: Arc<RpcClient>,
    active_trades: Arc<DashMap<String, Trade>>,
    market_data: Arc<DashMap<String, MarketData>>,
    keypair: Arc<Keypair>,
    runtime: &'static Runtime,
    config: Arc<Config>,
}

#[pymethods]
impl SolanaTrader {
    #[new]
    fn new(config_path: String, keypair_bytes: Vec<u8>) -> PyResult<Self> {
        let runtime = get_runtime()?;

        runtime.block_on(async {
            let keypair = Keypair::from_bytes(&keypair_bytes)
               .map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?;

            let config = load_config(&config_path)
               .map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?;

            let http_client = Client::builder()
               .timeout(Duration::from_secs(10))
               .pool_max_idle_per_host(100)
               .build()
               .map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?;

            let settings = Arc::new(RwLock::new(ScalperSettings {
                min_price_change: 0.0,
                max_position_size: config.scalping.max_position_size,
                take_profit: config.scalping.take_profit,
                stop_loss: config.scalping.stop_loss,
                max_slippage: config.sniping.max_slippage,
                min_volume: config.sniping.min_volume,
                priority_fee: config.sniping.priority_fee,
            }));

            Ok(Self {
                settings,
                http_client: Arc::new(http_client),
                rpc_client: Arc::new(RpcClient::new(config.network.rpc_url.clone())),
                active_trades: Arc::new(DashMap::new()),
                market_data: Arc::new(DashMap::new()),
                keypair: Arc::new(keypair),
                runtime,
                config: Arc::new(config),
            })
        })
    }

    #[pyo3(text_signature = "($self, token, is_buy)")]
    fn execute_trade<'p>(&self, py: Python<'p>, token: String, is_buy: bool) -> PyResult<&'p PyAny> {
        let settings = self.settings.clone();
        let http_client = self.http_client.clone();
        let rpc_client = self.rpc_client.clone();
        let active_trades = self.active_trades.clone();
        let keypair = self.keypair.clone();
        let config = self.config.clone();

        // Wrap in future_into_py to integrate with Python
        future_into_py(py, async move {
            if Pubkey::from_str(&token).is_err() {
                return Err(PyRuntimeError::new_err("Invalid token address"));
            }

            let amount = {
                let settings = settings.read().await;
                if is_buy {
                    settings.max_position_size
                } else {
                    active_trades.get(&token)
                       .map(|t| t.size)
                       .ok_or_else(|| PyRuntimeError::new_err("No active trade found for token"))?
                }
            };
            
            let lamports = (amount * 1e9) as u64;
            
            let quote = Self::retry_request(
                || {
                    let http_client = http_client.clone();
                    Box::pin(Self::get_jupiter_quote(&http_client, token.clone(), lamports, is_buy))
                },
                MAX_RETRIES
            ).await.map_err(|e| PyRuntimeError::new_err(format!("Jupiter quote error: {}", e)))?;
            
            let signature = Self::retry_request(
                || {
                    let keypair = keypair.clone();
                    let rpc_client = rpc_client.clone();
                    let settings = settings.clone();
                    Box::pin(Self::execute_jupiter_swap(quote, keypair, rpc_client, settings))
                },
                MAX_RETRIES
            ).await.map_err(|e| PyRuntimeError::new_err(format!("Transaction error: {}", e)))?;
            
            if is_buy {
                let market_data = Self::fetch_market_data_internal(
                    &http_client,
                    &rpc_client,
                    &token,
                    &config
                ).await.map_err(|e| PyRuntimeError::new_err(format!("Market data error: {}", e)))?;
            
                active_trades.insert(token.clone(), Trade {
                    token,
                    entry_price: market_data.price,
                    current_price: market_data.price,
                    size: amount,
                    profit_loss: 0.0,
                    timestamp: SystemTime::now()
                       .duration_since(UNIX_EPOCH)
                       .unwrap_or_default()
                       .as_secs() as i64,
                    status: "ACTIVE".to_string(),
                });
            } else {
                active_trades.remove(&token);
            }
            
            Ok(signature.to_string())
        })
    }
    #[pyo3(text_signature = "($self, token)")]
fn get_market_data<'p>(&self, py: Python<'p>, token: String) -> PyResult<&'p PyAny> {
    let http_client = self.http_client.clone();
    let rpc_client = self.rpc_client.clone();
    let config = self.config.clone();

    // Wrap in future_into_py to integrate with Python
    future_into_py(py, async move {
        Self::fetch_market_data_internal(&http_client, &rpc_client, &token, &config)
           .await.map_err(|e| PyRuntimeError::new_err(format!("Market data error: {}", e)))
    })
}

fn get_active_trades(&self) -> PyResult<HashMap<String, Trade>> {
    Ok(self.active_trades
       .iter()
       .map(|entry| (entry.key().clone(), entry.value().clone()))
       .collect())
}

fn update_settings(&self, settings: ScalperSettings) -> PyResult<()> {
    let settings_arc = self.settings.clone();
    self.runtime.block_on(async move {
        *settings_arc.write().await = settings;
        Ok(())
    })
}

fn retry_request<F>(operation: F, max_retries: u32) -> BoxFuture<'static, Result<Value>>
where
    F: Fn() -> BoxFuture<'static, Result<Value>> + Send +'static,
{
    Box::pin(async move {
        let mut retries = 0;
        let mut delay = RETRY_DELAY_MS;

        loop {
            match operation().await {
                Ok(result) => return Ok(result),
                Err(e) => {
                    if retries >= max_retries {
                        return Err(anyhow!("Operation failed after {} retries: {}", max_retries, e));
                    }
                    retries += 1;
                    tokio::time::sleep(Duration::from_millis(delay)).await;
                    delay *= 2; // Exponential backoff
                }
            }
        }
    })
}

async fn fetch_market_data_internal(
    http_client: &Client,
    rpc_client: &RpcClient,
    token: &str,
    config: &Config,
) -> Result<MarketData> {
    let fetch_data = |endpoint: &str| {
        let http_client = http_client.clone();
        let rpc_url = rpc_client.url().clone();
        let token = token.to_string();
        let api_key = config.network.api_key.clone();

        Box::pin(async move {
            let request = json!({
                "jsonrpc": "2.0",
                "id": format!("helius-{}", endpoint),
                "method": "getAssetBatch",
                "params": {
                    "mints": [token],
                    "options": { "showMarketData": true }
                }
            });

            let response = http_client
               .post(&rpc_url)
               .header("Authorization", format!("{} {}", HELIUS_API_HEADER, api_key))
              .json(&request)
              .send()
              .await?
              .json::<Value>()
              .await?;

            if let Some(error) = response.get("error") {
                return Err(anyhow!("API error: {}", error));
            }

            Ok(response.get("result").ok_or_else(|| anyhow!("Invalid response: missing'result' field"))?.clone()) // Use.clone() to obtain a Value
        })
    };

    let (price, volume, liquidity) = tokio::try_join!(
        Self::retry_request(|| fetch_data("price"), MAX_RETRIES),
        Self::retry_request(|| fetch_data("volume"), MAX_RETRIES),
        Self::retry_request(|| fetch_data("liquidity"), MAX_RETRIES)
    )?;

    let extract_market_data = |data: &Value, field: &str| -> Result<f64> {
        data.get("marketData")
          .and_then(|m| m.get(field))
          .and_then(|v| v.as_f64())
          .ok_or_else(|| anyhow!("Invalid {} data structure", field))
    };

    let price_value = extract_market_data(&price, "price")?;
    let volume_value = extract_market_data(&volume, "volume24h")?;
    let liquidity_value = extract_market_data(&liquidity, "liquidity")?;

    Ok(MarketData {
        price: price_value,
        volume_24h: volume_value,
        liquidity: liquidity_value,
        price_change_24h: 0.0, // Placeholder for actual price change calculation
        timestamp: SystemTime::now()
          .duration_since(UNIX_EPOCH)
          .map_err(|e| anyhow!("System time error: {}", e))?
          .as_secs() as i64,
    })
}

async fn get_jupiter_quote(
    http_client: &Client,
    token: String,
    amount: u64,
    is_buy: bool,
) -> Result<Value> {
    let quote_url = if is_buy {
        format!(
            "{}/quote?inputMint={}&outputMint={}&amount={}&slippageBps=50",
            JUPITER_API, SOL_MINT, token, amount
        )
    } else {
        format!(
            "{}/quote?inputMint={}&outputMint={}&amount={}&slippageBps=50",
            JUPITER_API, token, SOL_MINT, amount
        )
    };

    let response = http_client.get(&quote_url)
      .send()
      .await?
      .json::<Value>()
      .await?;

    if let Some(error) = response.get("error") {
        return Err(anyhow!("Jupiter quote error: {}", error));
    }

    Ok(response)
}

async fn execute_jupiter_swap(
    quote: Value,
    keypair: Arc<Keypair>,
    rpc_client: Arc<RpcClient>,
    settings: Arc<RwLock<ScalperSettings>>,
) -> Result<String> {
    let settings = settings.read().await;

    let swap_request = json!({
        "quoteResponse": quote,
        "userPublicKey": keypair.pubkey().to_string(),
        "wrapUnwrapSOL": true,
        "computeUnitPriceMicroLamports": settings.priority_fee,
        "priorityFeeLamports": settings.priority_fee,
        "asLegacyTransaction": false,
        "maxAccounts": 64,
        "useSharedAccounts": true,
    });

    let client = Client::new();
    let swap_response = client.post(format!("{}/swap", JUPITER_API))
      .json(&swap_request)
      .send()
      .await?
      .json::<Value>()
      .await?;

    let swap_data = swap_response["swapTransaction"]
      .as_str()
      .ok_or_else(|| anyhow!("Invalid swap data"))?;

    let blockhash = rpc_client.get_latest_blockhash().await?;
    let swap_data_bytes = BASE64.decode(swap_data)?;

    let priority_ix = ComputeBudgetInstruction::set_compute_unit_price(settings.priority_fee);
    let swap_ix = Instruction {
        program_id: Pubkey::from_str(JUPITER_PROGRAM_ID)?,
        accounts: vec![],
        data: swap_data_bytes,
    };

    let message = Message::new(
        &[priority_ix, swap_ix],
        Some(&keypair.pubkey())
    );

    let mut transaction = Transaction::new_unsigned(message);
    transaction.sign(&[keypair.as_ref()], blockhash);

    let signature = rpc_client.send_and_confirm_transaction(&transaction).await?;
    Ok(signature.to_string())
}
}
#[pyo3]
fn main() -> PyResult<()> {
    let file_path = "config.json";
    let config = load_config(file_path)?;

    let keypair_bytes = {
        let mut file = File::open("keypair.json")?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        contents.as_bytes().to_vec()
    };

    let trader = SolanaTrader::new(file_path.to_string(), keypair_bytes)?;

    let runtime = get_runtime()?;

    runtime.block_on(async {
        let settings = trader.settings.clone();
        let http_client = trader.http_client.clone();
        let rpc_client = trader.rpc_client.clone();
        let active_trades = trader.active_trades.clone();
        let keypair = trader.keypair.clone();
        let config = trader.config.clone();

        let (tx, mut rx) = tokio::sync::mpsc::channel(1);

        let task = runtime.spawn(async move {
            while let Some(token) = rx.recv().await {
                let is_buy = {
                    let active_trades = active_trades.clone();
                    active_trades.get(&token)
                      .map(|t| t.status == "ACTIVE")
                      .unwrap_or(false)
                };

                if is_buy {
                    println!("Attempting to sell {}", token);
                    trader.execute_trade(token, false).await?;
                } else {
                    println!("Attempting to buy {}", token);
                    trader.execute_trade(token, true).await?;
                }
            }
        });

        let mut interval = tokio::time::interval(Duration::from_millis(1000));

        loop {
            interval.tick().await;
            let market_data = trader.get_market_data("SOL").await?;
            println!("{:?}", market_data);

            let mut active_trades = active_trades.clone();
            for (token, trade) in active_trades.iter() {
                let market_data = trader.get_market_data(token).await?;
                let profit_loss = (market_data.price - trade.entry_price) / trade.entry_price;
                println!("{}: {}", token, profit_loss);

                if profit_loss > settings.read().await.take_profit {
                    tx.send(token.clone()).await?;
                } else if profit_loss < settings.read().await.stop_loss {
                    tx.send(token.clone()).await?;
                }
            }
        }
    });

    Ok(())
}

#[pymodule]
fn solana_rust_bot(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<SolanaTrader>()?;
    m.add_class::<ScalperSettings>()?;
    m.add_class::<Trade>()?;
    m.add_class::<MarketData>()?;
    Ok(())
}