please write this with proper spacing please and all the functions impliemented please use anyhow::{anyhow, Result};
use base64;
use bincode;
use config::{Config, File};
use ctrlc;
use env_logger::Env;
use futures_util::{SinkExt, StreamExt};
use log::{debug, error, info, warn};
use reqwest::Client as HttpClient;
use serde::{Deserialize, Serialize};
use serde_json::json;
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
    commitment_config::CommitmentConfig,
    hash::Hash,
    signer::{keypair::Keypair, Signer},
    transaction::Transaction,
};
use std::{
    collections::HashMap,
    fs::OpenOptions,
    io::{Read, Write},
    sync::Arc,
    time::{Duration, Instant},
};
use tokio::{sync::Mutex, time::interval};
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message as WsMessage};

// Constants
const WSOL_MINT: &str = "So11111111111111111111111111111111111111112";
const RAYDIUM_AMM_PROGRAM_ID: &str = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
const MAX_ACTIVE_TRADES: usize = 5;
const BUY_ATTEMPT_DELAY: Duration = Duration::from_millis(200);
const STATE_FILE: &str = "bot_state.json";
const PRICE_CHECK_INTERVAL: Duration = Duration::from_secs(1);
const SNIPE_AMOUNT: f64 = 0.01;
const MAX_RETRY_ATTEMPTS: u32 = 3;
const TAKING_PROFIT_PERCENT: f64 = 1.30;
const STOP_LOSS_PERCENT: f64 = 0.95;

// Hardcoded Keypair and Config Paths
const KEYPAIR_PATH: &str = "C:\\Users\\Orsen\\.config\\solana\\id.json";
const CONFIG_PATH: &str = "C:\\solana_rust_bot\\config.toml";

#[derive(Debug, Deserialize, Clone)]
pub struct BotConfig {
    rpc_url: String,
    helius_websocket_url: String,
    helius_api_key: String,
    max_slippage: f64,
    priority_fee: u64,
    min_liquidity: f64,
    max_liquidity: f64,
    min_sol_balance: f64,
}

fn load_config() -> Result<BotConfig> {
    let settings = Config::builder()
        .add_source(File::with_name(CONFIG_PATH))
        .build()?;
    settings.try_deserialize::<BotConfig>().map_err(|e| anyhow!("Failed to load config: {:?}", e))
}

fn load_keypair() -> Result<Keypair> {
    let data = std::fs::read(KEYPAIR_PATH)?;
    let json: Vec<u8> = serde_json::from_slice(&data)?;
    Keypair::from_bytes(&json).map_err(|e| anyhow!("Failed to load keypair: {:?}", e))
}

#[derive(Clone, Serialize, Deserialize, Debug)]
struct Trade {
    token_address: String,
    amount: u64,
    buy_price: f64,
    take_profit_price: f64,
    stop_loss_price: f64,
    timestamp: u64,
}

struct PriceCache {
    prices: HashMap<String, (f64, Instant)>,
    ttl: Duration,
}

impl PriceCache {
    fn new(ttl: u64) -> Self {
        Self {
            prices: HashMap::new(),
            ttl: Duration::from_secs(ttl),
        }
    }

    fn get(&self, token_address: &str) -> Option<f64> {
        self.prices
            .get(token_address)
            .and_then(|(price, timestamp)| {
                if timestamp.elapsed() < self.ttl {
                    Some(*price)
                } else {
                    None
                }
            })
    }

    fn set(&mut self, token_address: String, price: f64) {
        self.prices.insert(token_address.clone(), (price, Instant::now()));
        debug!("Price cache updated: {} = {}", token_address, price);
    }
}

struct Bot {
    config: BotConfig,
    rpc_client: Arc<RpcClient>,
    keypair: Arc<Keypair>,
    price_cache: Arc<Mutex<PriceCache>>,
    active_trades: Arc<Mutex<HashMap<String, Trade>>>,
    last_blockhash: Arc<Mutex<(Hash, Instant)>>,
    swap_limiter: Arc<Mutex<()>>,
    http_client: HttpClient,
}

impl Bot {
    async fn new() -> Result<Self> {
        info!("Loading configuration from config file");
        let config = load_config()?;
        info!("Config loaded: {:?}", config);

        let rpc_client = Arc::new(RpcClient::new_with_commitment(
            config.rpc_url.clone(),
            CommitmentConfig::processed(),
        ));
        let http_client = HttpClient::builder()
            .timeout(Duration::from_secs(10))
            .build()?;
        let keypair = Arc::new(load_keypair()?);
        debug!("Keypair successfully loaded.");

        let bot = Self {
            config,
            rpc_client,
            keypair,
            price_cache: Arc::new(Mutex::new(PriceCache::new(60))),
            active_trades: Arc::new(Mutex::new(HashMap::new())),
            last_blockhash: Arc::new(Mutex::new((Hash::default(), Instant::now()))),
            swap_limiter: Arc::new(Mutex::new(())),
            http_client,
        };
        bot.load_state().await?;
        info!("Bot initialized successfully.");
        Ok(bot)
    }

    async fn run(&self) -> Result<()> {
        info!("Starting Raydium Sniper Bot");

        let initial_balance = self.get_sol_balance().await?;
        info!("Initial SOL balance: {} SOL", initial_balance as f64 / 1e9);

        loop {
            info!("Attempting to connect to Helius WebSocket...");
            match connect_async(&self.config.helius_websocket_url).await {
                Ok((ws_stream, _)) => {
                    let (mut write, mut read) = ws_stream.split();
                    info!("Connected to Helius WebSocket");

                    let subscribe_message = json!({
                        "jsonrpc": "2.0",
                        "id": 1,
                        "method": "logsSubscribe",
                        "params": {
                            "filter": {
                                "programId": RAYDIUM_AMM_PROGRAM_ID
                            },
                            "commitment": "confirmed"
                        }
                    });
                    write.send(WsMessage::Text(subscribe_message.to_string())).await?;
                    info!("Subscribed to Raydium AMM logs");

                    let mut interval = interval(PRICE_CHECK_INTERVAL);
                    loop {
                        tokio::select! {
                            Some(msg) = read.next() => {
                                match msg {
                                    Ok(WsMessage::Text(text)) => {
                                        debug!("Received WebSocket message: {}", text);
                                        if let Err(e) = self.handle_event(&text).await {
                                            error!("Error handling event: {}", e);
                                        }
                                    }
                                    Ok(WsMessage::Close(_)) => {
                                        warn!("WebSocket connection closed");
                                        break;
                                    }
                                    Ok(_) => {},
                                    Err(e) => {
                                        error!("WebSocket error: {}", e);
                                        break;
                                    }
                                }
                            }
                            _ = interval.tick(), if !self.active_trades.lock().await.is_empty() => {
                                if let Err(e) = self.check_active_trades().await {
                                    error!("Error checking active trades: {}", e);
                                }
                            }
                        }
                    }
                }
                Err(e) => {
                    error!("WebSocket connect error: {}. Retrying in 5 seconds...", e);
                    tokio::time::sleep(Duration::from_secs(5)).await;
                }
            }
        }
    }

    async fn handle_event(&self, text: &str) -> Result<()> {
        debug!("Handling event for message: {}", text);
        let event: serde_json::Value = serde_json::from_str(text)?;

        if let Some(error) = event.get("error") {
            return Err(anyhow!("WebSocket error received: {:?}", error));
        }

        if let Some(params) = event.get("params") {
            if let Some(token_address) = params.get("tokenAddress").and_then    .as_str() {
                info!("New pool detected: Token {}", token_address);
        
                let token_metadata = self.get_token_metadata(token_address).await?;
                if token_metadata.get("mutable").map_or(false, |v| !v.as_bool().unwrap_or(false)) &&
                   token_metadata.get("burnt").map_or(false, |v| v.as_bool().unwrap_or(false)) {
        
                    self.process_token(token_address.to_string()).await?;
                } else {
                    warn!("Token {} does not meet criteria (mutable false, burnt true). Skipping.", token_address);
                }
            } else {
                warn!("Invalid WebSocket message format. Skipping.");
            }
                Ok(())
            }
        
            async fn process_token(&self, token_address: String) -> Result<()> {
                info!("Processing token {}", token_address);
        
                if self.is_valid_pool(&token_address).await? {
                    info!("Token {} is valid, attempting to buy...", token_address);
                    self.attempt_buy(token_address).await?;
                } else {
                    warn!("Token {} failed validation checks. Skipping.", token_address);
                }
                Ok(())
            }
        
            async fn get_token_metadata(&self, token_address: &str) -> Result<serde_json::Value> {
                let url = format!("{}?api-key={}", self.config.rpc_url, self.config.helius_api_key);
                let body = json!({
                    "jsonrpc": "2.0",
                    "id": "get-token-metadata",
                    "method": "getTokenMetadata",
                    "params": [
                        [token_address]
                    ]
                });
        
                info!("Fetching token metadata from URL: {}", url);
        
                let response = self.http_client.post(&url).json(&body).send().await?.json::<serde_json::Value>().await?;
                debug!("Received token metadata response: {:?}", response);
        
                Ok(response["result"].as_array().ok_or_else(|| anyhow!("Invalid metadata response format"))?.first().cloned().unwrap_or_default())
            }
        
            async fn get_token_price(&self, token_address: &str) -> Result<f64> {
                debug!("Fetching token price for: {}", token_address);
                let url = format!("{}?api-key={}", self.config.rpc_url, self.config.helius_api_key);
        
                let body = json!({
                    "jsonrpc": "2.0",
                    "id": "get-token-price",
                    "method": "getTokenMetadata",
                    "params": [
                        [token_address]
                    ]
                });
        
                info!("Fetching token price from URL: {}", url);
                let response = self.http_client.post(&url).json(&body).send().await?.json::<serde_json::Value>().await?;
        
                debug!("Received price response: {:?}", response);
        
                if let Some(price) = response["result"][0]["price"].as_f64() {
                    Ok(price)
                } else {
                    Err(anyhow!("Price not found for token {}", token_address))
                }
            }
        
            async fn attempt_buy(&self, token_address: String) -> Result<()> {
                info!("Starting buy attempts for token: {}", token_address);
                let active_trades_count = self.active_trades.lock().await.len();
                if active_trades_count >= MAX_ACTIVE_TRADES {
                    warn!("Maximum active trades ({}) reached. Skipping buy for {}.", MAX_ACTIVE_TRADES, token_address);
                    return Ok(());
                }
        
                let snipe_amount = SNIPE_AMOUNT;
                let snipe_amount_lamports = (snipe_amount * 1e9) as u64;
        
                for attempt in 1..=MAX_RETRY_ATTEMPTS {
                    info!("Buy attempt {} for token {}.", attempt, token_address);
                    match self.execute_buy(&token_address, snipe_amount_lamports).await {
                        Ok(_) => {
                            info!("Successfully bought token {}", token_address);
                            return Ok(());
                        }
                        Err(e) => {
                            warn!("Buy attempt {} failed for token {}: {}", attempt, token_address, e);
                            if attempt < MAX_RETRY_ATTEMPTS {
                                tokio::time::sleep(BUY_ATTEMPT_DELAY).await;
                            }
                        }
                    }
                }
                error!("All buy attempts failed for token: {}", token_address);
                Ok(())
            }
        
            async fn execute_buy(&self, token_address: &str, amount: u64) -> Result<()> {
                debug!("Preparing to execute buy for token: {}, amount: {}", token_address, amount);
                let _guard = self.swap_limiter.lock().await;
        
                let jupiter_quote_url = format!(
                    "https://quote-api.jup.ag/v4/quote?inputMint={}&outputMint={}&amount={}&slippageBps={}",
                    WSOL_MINT,
                    token_address,
                    amount,
                    (self.config.max_slippage * 100.0) as u64
                );
        
                let quote: serde_json::Value = self.http_client.get(&jupiter_quote_url).send().await?.json().await?;
                debug!("Received Jupiter quote: {:?}", quote);
        
                let route = quote["data"].as_array()
                    .and_then(|arr| arr.first())
                    .ok_or_else(|| anyhow!("No route found"))?;
        
                let jupiter_swap_url = "https://quote-api.jup.ag/v4/swap";
                let swap_request = json!({
                    "route": route,
                    "userPublicKey": self.keypair.pubkey().to_string(),
                    "wrapUnwrapSOL": true
                });
        
                let swap_response: serde_json::Value = self.http_client.post(jupiter_swap_url)
                    .json(&swap_request)
                    .send().await?
                    .json().await?;
                debug!("Received Jupiter swap response: {:?}", swap_response);
        
                let swap_transaction = swap_response["swapTransaction"].as_str()
                    .ok_or_else(|| anyhow!("Swap transaction not found in response"))?;
        
                let decoded_transaction = base64::decode(swap_transaction)?;
                let mut transaction: Transaction = bincode::deserialize(&decoded_transaction)?;
        
                let (blockhash, _) = self.get_latest_blockhash().await?;
                transaction.message.recent_blockhash = blockhash;
        
                transaction.sign(&[&*self.keypair], transaction.message.recent_blockhash);
        
                let signature = self.rpc_client.send_and_confirm_transaction_with_spinner(&transaction)?;
                info!("Buy transaction confirmed: {}", signature);
        
                let buy_price = self.get_token_price(token_address).await?;
                let take_profit_price = buy_price * TAKING_PROFIT_PERCENT;
                let stop_loss_price = buy_price * STOP_LOSS_PERCENT;
        
                let trade = Trade {
                    token_address: token_address.to_string(),
                    amount,
                    buy_price,
                    take_profit_price,
                    stop_loss_price,
                    timestamp: chrono::Utc::now().timestamp() as u64,
                };
        
                self.active_trades.lock().await.insert(token_address.to_string(), trade);
                self.save_state().await?;
        
                Ok(())
            }
        
            async fn check_active_trades(&self) -> Result<()> {
                debug!("Checking active trades");
                let mut trades_to_remove = Vec::new();
        
                for (token_address, trade) in self.active_trades.lock().await.iter() {
                    match self.get_token_price(token_address).await {
                        Ok(current_price) => {
                            if current_price >= trade.take_profit_price || current_price <= trade.stop_loss_price {
                                info!("Executing sell for token: {}", token_address);
                                if let Err(e) = self.execute_sell(token_address, trade.amount).await {
                                    error!("Failed to sell token {}: {}", token_address, e);
                                } else {
                                    trades_to_remove.push(token_address.clone());
                                }
                            }
                        }
                        Err(e) => {
                            warn!("Failed to get price for token {}: {}", token_address, e);
                        }
                    }
                }
        
                for token_address in trades_to_remove {
                    self.active_trades.lock().await.remove(&token_address);
                }
        
                self.save_state().await?;
                Ok(())
            }
        
            async fn execute_sell(&self, token_address: &str, amount: u64) -> Result<()> {
                debug!("Preparing to execute sell for token: {}, amount: {}", token_address, amount);
                let _guard = self.swap_limiter.lock().await;
        
                let jupiter_quote_url
                async fn execute_sell(&self, token_address: &str, amount: u64) -> Result<()> {
                    debug!("Preparing to execute sell for token: {}, amount: {}", token_address, amount);
                    let _guard = self.swap_limiter.lock().await;
            
                    let jupiter_quote_url = format!(
                        "https://quote-api.jup.ag/v4/quote?inputMint={}&outputMint={}&amount={}&slippageBps={}",
                        token_address,
                        WSOL_MINT,
                        amount,
                        (self.config.max_slippage * 100.0) as u64
                    );
            
                    let quote: serde_json::Value = self.http_client.get(&jupiter_quote_url).send().await?.json().await?;
                    debug!("Received Jupiter quote for sell: {:?}", quote);
            
                    let route = quote["data"].as_array()
                        .and_then(|arr| arr.first())
                        .ok_or_else(|| anyhow!("No route found for sell"))?;
            
                    let jupiter_swap_url = "https://quote-api.jup.ag/v4/swap";
                    let swap_request = json!({
                        "route": route,
                        "userPublicKey": self.keypair.pubkey().to_string(),
                        "wrapUnwrapSOL": true
                    });
            
                    let swap_response: serde_json::Value = self.http_client.post(jupiter_swap_url)
                        .json(&swap_request)
                        .send().await?
                        .json().await?;
                    debug!("Received Jupiter swap response for sell: {:?}", swap_response);
            
                    let swap_transaction = swap_response["swapTransaction"].as_str()
                        .ok_or_else(|| anyhow!("Swap transaction not found in response"))?;
            
                    let decoded_transaction = base64::decode(swap_transaction)?;
                    let mut transaction: Transaction = bincode::deserialize(&decoded_transaction)?;
            
                    let (blockhash, _) = self.get_latest_blockhash().await?;
                    transaction.message.recent_blockhash = blockhash;
            
                    transaction.sign(&[&*self.keypair], transaction.message.recent_blockhash);
            
                    let signature = self.rpc_client.send_and_confirm_transaction_with_spinner(&transaction)?;
                    info!("Sell transaction confirmed: {}", signature);
            
                    Ok(())
                }
            
                async fn is_valid_pool(&self, token_address: &str) -> Result<bool> {
                    debug!("Checking if pool is valid for token: {}", token_address);
                    let liquidity = self.get_pool_liquidity(token_address).await?;
            
                    if liquidity < self.config.min_liquidity || liquidity > self.config.max_liquidity {
                        warn!("Token {} liquidity ({}) is outside the configured range.", token_address, liquidity);
                        return Ok(false);
                    }
            
                    Ok(true)
                }
            
                async fn get_pool_liquidity(&self, token_address: &str) -> Result<f64> {
                    debug!("Fetching pool liquidity for token: {}", token_address);
                    // Implement the logic to fetch pool liquidity from Raydium or another source
                    // This is a placeholder implementation
                    Ok(1000000.0)  // Return a dummy value for now
                }
            
                async fn get_latest_blockhash(&self) -> Result<(Hash, Instant)> {
                    let mut guard = self.last_blockhash.lock().await;
                    if guard.1.elapsed() > Duration::from_secs(120) {
                        let blockhash = self.rpc_client.get_latest_blockhash()?;
                        *guard = (blockhash, Instant::now());
                    }
                    Ok(guard.clone())
                }
            
                async fn get_sol_balance(&self) -> Result<u64> {
                    self.rpc_client.get_balance(&self.keypair.pubkey()).map_err(|e| anyhow!("Failed to get SOL balance: {}", e))
                }
            
                async fn save_state(&self) -> Result<()> {
                    let state = self.active_trades.lock().await.clone();
                    let serialized = serde_json::to_string(&state)?;
                    let mut file = OpenOptions::new().write(true).create(true).truncate(true).open(STATE_FILE)?;
                    file.write_all(serialized.as_bytes())?;
                    debug!("Bot state saved to file");
                    Ok(())
                }
            
                async fn load_state(&self) -> Result<()> {
                    let mut file = match OpenOptions::new().read(true).open(STATE_FILE) {
                        Ok(file) => file,
                        Err(_) => {
                            debug!("No existing state file found. Starting with empty state.");
                            return Ok(());
                        }
                    };
            
                    let mut contents = String::new();
                    file.read_to_string(&mut contents)?;
                    let state: HashMap<String, Trade> = serde_json::from_str(&contents)?;
                    *self.active_trades.lock().await = state;
                    debug!("Bot state loaded from file");
                    Ok(())
                }
            }
            
            #[tokio::main]
            async fn main() -> Result<()> {
                env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
                info!("Starting Raydium Sniper Bot");
            
                let bot = Arc::new(Bot::new().await?);
                let bot_clone = Arc::clone(&bot);
            
                ctrlc::set_handler(move || {
                    info!("Received Ctrl+C, shutting down...");
                    std::process::exit(0);
                })?;
            
                bot_clone.run().await?;
            
                Ok(())
            }
            
            fn extract_token_address(log: &str) -> Option<String> {
                // Implement logic to extract token address from the log
                // This is a placeholder implementation
                None
            }