use anyhow::{anyhow, Result};
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use colored::*;
use dashmap::DashMap;
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
    pubkey::Pubkey,
    signature::{Keypair, Signer},
    system_instruction,
    transaction::Transaction,
};
use spl_associated_token_account::get_associated_token_address;
use spl_token::instruction as token_instruction;
use std::{
    sync::Arc,
    time::{Duration, SystemTime, UNIX_EPOCH},
};
use tokio::sync::broadcast;
use tracing::{debug, error, info, warn};
use uuid::Uuid;

const WSOL_MINT: &str = "So11111111111111111111111111111111111111112";

#[derive(Debug, Deserialize, Clone)]
pub struct BotConfig {
    pub rpc_url: String,
    pub ws_endpoint: String,
    pub helius_api_key: String,
    pub keypair_path: String,
    pub wsol_account: String,
    #[serde(default = "default_snipe_amount")]
    pub snipe_amount: f64,
    #[serde(default = "default_max_slippage")]
    pub max_slippage: f64,
    #[serde(default = "default_priority_fee")]
    pub priority_fee: u64,
    #[serde(default = "default_min_sol_balance")]
    pub min_sol_balance: f64,
    #[serde(default = "default_min_wsol_balance")]
    pub min_wsol_balance: f64,
    #[serde(default = "default_profit_target")]
    pub profit_target_percent: f64,
    #[serde(default = "default_stop_loss")]
    pub stop_loss_percent: f64,
    #[serde(default = "default_min_supply")]
    pub min_supply: u64,
    #[serde(default = "default_max_age")]
    pub max_age_seconds: u64,
    #[serde(default)]
    pub mutable: bool,
    #[serde(default = "default_true")]
    pub burnt: bool,
    #[serde(default)]
    pub frozen: bool,
}

fn default_true() -> bool { true }
fn default_snipe_amount() -> f64 { 0.01 }
fn default_max_slippage() -> f64 { 15.0 }
fn default_priority_fee() -> u64 { 5000 }
fn default_min_sol_balance() -> f64 { 0.05 }
fn default_min_wsol_balance() -> f64 { 0.1 }
fn default_profit_target() -> f64 { 10.0 }
fn default_stop_loss() -> f64 { 5.0 }
fn default_min_supply() -> u64 { 900_000_000 }
fn default_max_age() -> u64 { 30 }

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Trade {
    id: String,
    token_address: String,
    token_mint: String,
    token_account: String,
    amount: u64,
    buy_price: f64,
    take_profit_price: f64,
    stop_loss_price: f64,
    timestamp: DateTime<Utc>,
    status: TradeStatus,
}

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

struct Bot {
    config: BotConfig,
    rpc_client: Arc<RpcClient>,
    http_client: reqwest::Client,
    keypair: Arc<Keypair>,
    wsol_account: Pubkey,
    active_trades: Arc<DashMap<String, Trade>>,
    trade_updates: broadcast::Sender<Trade>,
    shutdown: Arc<RwLock<bool>>,
}


impl Bot {
    pub async fn new(config_path: &str) -> Result<Self> {
        let settings = config::Config::builder()
            .add_source(config::File::with_name(config_path))
            .build()?;
        
        let mut config: BotConfig = settings.try_deserialize()?;

        // Validate and construct URLs
        if !config.ws_endpoint.contains("api-key") {
            config.ws_endpoint = format!("{}/?api-key={}", config.ws_endpoint, config.helius_api_key);
        }
        if !config.rpc_url.contains("api-key") {
            config.rpc_url = format!("{}/?api-key={}", config.rpc_url, config.helius_api_key);
        }

        // Initialize clients with timeouts and retries
        let rpc_client = Arc::new(RpcClient::new_with_timeout_and_commitment(
            config.rpc_url.clone(),
            Duration::from_secs(30),
            solana_sdk::commitment_config::CommitmentConfig::confirmed(),
        ));

        let http_client = reqwest::Client::builder()
            .timeout(Duration::from_secs(30))
            .pool_max_idle_per_host(0)
            .build()?;

        // Load keypair
        let keypair_bytes: Vec<u8> = serde_json::from_str(&std::fs::read_to_string(&config.keypair_path)?)?;
        let keypair = Arc::new(Keypair::from_bytes(&keypair_bytes)?);

        let wsol_account = Pubkey::from_str(&config.wsol_account)?;
        let (tx, _) = broadcast::channel(100);

        Ok(Self {
            config,
            rpc_client,
            http_client,
            keypair,
            wsol_account,
            active_trades: Arc::new(DashMap::new()),
            trade_updates: tx,
            shutdown: Arc::new(RwLock::new(false)),
        })
    }

    async fn handle_pool_event(&self, event: serde_json::Value) -> Result<()> {
        if let Some(params) = event.get("params") {
            if let (Some(token_address), Some(pool_address)) = (
                params.get("token_address").and_then(|v| v.as_str()),
                params.get("pool_address").and_then(|v| v.as_str()),
            ) {
                info!("{} New pool detected - Token: {}, Pool: {}", 
                    "🔍".blue(), token_address.yellow(), pool_address.yellow());

                if self.is_valid_pool(token_address).await? {
                    info!("{} Valid pool found, executing trade...", "✅".green());
                    self.execute_trade(token_address).await?;
                } else {
                    debug!("{} Pool validation failed for token: {}", "❌".red(), token_address);
                }
            }
        }
        Ok(())
    }

    async fn is_valid_pool(&self, token_address: &str) -> Result<bool> {
        let url = format!(
            "https://api.helius.xyz/v0/tokens/getAsset?api-key={}",
            self.config.helius_api_key
        );

        let response = self
            .http_client
            .post(&url)
            .json(&serde_json::json!({ "id": token_address }))
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;

        if let Some(result) = response.get("result") {
            let validation_result = self.validate_token_data(result)?;
            
            if validation_result {
                info!("{} Token validation passed for {}", "✅".green(), token_address);
            } else {
                debug!("{} Token validation failed for {}", "❌".red(), token_address);
            }

            Ok(validation_result)
        } else {
            Err(anyhow!("Failed to get asset information"))
        }
    }

    fn validate_token_data(&self, token_data: &serde_json::Value) -> Result<bool> {
        let mutable = token_data.get("mutable").and_then(|v| v.as_bool()).unwrap_or(true);
        let burnt = token_data.get("burnt").and_then(|v| v.as_bool()).unwrap_or(false);
        let frozen = token_data.get("frozen").and_then(|v| v.as_bool()).unwrap_or(false);
        let supply = token_data
            .get("supply")
            .and_then(|v| v.as_str())
            .and_then(|s| s.parse::<u64>().ok())
            .unwrap_or(0);
        let created_at = token_data
            .get("created_at")
            .and_then(|v| v.as_i64())
            .unwrap_or(0);

        let is_raydium = token_data
            .get("grouping")
            .and_then(|g| g.as_array())
            .map(|arr| {
                arr.iter().any(|item| {
                    item.get("group_key").and_then(|k| k.as_str()) == Some("dex")
                        && item.get("group_value").and_then(|v| v.as_str()) == Some("raydium")
                })
            })
            .unwrap_or(false);

        let age = SystemTime::now()
            .duration_since(UNIX_EPOCH)?
            .as_secs() as i64
            - created_at;

        Ok(
            mutable == self.config.mutable
            && burnt == self.config.burnt
            && frozen == self.config.frozen
            && supply >= self.config.min_supply
            && age <= self.config.max_age_seconds as i64
            && is_raydium
        )
    }

    async fn execute_trade(&self, token_mint: &str) -> Result<()> {
        info!("{} Executing trade for token: {}", "💫".cyan(), token_mint.yellow());
            
        let url = format!(
            "https://api.helius.xyz/v0/tokens/swap?api-key={}",
            self.config.helius_api_key
        );
    
        let amount_lamports = (self.config.snipe_amount * 1e9) as u64;
        let new_token_account = get_associated_token_address(
            &self.keypair.pubkey(),
            &Pubkey::from_str(token_mint)?,
        );
    
        let swap_params = serde_json::json!({
            "fromToken": WSOL_MINT,
            "fromTokenAccount": self.wsol_account.to_string(),
            "toToken": token_mint,
            "toTokenAccount": new_token_account.to_string(),
            "amount": amount_lamports,
            "slippage": self.config.max_slippage,
            "priorityFee": self.config.priority_fee
        });
    
        let response = self
            .http_client
            .post(&url)
            .json(&swap_params)
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;
    
        if let Some(signature) = response.get("signature").and_then(|v| v.as_str()) {
            info!("{} Trade executed. Signature: {}", "✅".green(), signature.cyan());
                
            let current_price = self.get_token_price(token_mint).await?;
            let take_profit_price = current_price * (1.0 + self.config.profit_target_percent / 100.0);
            let stop_loss_price = current_price * (1.0 - self.config.stop_loss_percent / 100.0);
    
            let trade = Trade {
                id: Uuid::new_v4().to_string(),
                token_address: token_mint.to_string(),
                token_mint: token_mint.to_string(),
                token_account: new_token_account.to_string(),
                amount: amount_lamports,
                buy_price: current_price,
                take_profit_price,
                stop_loss_price,
                timestamp: Utc::now(),
                status: TradeStatus::Active,
            };
    
            self.active_trades.insert(trade.id.clone(), trade.clone());
            let _ = self.trade_updates.send(trade);
    
            Ok(())
        } else {
            Err(anyhow!("Failed to execute trade: {:?}", response))
        }
    }
    
    async fn execute_sell(&self, trade: &Trade) -> Result<()> {
        info!("{} Executing sell for token: {}", "💫".cyan(), trade.token_mint.yellow());
            
        let url = format!(
            "https://api.helius.xyz/v0/tokens/swap?api-key={}",
            self.config.helius_api_key
        );
    
        let swap_params = serde_json::json!({
            "fromToken": trade.token_mint,
            "fromTokenAccount": trade.token_account,
            "toToken": WSOL_MINT,
            "toTokenAccount": self.wsol_account.to_string(),
            "amount": trade.amount,
            "slippage": self.config.max_slippage,
            "priorityFee": self.config.priority_fee
        });
    
        let response = self
            .http_client
            .post(&url)
            .json(&swap_params)
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;
    
        if let Some(signature) = response.get("signature").and_then(|v| v.as_str()) {
            info!("{} Sell executed. Signature: {}", "✅".green(), signature.cyan());
            Ok(())
        } else {
            Err(anyhow!("Failed to execute sell: {:?}", response))
        }
    }
    
    async fn check_active_trades(&self) -> Result<()> {
        let trades: Vec<Trade> = self.active_trades
            .iter()
            .filter(|entry| entry.value().status == TradeStatus::Active)
            .map(|entry| entry.value().clone())
            .collect();
    
        for trade in trades {
            match self.get_token_price(&trade.token_mint).await {
                Ok(current_price) => {
                    let price_change = ((current_price - trade.buy_price) / trade.buy_price) * 100.0;
                        
                    if current_price >= trade.take_profit_price {
                        info!(
                            "{} Take profit triggered for {} at {}%",
                            "💰".green(),
                            trade.token_mint.yellow(),
                            format!("{:.2}", price_change).green()
                        );
                            
                        if let Err(e) = self.execute_sell(&trade).await {
                            error!("{} Failed to execute take profit sell: {}", "❌".red(), e);
                            continue;
                        }
                        
                        if let Some(mut trade) = self.active_trades.get_mut(&trade.id) {
                            trade.status = TradeStatus::Completed;
                            let _ = self.trade_updates.send(trade.clone());
                        }
                    } else if current_price <= trade.stop_loss_price {
                        info!(
                            "{} Stop loss triggered for {} at {}%",
                            "⚠️".yellow(),
                            trade.token_mint.yellow(),
                            format!("{:.2}", price_change).red()
                        );
                        
                        if let Err(e) = self.execute_sell(&trade).await {
                            error!("{} Failed to execute stop loss sell: {}", "❌".red(), e);
                            continue;
                        }
                        
                        if let Some(mut trade) = self.active_trades.get_mut(&trade.id) {
                            trade.status = TradeStatus::Completed;
                            let _ = self.trade_updates.send(trade.clone());
                        }
                    }
                }
                Err(e) => {
                    warn!("{} Failed to get price for {}: {}", "⚠️".yellow(), trade.token_mint, e);
                }
            }
        }

        Ok(())
    }

    async fn get_token_price(&self, token_mint: &str) -> Result<f64> {
        let url = format!(
            "https://api.helius.xyz/v0/token-metadata?api-key={}",
            self.config.helius_api_key
        );

        let response = self
            .http_client
            .post(&url)
            .json(&serde_json::json!({
                "mintAccounts": [token_mint]
            }))
            .send()
            .await?
            .json::<Vec<serde_json::Value>>()
            .await?;

        if let Some(token_data) = response.first() {
            if let Some(price) = token_data.get("price").and_then(|p| p.as_f64()) {
                Ok(price)
            } else {
                Err(anyhow!("Price not found for token {}", token_mint))
            }
        } else {
            Err(anyhow!("No data found for token {}", token_mint))
        }
    }

    async fn ensure_balances(&self) -> Result<()> {
        let sol_balance = self.rpc_client.get_balance(&self.keypair.pubkey())?;
        let wsol_balance = self
            .rpc_client
            .get_token_account_balance(&self.wsol_account)?;

        let min_sol_lamports = (self.config.min_sol_balance * 1e9) as u64;
        let min_wsol_lamports = (self.config.min_wsol_balance * 1e9) as u64;

        info!(
            "{} Current balances - SOL: {} ◎, WSOL: {} ◎",
            "💰".green(),
            (sol_balance as f64 / 1e9).to_string().cyan(),
            (wsol_balance.amount.parse::<f64>()? / 1e9).to_string().cyan()
        );

        if sol_balance < min_sol_lamports {
            warn!(
                "{} SOL balance too low: {} ◎ (minimum: {} ◎)",
                "⚠️".yellow(),
                (sol_balance as f64 / 1e9).to_string().red(),
                self.config.min_sol_balance.to_string().yellow()
            );
        }

        let wsol_amount = wsol_balance.amount.parse::<u64>()?;
        if wsol_amount < min_wsol_lamports {
        let amount_to_wrap = min_wsol_lamports - wsol_amount;
        if amount_to_wrap > 0 {
                info!(
                    "{} Wrapping {} ◎ to maintain minimum WSOL balance",
                    "💫".cyan(),
                    (amount_to_wrap as f64 / 1e9).to_string().yellow()
                );
                self.wrap_sol(amount_to_wrap).await?;
            }
        }

        Ok(())
    }

    async fn wrap_sol(&self, amount: u64) -> Result<()> {
        let instructions = vec![
            system_instruction::transfer(&self.keypair.pubkey(), &self.wsol_account, amount),
            token_instruction::sync_native(&spl_token::id(), &self.wsol_account)?,
        ];

        let recent_blockhash = self.rpc_client.get_latest_blockhash()?;
        let transaction = Transaction::new_signed_with_payer(
            &instructions,
            Some(&self.keypair.pubkey()),
            &[&self.keypair],
            recent_blockhash,
        );

        let signature = self
            .rpc_client
            .send_and_confirm_transaction_with_spinner(&transaction)?;
        
        info!("{} SOL wrapped successfully. Signature: {}", "✅".green(), signature.cyan());
        Ok(())
    }

    pub async fn run(&self) -> Result<()> {
        info!("{} Starting Raydium Sniper Bot", "🚀".bright_green());
        info!(
            "{} Wallet address: {}",
            "👛".bright_yellow(),
            self.keypair.pubkey().to_string().cyan()
        );

        // Set up Ctrl+C handler
        let shutdown = self.shutdown.clone();
        ctrlc::set_handler(move || {
            *shutdown.write() = true;
            info!("{} Shutting down gracefully...", "🛑".red());
        })?;

        // Initial balance check
        self.ensure_balances().await?;

        // Start price checker in separate task
        let price_checker_bot = self.clone();
        let price_checker_shutdown = self.shutdown.clone();
        tokio::spawn(async move {
            let mut interval = tokio::time::interval(Duration::from_secs(1));
            while !*price_checker_shutdown.read() {
                interval.tick().await;
                if let Err(e) = price_checker_bot.check_active_trades().await {
                    error!("{} Error checking active trades: {}", "❌".red(), e);
                }
            }
        });

        // Main WebSocket connection loop
        while !*self.shutdown.read() {
            info!("{} Connecting to WebSocket: {}", "🔌".bright_yellow(), self.config.ws_endpoint);
            
            match self.connect_and_handle_messages().await {
                Ok(_) => {
                    if *self.shutdown.read() {
                        break;
                    }
                }
                Err(e) => {
                    error!("{} WebSocket error: {}", "❌".red(), e);
                }
            }

            // Reconnection logic with exponential backoff
            if !*self.shutdown.read() {
                for i in 0..5 {
                    let delay = Duration::from_secs(2u64.pow(i));
                    info!("{} Reconnecting in {} seconds...", "⏳".yellow(), delay.as_secs());
                    tokio::time::sleep(delay).await;

                    if *self.shutdown.read() {
                        break;
                    }
                }
            }
        }

        info!("{} Bot shutdown complete", "👋".bright_yellow());
        Ok(())
    }

    async fn connect_and_handle_messages(&self) -> Result<()> {
        let (ws_stream, _) = tokio_tungstenite::connect_async(&self.config.ws_endpoint).await?;
        let (mut write, mut read) = ws_stream.split();

        let subscribe_msg = serde_json::json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": "subscribePoolCreations",
            "params": []
        })
        .to_string();

        write.send(tokio_tungstenite::tungstenite::Message::Text(subscribe_msg)).await?;
        info!("{} Subscribed to pool creations", "📡".bright_green());

        let mut heartbeat = tokio::time::interval(Duration::from_secs(30));

        loop {
            tokio::select! {
                Some(msg) = read.next() => {
                    match msg {
                        Ok(tokio_tungstenite::tungstenite::Message::Text(text)) => {
                            if let Ok(event) = serde_json::from_str::<serde_json::Value>(&text) {
                                if let Err(e) = self.handle_pool_event(event).await {
                                    error!("{} Error handling event: {}", "❌".red(), e);
                                }
                            }
                        }
                        Ok(tokio_tungstenite::tungstenite::Message::Ping(_)) => {
                            if let Err(e) = write.send(tokio_tungstenite::tungstenite::Message::Pong(vec![])).await {
                                error!("{} Failed to send pong: {}", "❌".red(), e);
                                break;
                            }
                        }
                        Ok(tokio_tungstenite::tungstenite::Message::Close(_)) => {
                            info!("{} WebSocket connection closed by server", "🔌".yellow());
                            break;
                        }
                        Err(e) => {
                            warn!("{} WebSocket error: {}", "⚠️".yellow(), e);
                            break;
                        }
                        _ => {}
                    }
                }
                _ = heartbeat.tick() => {
                    if let Err(e) = write.send(tokio_tungstenite::tungstenite::Message::Ping(vec![])).await {
                        error!("{} Failed to send ping: {}", "❌".red(), e);
                        break;
                    }
                    if let Err(e) = self.ensure_balances().await {
                        warn!("{} Failed to check balances: {}", "⚠️".yellow(), e);
                    }
                }
                _ = tokio::time::sleep(Duration::from_secs(1)) => {
                    if *self.shutdown.read() {
                        info!("{} Shutdown signal received, closing WebSocket connection", "🛑".red());
                        break;
                    }
                }
            }
        }

        Ok(())
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize tracing subscriber
    tracing_subscriber::fmt()
        .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()
        .add_directive(tracing::Level::INFO.into()))
        .with_target(false)
        .with_thread_ids(true)
        .with_thread_names(true)
        .with_file(true)
        .with_line_number(true)
        .with_ansi(true)
        .init();

    info!("{} Initializing Raydium Sniper Bot", "🎯".bright_green());

    // Create and run the bot
    let bot = Bot::new("config.toml").await?;
    bot.run().await?;

    Ok(())
}
  Compiling solana_rust_bot v0.1.0 (C:\solana_rust_bot)
warning: unused import: `async_trait::async_trait`
 --> src/main.rs:2:5
  |
2 | use async_trait::async_trait;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

error[E0599]: no function or associated item named `from_str` found for struct `Pubkey` in the current scope
   --> src/main.rs:136:36
    |
136 |         let wsol_account = Pubkey::from_str(&config.wsol_account)?;
    |                                    ^^^^^^^^ function or associated item not found in `Pubkey`        
    |
note: if you're trying to build a new `Pubkey` consider using one of the following associated functions:   
      Pubkey::new
      Pubkey::new_from_array
      Pubkey::new_rand
      Pubkey::new_unique
      and 2 others
   --> C:\Users\Orsen\.cargo\registry\src\index.crates.io-6f17d22bba15001f\solana-program-1.18.26\src\pubkey.rs:179:5
    |
179 |     pub fn new(pubkey_vec: &[u8]) -> Self {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
183 |     pub const fn new_from_array(pubkey_array: [u8; 32]) -> Self {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
189 |     pub fn new_rand() -> Self {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
...
195 |     pub fn new_unique() -> Self {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: items from traits can only be used if the trait is in scope
help: trait `FromStr` which provides `from_str` is implemented but not in scope; perhaps you want to import it
    |
1   + use std::str::FromStr;
    |
help: there is an associated function `from` with a similar name
    |
136 |         let wsol_account = Pubkey::from(&config.wsol_account)?;
    |                                    ~~~~

error[E0599]: no function or associated item named `from_str` found for struct `Pubkey` in the current scope
   --> src/main.rs:252:22
    |
252 |             &Pubkey::from_str(token_mint)?,
    |                      ^^^^^^^^ function or associated item not found in `Pubkey`
    |
note: if you're trying to build a new `Pubkey` consider using one of the following associated functions:   
      Pubkey::new
      Pubkey::new_from_array
      Pubkey::new_rand
      Pubkey::new_unique
      and 2 others
   --> C:\Users\Orsen\.cargo\registry\src\index.crates.io-6f17d22bba15001f\solana-program-1.18.26\src\pubkey.rs:179:5
    |
179 |     pub fn new(pubkey_vec: &[u8]) -> Self {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
183 |     pub const fn new_from_array(pubkey_array: [u8; 32]) -> Self {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
189 |     pub fn new_rand() -> Self {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
...
195 |     pub fn new_unique() -> Self {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: items from traits can only be used if the trait is in scope
help: trait `FromStr` which provides `from_str` is implemented but not in scope; perhaps you want to import it
    |
1   + use std::str::FromStr;
    |
help: there is an associated function `from` with a similar name
    |
252 |             &Pubkey::from(token_mint)?,
    |                      ~~~~

error[E0599]: no method named `cyan` found for struct `solana_sdk::signature::Signature` in the current scope
   --> src/main.rs:482:84
    |
482 |         info!("{} SOL wrapped successfully. Signature: {}", "✅".green(), signature.cyan());
    |                                                                                     ^^^^ method not found in `Signature`

error[E0521]: borrowed data escapes outside of method
   --> src/main.rs:505:33
    |
486 |     pub async fn run(&self) -> Result<()> {
    |                      -----
    |                      |
    |                      `self` is a reference that is only valid in the method body
    |                      let's call the lifetime of this reference `'1`
...
505 |         let price_checker_bot = self.clone();
    |                                 ^^^^^^^^^^^^
    |                                 |
    |                                 `self` escapes the method body here
    |                                 argument requires that `'1` must outlive `'static`

error[E0599]: no method named `split` found for struct `WebSocketStream` in the current scope
    --> src/main.rs:552:47
     |
552  |         let (mut write, mut read) = ws_stream.split();
     |                                               ^^^^^ method not found in `WebSocketStream<MaybeTlsStream<TcpStream>>`
     |
    ::: C:\Users\Orsen\.cargo\registry\src\index.crates.io-6f17d22bba15001f\futures-util-0.3.31\src\stream\stream\mod.rs:1582:8
     |
1582 |     fn split<Item>(self) -> (SplitSink<Self, Item>, SplitStream<Self>)
     |        ----- the method is available for `WebSocketStream<tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>>` here
     |
     = help: items from traits can only be used if the trait is in scope
help: trait `StreamExt` which provides `split` is implemented but not in scope; perhaps you want to import it
     |
1    + use futures_util::stream::stream::StreamExt;
     |

Some errors have detailed explanations: E0521, E0599.
For more information about an error, try `rustc --explain E0521`.
warning: `solana_rust_bot` (bin "solana_rust_bot") generated 1 warning
error: could not compile `solana_rust_bot` (bin "solana_rust_bot") due to 5 previous errors; 1 warning emitted please fix write the entire script for me to copy paste