please fix this script use anyhow::{anyhow, Result};
use base64::{engine::general_purpose::STANDARD as base64_engine, Engine};
use colored::*;
use config::{Config, File};
use futures_util::{SinkExt, StreamExt};
use log::{info};
use serde::{Deserialize, Serialize};
use serde_json::json;
use solana_client::rpc_client::RpcClient;
use solana_client::rpc_request::TokenAccountsFilter;
use solana_sdk::{
    commitment_config::CommitmentConfig,
    instruction::{AccountMeta, Instruction},
    message::Message,
    pubkey::Pubkey,
    signer::{keypair::read_keypair_file, keypair::Keypair, Signer},
    transaction::Transaction,
};
use std::str::FromStr;
use std::{
    collections::HashMap,
    sync::{Arc, Mutex},
    time::Duration,
};
use tokio::{self, time::interval};
use tokio_tungstenite::{connect_async, tungstenite::Message as WsMessage};

const WSOL_MINT: &str = "So11111111111111111111111111111111111111112";
const RAYDIUM_AMM_PROGRAM_ID: &str = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
const MAX_CONCURRENT_TRADES: usize = 5;
const MIN_PRIORITY_FEE: u64 = 10000;

#[derive(Debug, Deserialize, Clone)]
struct BotConfig {
    rpc_url: String,
    ws_url: String,
    solana_rpc_url: String,
    fallback_url: String,
    keypair_path: String,
    helius_api_key: String,

    // Trading parameters
    snipe_amount: u64,
    profit_target_percent: f64,
    stop_loss_percent: f64,
    max_slippage: f64,
    priority_fee: u64,
    min_sol_balance: f64,

    // Token requirements
    mutable: bool,
    burnt: bool,
    frozen: bool,
    min_supply: u64,

    // WebSocket settings
    reconnect_interval: u64,

    // Logging
    debug: bool,
    log_level: String,
    show_scanning: bool,
    show_trades: bool,
    show_balances: bool,
}

#[derive(Debug, Deserialize, Clone)]
struct BotConfig {
    rpc_url: String,
    ws_url: String,
    solana_rpc_url: String,
    fallback_url: String,
    keypair_path: String,
    helius_api_key: String,
    snipe_amount: u64,
    profit_target_percent: f64,
    stop_loss_percent: f64,
    max_slippage: f64,
    priority_fee: u64,
    min_sol_balance: f64,
    mutable: bool,
    burnt: bool,
    frozen: bool,
    min_supply: u64,
    reconnect_interval: u64,
    debug: bool,
    log_level: String,
    show_scanning: bool,
    show_trades: bool,
    show_balances: bool,
}


#[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,
    status: TradeStatus,
    initial_buy_amount: u64,
}

#[derive(Clone, Serialize, Deserialize, Debug)]
enum TradeStatus {
    Active,
    PendingSell,
    Completed,
    Failed(String),
}

#[derive(Serialize, Deserialize)]
struct SavedState {
    active_trades: HashMap<String, Trade>,
    last_update: i64,
}

impl Bot {
    async fn new() -> Result<Self> {
        println!(
            "{}",
            "🔫 Initializing Solana Sniper Bot v2.0"
                .bright_green()
                .bold()
        );

        let config = Config::builder()
            .add_source(File::with_name("config.toml"))
            .build()?
            .try_deserialize::<BotConfig>()?;

        let keypair = Arc::new(read_keypair_file(&config.keypair_path)
            .map_err(|e| anyhow::Error::msg(e.to_string()))?);      
        println!(
            "{}",
            format!("💰 Loaded wallet: {}", keypair.pubkey()).yellow()
        );

        let rpc_client = Arc::new(RpcClient::new_with_commitment(
            config.rpc_url.clone(),
            CommitmentConfig::confirmed(),
        ));

        let secondary_rpc = Arc::new(RpcClient::new_with_commitment(
            config.solana_rpc_url.clone(),
            CommitmentConfig::confirmed(),
        ));

        let fallback_rpc = Arc::new(RpcClient::new_with_commitment(
            config.fallback_url.clone(),
            CommitmentConfig::confirmed(),
        ));

        let http_client = reqwest::Client::builder()
            .timeout(Duration::from_secs(5))
            .pool_idle_timeout(Duration::from_secs(30))
            .pool_max_idle_per_host(32)
            .default_headers({
                let mut headers = reqwest::header::HeaderMap::new();
                headers.insert(
                    "Authorization",
                    format!("Bearer {}", config.helius_api_key).parse()?,
                );
                headers
            })
            .build()?;

        let active_trades = Arc::new(Mutex::new(HashMap::new()));

        Ok(Self {
            config,
            rpc_client,
            secondary_rpc,
            fallback_rpc,
            keypair,
            active_trades,
            http_client,
        })
    }

    async fn can_take_new_trade(&self) -> bool {
        self.active_trades.lock().unwrap().len() < MAX_CONCURRENT_TRADES - 1
    }

    async fn get_priority_fee(&self, token_address: &str) -> Result<u64> {
        let priority_fee_response = self
            .http_client
            .post(&self.config.rpc_url)
            .json(&json!({
                "jsonrpc": "2.0",
                "id": "marga-priority",
                "method": "getPriorityFeeEstimate",
                "params": [{
                    "accountKeys": [token_address],
                    "options": {
                        "includeAllPriorityFeeLevels": true
                    }
                }]
            }))
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;

        Ok(priority_fee_response["result"]["priorityFeeLamports"]
            .as_u64()
            .unwrap_or(self.config.priority_fee)
            .max(MIN_PRIORITY_FEE))
    }

    async fn get_token_price(&self, token_address: &str) -> Result<f64> {
        // Try Jupiter first
        let jupiter_result = self.get_jupiter_price(token_address).await;

        if let Ok(price) = jupiter_result {
            return Ok(price);
        }

        // Fallback to Helius
        self.get_helius_price(token_address).await
    }

    async fn get_jupiter_price(&self, token_address: &str) -> Result<f64> {
        let price_response = self
            .http_client
            .get(&format!(
                "https://price.jup.ag/v6/price?ids={}&vsToken=SOL",
                token_address
            ))
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;

        price_response["data"][token_address]["price"]
            .as_f64()
            .ok_or_else(|| anyhow!("Jupiter price not found"))
    }

    async fn get_helius_price(&self, token_address: &str) -> Result<f64> {
        let price_response = self
            .http_client
            .get(&format!(
                "{}/token/{}",
                self.config.rpc.fallback_url, token_address
            ))
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;

        price_response["price"]
            .as_f64()
            .ok_or_else(|| anyhow!("Helius price not found"))
    }
    async fn extract_token_info(&self, ws_message: &str) -> Option<(String, bool, bool, bool, u64)> {
        let parsed = match serde_json::from_str::<serde_json::Value>(ws_message) {
            Ok(v) => v,
            Err(_) => return None,
        };
        // Add implementation details here
        None
    }

    async fn process_new_token(&self, token_address: &str, supply: u64, mutable: bool, burnt: bool, frozen: bool) -> Result<()> {
        if !self.can_take_new_trade().await {
            return Ok(());
        }
        // Add implementation details here
        Ok(())
    }

    async fn process_trades(&self) -> Result<()> {
        let trades = self.active_trades.lock().unwrap();
        // Add implementation details here
        Ok(())
    }

    async fn is_new_token(&self, token_address: &str) -> Result<bool> {
        let pubkey = token_address
            .parse::<Pubkey>()
            .map_err(|_| anyhow!("Invalid token address"))?;

        let _token_info = self
            .rpc_client
            .get_token_supply(&pubkey)
            .map_err(|e| anyhow!("Failed to get token supply: {}", e))?;

        let creation_info = self
            .rpc_client
            .get_token_largest_accounts(&pubkey)
            .map_err(|e| anyhow!("Failed to get token accounts: {}", e))?;

        if let Some(first_holder) = creation_info.iter().next() {
            let holder_pubkey = Pubkey::from_str(&first_holder.address.to_string())?;
            let tx_history = self
                .rpc_client
                .get_signatures_for_address(&holder_pubkey)
                .map_err(|e| anyhow!("Failed to get signatures: {}", e))?;

            if let Some(first_tx) = tx_history.first() {
                let current_time = chrono::Utc::now().timestamp() as i64;
                return Ok(first_tx.block_time.unwrap_or(0) > current_time - 10);
            }
        }
        Ok(false)
    }

    async fn track_single_trade(&self, token_address: &str, trade: &Trade) -> Result<bool> {
        let current_price = self.get_token_price(token_address).await?;
        let profit_percent = ((current_price - trade.buy_price) / trade.buy_price * 100.0).round();

        let status = if profit_percent >= 0.0 {
            format!("📈 +{}%", profit_percent).green()
        } else {
            format!("📉 {}%", profit_percent).red()
        };

        println!(
            "{}",
            format!("💰 Token: {} | {}", token_address, status).yellow()
        );

        // Check take profit (30%)
        if profit_percent >= self.config.trading.profit_target_percent {
            self.execute_sell(token_address, trade.initial_buy_amount, false)
                .await?;
            return Ok(true);
        }

        // Check stop loss (-7%)
        if profit_percent <= -self.config.trading.stop_loss_percent {
            self.execute_sell(token_address, trade.initial_buy_amount, true)
                .await?;
            return Ok(true);
        }

        Ok(false)
    }
    async fn execute_buy(&self, token_address: &str) -> Result<(u64, f64)> {
        println!("{}", "🎯 EXECUTING BUY".bright_green().bold());

        let priority_fee = self.get_priority_fee(token_address).await?;
        debug!("⚡ Buy Priority Fee: {}", priority_fee);

        let jupiter_quote_url = format!(
            "https://quote-api.jup.ag/v6/quote?inputMint={}&outputMint={}&amount={}&slippageBps={}",
            WSOL_MINT,
            token_address,
            self.config.snipe_amount,
            (self.config.max_slippage * 100.0) as u64
        );

        let quote_response = self.http_client.get(&jupiter_quote_url).send().await?;

        let quote: serde_json::Value = quote_response.json().await?;

        let swap_request = json!({
            "quoteResponse": quote,
            "userPublicKey": self.keypair.pubkey().to_string(),
            "wrapUnwrapSOL": true,
            "computeUnitPriceMicroLamports": priority_fee,
            "asLegacyTransaction": true
        });

        let swap_response: serde_json::Value = self
            .http_client
            .post("https://quote-api.jup.ag/v6/swap")
            .json(&swap_request)
            .send()
            .await?
            .json()
            .await?;

        let swap_transaction = swap_response["swapTransaction"]
            .as_str()
            .ok_or_else(|| anyhow!("Buy transaction not found in response"))?;

        let decoded_transaction = base64_engine.decode(swap_transaction)?;
        let mut transaction: Transaction = bincode::deserialize(&decoded_transaction)?;

        let final_instructions: Vec<Instruction> = transaction
            .message
            .instructions
            .iter()
            .map(|ix| Instruction {
                program_id: transaction.message.account_keys[ix.program_id_index as usize],
                accounts: ix
                    .accounts
                    .iter()
                    .map(|&idx| {
                        let is_signer = transaction.message.header.num_required_signatures as usize
                            > idx as usize;
                        let is_writable = transaction.message.is_writable(idx as usize);
                        AccountMeta {
                            pubkey: transaction.message.account_keys[idx as usize],
                            is_signer,
                            is_writable,
                        }
                    })
                    .collect(),
                data: ix.data.clone(),
            })
            .collect();

        let blockhash = match self.rpc_client.get_latest_blockhash() {
            Ok(hash) => hash,
            Err(_) => self.fallback_rpc.get_latest_blockhash()?,
        };

        let message = Message::new(&final_instructions, Some(&self.keypair.pubkey()));
        transaction = Transaction::new(&[&self.keypair], message, blockhash);

        println!("{}", "🚀 Sending buy transaction...".bright_yellow());

        let signature = match self
            .rpc_client
            .send_and_confirm_transaction_with_spinner(&transaction)
        {
            Ok(sig) => sig,
            Err(_) => {
                println!("{}", "⚠️ Primary RPC failed, using fallback...".yellow());
                self.fallback_rpc
                    .send_and_confirm_transaction_with_spinner(&transaction)?
            }
        };

        println!(
            "{}",
            format!("✅ Buy transaction confirmed: {}", signature).bright_green()
        );

        let entry_price = self.get_token_price(token_address).await?;
        let bought_amount = self.config.snipe_amount;

        Ok((bought_amount, entry_price))
    }

    async fn execute_sell(
        &self,
        token_address: &str,
        initial_amount: u64,
        is_stop_loss: bool,
    ) -> Result<()> {
        println!(
            "{}",
            if is_stop_loss {
                "🛑 EXECUTING STOP LOSS".bright_red().bold()
            } else {
                "🎯 EXECUTING TAKE PROFIT".bright_green().bold()
            }
        );

        let priority_fee = self.get_priority_fee(token_address).await?;
        debug!("⚡ Sell Priority Fee: {}", priority_fee);

        let accounts = self.rpc_client.get_token_accounts_by_owner(
            &self.keypair.pubkey(),
            TokenAccountsFilter::Mint(token_address.parse()?),
        )?;

        let token_account = accounts
            .iter()
            .next()
            .ok_or_else(|| anyhow!("No token account found"))?;

        let pubkey = Pubkey::from_str(&token_account.pubkey)?;
        let token_balance =
            self.rpc_client
                .get_token_account_balance(&pubkey)?
                .ui_amount
                .ok_or_else(|| anyhow!("Failed to get token balance"))? as u64;

        let sell_amount = token_balance.min(initial_amount);
        println!(
            "{}",
            format!("💰 Selling amount: {} tokens", sell_amount).yellow()
        );

        let jupiter_quote_url = format!(
            "https://quote-api.jup.ag/v6/quote?inputMint={}&outputMint={}&amount={}&slippageBps={}",
            token_address,
            WSOL_MINT,
            sell_amount,
            (self.config.max_slippage * 100.0) as u64
        );

        let quote_response = self.http_client.get(&jupiter_quote_url).send().await?;

        let quote: serde_json::Value = quote_response.json().await?;

        let swap_request = json!({
            "quoteResponse": quote,
            "userPublicKey": self.keypair.pubkey().to_string(),
            "wrapUnwrapSOL": true,
            "computeUnitPriceMicroLamports": priority_fee,
            "asLegacyTransaction": true
        });

        let swap_response: serde_json::Value = self
            .http_client
            .post("https://quote-api.jup.ag/v6/swap")
            .json(&swap_request)
            .send()
            .await?
            .json()
            .await?;

        let swap_transaction = swap_response["swapTransaction"]
            .as_str()
            .ok_or_else(|| anyhow!("Sell transaction not found in response"))?;

        let decoded_transaction = base64_engine.decode(swap_transaction)?;
        let mut transaction: Transaction = bincode::deserialize(&decoded_transaction)?;

        let final_instructions: Vec<Instruction> = transaction
            .message
            .instructions
            .iter()
            .map(|ix| Instruction {
                program_id: transaction.message.account_keys[ix.program_id_index as usize],
                accounts: ix
                    .accounts
                    .iter()
                    .map(|&idx| {
                        let is_signer = transaction.message.header.num_required_signatures as usize
                            > idx as usize;
                        let is_writable = transaction.message.is_writable(idx as usize);
                        AccountMeta {
                            pubkey: transaction.message.account_keys[idx as usize],
                            is_signer,
                            is_writable,
                        }
                    })
                    .collect(),
                data: ix.data.clone(),
            })
            .collect();

        let blockhash = match self.rpc_client.get_latest_blockhash() {
            Ok(hash) => hash,
            Err(_) => self.fallback_rpc.get_latest_blockhash()?,
        };

        let message = Message::new(&final_instructions, Some(&self.keypair.pubkey()));
        transaction = Transaction::new(&[&self.keypair], message, blockhash);

        println!("{}", "🚀 Processing sell...".bright_yellow());

        let signature = match self
            .rpc_client
            .send_and_confirm_transaction_with_spinner(&transaction)
        {
            Ok(sig) => sig,
            Err(_) => {
                println!("{}", "⚠️ Primary RPC failed, using fallback...".yellow());
                self.fallback_rpc
                    .send_and_confirm_transaction_with_spinner(&transaction)?
            }
        };

        println!(
            "{}",
            format!("✅ Sell transaction confirmed: {}", signature).bright_green()
        );

        let mut trades = self.active_trades.lock().unwrap();
        trades.remove(token_address);
        println!(
            "{}",
            format!("📊 Active trades remaining: {}", trades.len()).blue()
        );

        Ok(())
    }

    async fn run(&self) -> Result<()> {
        println!("{}", "\n🎯 SNIPER ACTIVATED".bright_green().bold());
        println!("{}", "🔥 MARGA FAST MAINNET + HELIUS PRO".bright_yellow());

        self.load_state().await?;

        let save_interval = interval(Duration::from_secs(30));
        let bot_clone = Arc::new(Bot::clone(self));

        tokio::spawn(async move {
            let mut interval = save_interval;
            loop {
                interval.tick().await;
                if let Err(e) = bot_clone.save_state().await {
                    warn!("Failed to auto-save state: {}", e);
                }
            }
        });

        let ws_url = url::Url::parse(&self.config.ws_url)?;
        let mut retry_count = 0;
        let max_retries = 5;

        while retry_count < max_retries {
            match connect_async(&ws_url).await {
                Ok((ws_stream, _)) => {
                    retry_count = 0;
                    let (mut write, mut read) = ws_stream.split();

                    let subscribe_msg = json!({
                        "jsonrpc": "2.0",
                        "id": 1,
                        "method": "programSubscribe",
                        "params": [
                            RAYDIUM_AMM_PROGRAM_ID,
                            {"encoding": "jsonParsed", "commitment": "confirmed"}
                        ]
                    });

                    write
                        .send(WsMessage::Text(subscribe_msg.to_string()))
                        .await?;
                    println!("{}", "👀 Scanning for new tokens...".bright_blue());

                    let mut interval = interval(Duration::from_secs(1));

                    loop {
                        tokio::select! {
                            Some(msg) = read.next() => {
                                match msg {
                                    Ok(WsMessage::Text(text)) => {
                                        if let Some((token_address, mutable, burnt, frozen, supply)) =
                                            self.extract_token_info(&text).await
                                        {
                                            self.process_new_token(&token_address, supply, mutable, burnt, frozen).await?;
                                        }
                                    }
                                    Ok(WsMessage::Close(_)) => {
                                        println!("{}", "📡 WebSocket connection closed".bright_yellow());
                                        break;
                                    }
                                    Err(e) => {
                                        println!("{}", format!("⚠️ WebSocket error: {}", e).bright_red());
                                        break;
                                    }
                                    _ => {}
                                }
                            }
                            _ = interval.tick() => {
                                if !self.active_trades.lock().unwrap().is_empty() {
                                    self.process_trades().await?;
                                }
                            }
                        }
                    }
                }
                Err(e) => {
                    retry_count += 1;
                    println!(
                        "{}",
                        format!(
                            "🔄 Connection error (attempt {}/{}): {}. Retrying...",
                            retry_count, max_retries, e
                        )
                        .bright_yellow()
                    );
                    tokio::time::sleep(Duration::from_secs(self.config.reconnect_interval)).await;
                }
            }
        }

        Err(anyhow!("Max WebSocket reconnection attempts reached"))
    }

    async fn save_state(&self) -> Result<()> {
        let trades = self.active_trades.lock().unwrap();
        let state = SavedState {
            active_trades: trades.clone(),
            last_update: chrono::Utc::now().timestamp(),
        };

        let state_json = serde_json::to_string_pretty(&state)?;
        tokio::fs::write("bot_state.json", state_json).await?;
        println!("{}", "💾 State saved successfully".green());
        Ok(())
    }

    async fn load_state(&self) -> Result<()> {
        if let Ok(state_data) = tokio::fs::read_to_string("bot_state.json").await {
            let saved_state: SavedState = serde_json::from_str(&state_data)?;
            let mut trades = self.active_trades.lock().unwrap();
            *trades = saved_state.active_trades;
            println!(
                "{}",
                format!("📂 Loaded {} active trades from saved state", trades.len()).green()
            );
        }
        Ok(())
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    let bot = Bot::new().await?;

    let token_address = "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263";

    println!("{}", "🧪 STARTING TRADE TEST".bright_green());
    println!("Testing with BONK token");

    let (amount, _price) = bot.execute_buy(token_address).await?;
    tokio::time::sleep(Duration::from_secs(5)).await;
    bot.execute_sell(token_address, amount, false).await?;

    println!("{}", "✅ TEST COMPLETE".bright_green());
    Ok(())
}
 the whole thing im going blind i need all the functions to work please