use config::{Config, File as ConfigFile};
use {
    anyhow::{anyhow, Result},
    colored::*,
    dashmap::DashMap,
    futures_util::{SinkExt, StreamExt},
    log::{debug, error, info, warn},
    serde::{Deserialize, Serialize},
    serde_json::{json, Value},
    solana_client::rpc_client::RpcClient,
    solana_sdk::{
        commitment_config::CommitmentConfig,
        pubkey::Pubkey,
        signature::{Keypair, Signature, Signer},
        account::Account,
    },
    std::{
        str::FromStr,
        sync::Arc,
        time::{Duration, Instant},
    },
    tokio::{
        sync::Mutex,
        time::interval,
    },
    tokio_tungstenite::{
        connect_async,
        tungstenite::protocol::Message as WsMessage,
    },
};

// Constants are properly defined
const RAYDIUM_V4: &str = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
const ORCA_WHIRLPOOL: &str = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc";

// Trade state structure
#[derive(Debug, Clone, Serialize, Deserialize)]
struct TradeState {
    active_trades: Vec<ActiveTrade>,
    last_update: chrono::DateTime<chrono::Utc>,
}

// Config structs follow
#[derive(Debug, Deserialize, Clone)]
struct BotConfig {
    rpc: RpcConfig,
    wallet: WalletConfig,
    trading: TradingConfig,
    token: TokenRequirements,
    websocket: WebsocketConfig,
    logging: LoggingConfig,
}

#[derive(Debug, Deserialize, Clone)]
struct RpcConfig {
    solana_rpc_url: String,
    fallback_url: String,
    ws_url: String,
    api_key: String,
}

#[derive(Debug, Deserialize, Clone)]
struct WalletConfig {
    keypair_path: String,
    public_key: String,
}

#[derive(Debug, Deserialize, Clone)]
struct TradingConfig {
    snipe_amount: u64,
    max_slippage: f64,
    priority_fee: u64,
    profit_target_percent: f64,
    stop_loss_percent: f64,
    max_concurrent_trades: usize,
    min_liquidity: u64,
}

#[derive(Debug, Deserialize, Clone)]
struct TokenRequirements {
    min_supply: u64,
    mutable: bool,
    burnt: bool,
    frozen: bool,
}

#[derive(Debug, Deserialize, Clone)]
struct WebsocketConfig {
    reconnect_interval: u64,
    heartbeat_interval: u64,
}

#[derive(Debug, Deserialize, Clone)]
struct LoggingConfig {
    show_balances: bool,
    debug_mode: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct ActiveTrade {
    token_mint: String,
    entry_price: f64,
    amount: u64,
    start_time: chrono::DateTime<chrono::Utc>,
    last_price: f64,
    buy_attempts: u8,
    sell_attempts: u8,
}

struct Bot {
    config: BotConfig,
    rpc_client: Arc<RpcClient>,
    fallback_rpc: Arc<RpcClient>,
    keypair: Arc<Keypair>,
    active_trades: Arc<DashMap<String, ActiveTrade>>,
    http_client: reqwest::Client,
}

impl Bot {
    async fn new() -> Result<Self> {
        println!("{}", "\n🚀 INITIALIZING SOLANA SNIPER BOT v2.0".bright_green().bold());

        // Load configuration
        let settings = Config::builder()
            .add_source(ConfigFile::with_name("config.toml"))
            .build()
            .map_err(|e| anyhow!("Failed to load config: {}", e))?;

        let config: BotConfig = settings.try_deserialize()
            .map_err(|e| anyhow!("Failed to parse config: {}", e))?;

        // Initialize RPC clients
        let rpc_client = Arc::new(RpcClient::new_with_commitment(
            config.rpc.solana_rpc_url.clone(),
            CommitmentConfig::confirmed(),
        ));

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

        // Load and parse keypair directly from JSON array
        let keypair_bytes: Vec<u8> = serde_json::from_reader(
            std::fs::File::open(&config.wallet.keypair_path)?
        )?;

        let keypair = Arc::new(Keypair::from_bytes(&keypair_bytes)
            .map_err(|e| anyhow!("Failed to create keypair: {}", e))?);

        println!("{}", format!("💰 Loaded wallet: {}", keypair.pubkey()).yellow());

        // Initialize HTTP client
        let http_client = reqwest::Client::builder()
            .timeout(Duration::from_secs(10))
            .pool_idle_timeout(Duration::from_secs(30))
            .build()?;

        Ok(Self {
            config,
            rpc_client,
            fallback_rpc,
            keypair,
            active_trades: Arc::new(DashMap::new()),
            http_client,
        })
    }

    pub fn calculate_pool_liquidity(pool_data: &[(Pubkey, Account)]) -> Result<f64> {
        let mut total_liquidity = 0.0;
        for (_, account) in pool_data {
            let data = &account.data;
            let quote_amount = u64::from_le_bytes(data[16..24].try_into()?);
            let sol_liquidity = quote_amount as f64 / 1e9;
            total_liquidity += sol_liquidity;
        }
        Ok(total_liquidity)
    }

    async fn get_priority_fee(&self, token_mint: &str) -> Result<u64> {
        let priority_response = self.http_client
            .post(&self.config.rpc.solana_rpc_url)
            .header("Authorization", format!("Bearer {}", self.config.rpc.api_key))
            .json(&json!({
                "jsonrpc": "2.0",
                "id": "helius-priority",
                "method": "getPriorityFeeEstimate",
                "params": [{
                    "accountKeys": [token_mint, "So11111111111111111111111111111111111111112"],
                    "options": {
                        "includeAllPriorityFeeLevels": true,
                        "priorityLevel": "HIGH"
                    }
                }]
            }))
            .send()
            .await?
            .json::<Value>()
            .await?;

        let recommended_fee = priority_response["result"]["priorityFeeLamports"]
            .as_u64()
            .unwrap_or(self.config.trading.priority_fee);

        let priority_fee = (recommended_fee.max(self.config.trading.priority_fee) as f64 * 1.2) as u64;

        info!("💰 Using priority fee: {} lamports", priority_fee);
        Ok(priority_fee)
    }

    async fn get_token_price(&self, token_mint: &str) -> Result<f64> {
        let jupiter_price_url = format!(
            "https://price.jup.ag/v6/price?ids={}&vsToken=SOL",
            token_mint
        );

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

        let price = response["data"][token_mint]["price"]
            .as_f64()
            .ok_or_else(|| anyhow!("Price not found"))?;

        Ok(price)
    }

    async fn validate_token(&self, value: &Value) -> Result<bool> {
        let token_info = &value["params"]["result"]["value"]["account"]["data"]["parsed"]["info"];
        let token_mint = value["params"]["result"]["value"]["pubkey"]
            .as_str()
            .ok_or_else(|| anyhow!("Token mint not found"))?;

        let supply = token_info["supply"]
            .as_str()
            .unwrap_or("0")
            .parse::<u64>()
            .map_err(|_| anyhow!("Failed to parse supply"))?;

        let decimals = token_info["decimals"]
            .as_u64()
            .unwrap_or(0);

        let is_frozen = token_info["freezeAuthority"].is_null();
        let is_burnt = token_info["mintAuthority"].is_null();
        let is_mutable = !token_info["mintAuthority"].is_null();

        // Log token details
        info!("Token Analysis for {}", token_mint);
        info!("📊 Raw Supply: {}", supply);
        info!("🔢 Decimals: {}", decimals);
        info!("🔒 Mint Authority Burnt: {}", is_burnt);
        info!("🔑 Mutable: {}", is_mutable);
        info!("❄️ Frozen: {}", is_frozen);

        // Calculate actual supply considering decimals
        let actual_supply = supply as f64 / 10f64.powi(decimals as i32);
        info!("💰 Actual Supply: {}", actual_supply);

        // Validate requirements
        if !is_burnt == self.config.token.burnt {
            self.log_with_config(
                log::Level::Debug,
                &format!("❌ Token rejected: Invalid mint authority status (burnt: {}, required: {})",
                    is_burnt, self.config.token.burnt)
            );
            return Ok(false);
        }

        if is_frozen != self.config.token.frozen {
            self.log_with_config(
                log::Level::Debug,
                &format!("❌ Token rejected: Invalid freeze status (frozen: {}, required: {})",
                    is_frozen, self.config.token.frozen)
            );
            return Ok(false);
        }

        if is_mutable != self.config.token.mutable {
            self.log_with_config(
                log::Level::Debug,
                &format!("❌ Token rejected: Invalid mutability (mutable: {}, required: {})",
                    is_mutable, self.config.token.mutable)
            );
            return Ok(false);
        }

        if actual_supply < self.config.token.min_supply as f64 {
            self.log_with_config(
                log::Level::Debug,
                &format!("❌ Token rejected: Insufficient supply ({} < {})",
                    actual_supply, self.config.token.min_supply)
            );
            return Ok(false);
        }

        // Check trade slot availability
        if self.active_trades.len() >= self.config.trading.max_concurrent_trades {
            self.log_with_config(
                log::Level::Debug,
                &format!("❌ Token rejected: Maximum concurrent trades reached ({}/{})",
                    self.active_trades.len(), self.config.trading.max_concurrent_trades)
            );
            return Ok(false);
        }

        // Check liquidity
        match self.check_liquidity(token_mint).await? {
            Some(liquidity) => {
                info!("💧 Liquidity: {} SOL", liquidity);
                if liquidity < self.config.trading.min_liquidity as f64 {
                    self.log_with_config(
                        log::Level::Debug,
                        &format!("❌ Token rejected: Insufficient liquidity ({} < {} SOL)",
                            liquidity, self.config.trading.min_liquidity)
                    );
                    return Ok(false);
                }
            },
            None => {
                self.log_with_config(
                    log::Level::Debug,
                    "❌ Token rejected: Could not verify liquidity"
                );
                return Ok(false);
            }
        }

        // All validations passed
        info!("✅ Token validated successfully: {}", token_mint);
        Ok(true)
    }

    async fn check_liquidity(&self, token_mint: &str) -> Result<Option<f64>> {
        let jupiter_quote_url = format!(
            "https://quote-api.jup.ag/v6/quote?inputMint={}&outputMint={}&amount={}&slippageBps={}",
            "So11111111111111111111111111111111111111112",
            token_mint,
            self.config.trading.snipe_amount,
            (self.config.trading.max_slippage * 100.0) as u64
        );

        let quote = self.http_client
            .get(&jupiter_quote_url)
            .send()
            .await?
            .json::<Value>()
            .await?;

        if let Some(market_infos) = quote["data"]["marketInfos"].as_array() {
            if let Some(first_market) = market_infos.first() {
                let liquidity = first_market["liquidityInSol"]
                    .as_f64()
                    .unwrap_or(0.0);

                info!("💧 Liquidity: {} SOL", liquidity);
                return Ok(Some(liquidity));
            }
        }

        Ok(None)
    }

    async fn execute_trade(&self, token_mint: &str, is_buy: bool) -> Result<String> {
        let start = Instant::now();

        // Get SOL balance correctly
        let sol_balance = self.rpc_client.get_balance(&self.keypair.pubkey())?;
        if is_buy && sol_balance < self.config.trading.snipe_amount {
            return Err(anyhow!("Insufficient SOL for trade"));
        }

        let priority_fee = self.get_priority_fee(token_mint).await?;

        let (input_mint, output_mint, amount) = if is_buy {
            ("So11111111111111111111111111111111111111112", token_mint, self.config.trading.snipe_amount)
        } else {
            let sell_amount = self.config.trading.snipe_amount.saturating_mul(98) / 100;
            (token_mint, "So11111111111111111111111111111111111111112", sell_amount)
        };

        let quote = match self.get_quote(input_mint, output_mint, amount).await {
            Ok(q) => q,
            Err(e) => {
                info!("🔄 Retrying quote...");
                tokio::time::sleep(Duration::from_millis(200)).await;
                self.get_quote(input_mint, output_mint, amount).await?
            }
        };

        if !quote["data"]["routesInfos"].as_array().map_or(false, |r| !r.is_empty()) {
            return Err(anyhow!("No valid routes found"));
        }

        let swap_data = self.build_swap_transaction(&quote, priority_fee).await?;
        let signature = self.send_priority_transaction(swap_data, priority_fee).await?;

        info!("✨ Trade executed in {:?}", start.elapsed());
        info!("🔗 Signature: {}", signature);

        // Convert string signature to Signature type and confirm
        let sig = Signature::from_str(&signature)?;
        let confirmed = self.rpc_client.confirm_transaction(&sig)?;

        if confirmed {
            info!("✅ Transaction confirmed!");
            Ok(signature)
        } else {
            Err(anyhow!("Transaction failed to confirm"))
        }
    }

    async fn get_quote(&self, input_mint: &str, output_mint: &str, amount: u64) -> Result<Value> {
        let url = format!(
            "https://quote-api.jup.ag/v6/quote?inputMint={}&outputMint={}&amount={}&slippageBps={}&onlyDirectRoutes=true",
            input_mint,
            output_mint,
            amount,
            (self.config.trading.max_slippage * 100.0) as u64
        );

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

        Ok(response)
    }

    async fn build_swap_transaction(&self, quote: &Value, priority_fee: u64) -> Result<String> {
        let swap_request = json!({
            "quoteResponse": quote,
            "userPublicKey": self.config.wallet.public_key,
            "wrapUnwrapSOL": true,
            "computeUnitPriceMicroLamports": priority_fee,
            "priorityFeeLamports": priority_fee,
            "asLegacyTransaction": false,
            "maxAccounts": 64,
            "verifyWallet": true
        });

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

        let swap_transaction = response["swapTransaction"]
            .as_str()
            .ok_or_else(|| anyhow!("Invalid swap response"))?;

        Ok(swap_transaction.to_string())
    }

    async fn send_priority_transaction(&self, transaction_data: String, priority_fee: u64) -> Result<String> {
        // Enhanced Helius Pro priority transaction
        let helius_request = json!({
            "jsonrpc": "2.0",
            "id": "helius-priority",
            "method": "sendTransaction",
            "params": [
                transaction_data,
                {
                    "encoding": "base64",
                    "maxRetries": 3,
                    "skipPreflight": true,
                    "preflightCommitment": "confirmed",
                    "priorityFee": priority_fee,
                    "minContextSlot": "max",
                    "maxAccountLocks": 64
                }
            ]
        });

        let response = self.http_client
            .post(&self.config.rpc.solana_rpc_url)
            .header("Authorization", format!("Bearer {}", self.config.rpc.api_key))
            .json(&helius_request)
            .send()
            .await?
            .json::<Value>()
            .await?;

        match response.get("result") {
            Some(result) => {
                let signature = result.as_str().unwrap_or_default().to_string();
                info!("🚀 Priority TX sent: {}", signature);
                Ok(signature)
            },
            None => {
                if let Some(error) = response.get("error") {
                    Err(anyhow!("TX failed: {:?}", error))
                } else {
                    Err(anyhow!("TX failed without error details"))
                }
            }
        }
    }

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

        // Load previous state
        match self.load_state().await {
            Ok(_) => info!("💾 Previous state loaded successfully"),
            Err(e) => warn!("Failed to load previous state: {}", e),
        }

        // Start state auto-save task
        let state_bot = self.clone();
        tokio::spawn(async move {
            let mut interval = interval(Duration::from_secs(30));
            loop {
                interval.tick().await;
                if let Err(e) = state_bot.save_state().await {
                    error!("Failed to auto-save state: {}", e);
                } else {
                    debug!("💾 State auto-saved successfully");
                }
            }
        });

        let mut retry_count = 0;
        const MAX_RETRIES: u8 = 5;

        // Main WebSocket loop with retry logic
        loop {
            info!("📡 Connecting to WebSocket...");

            match self.clone().connect_and_handle_messages().await {
                Ok(_) => {
                    info!("✅ WebSocket connection successful");
                    retry_count = 0;
                    continue;
                }
                Err(e) => {
                    retry_count += 1;
                    error!("❌ WebSocket error: {}. Attempt {}/{}", e, retry_count, MAX_RETRIES);

                    if retry_count >= MAX_RETRIES {
                        error!("🔄 Maximum retry attempts reached, forcing restart...");

                        // Try to save state before exit
                        if let Err(e) = self.save_state().await {
                            error!("Failed to save state during shutdown: {}", e);
                        }
                        std::process::exit(1); // Process manager will restart
                    }

                    // Wait before retry with exponential backoff
                    let retry_delay = self.config.websocket.reconnect_interval * (retry_count as u64);
                    info!("⏳ Waiting {} seconds before retry...", retry_delay);

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

            // Check if we should save state between retries
            if let Err(e) = self.save_state().await {
                warn!("Failed to save state between retries: {}", e);
            }
        }
    }

    fn log_with_config(&self, level: log::Level, message: &str) {
        if self.config.logging.debug_mode || level != log::Level::Debug {
            log::log!(level, "{}", message);
        }

        if self.config.logging.show_balances && message.contains("Balance") {
            println!("{}", message.bright_yellow());
        }
    }

    async fn connect_and_handle_messages(self: Arc<Self>) -> Result<()> {
        let (ws_stream, _) = connect_async(&url::Url::parse(&self.config.rpc.ws_url)?).await?;
        let (mut write, mut read) = ws_stream.split();

        // Start price monitoring task
        let monitor_bot = self.clone();
        let monitor_handle = tokio::spawn(async move {
            monitor_bot.monitor_active_trades().await;
        });

        // Setup subscription
        let subscribe_msg = json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": "programSubscribe",
            "params": [
                "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                {
                    "encoding": "jsonParsed",
                    "filters": [
                        {
                            "dataSize": 82
                        }
                    ]
                }
            ]
        });

        write.send(WsMessage::Text(subscribe_msg.to_string())).await?;
        info!("👀 Token subscription active");

        // Heartbeat tracking
        let heartbeat_interval = Duration::from_secs(self.config.websocket.heartbeat_interval);
        let last_msg_time = Arc::new(Mutex::new(Instant::now()));
        let last_msg_time_clone = last_msg_time.clone();

        // Start heartbeat monitor
        let heartbeat_handle = tokio::spawn(async move {
            let mut interval = interval(Duration::from_secs(1));
            loop {
                interval.tick().await;
                let elapsed = last_msg_time_clone.lock().await.elapsed();
                if elapsed > heartbeat_interval {
                    error!("💔 WebSocket heartbeat timeout after {:?}", elapsed);
                    break;
                }
            }
        });

        // Main message processing loop
        while let Some(msg_result) = read.next().await {
            *last_msg_time.lock().await = Instant::now();

            match msg_result {
                Ok(msg) => match msg {
                    WsMessage::Text(text) => {
                        if let Err(e) = self.process_ws_message(&text).await {
                            warn!("Message processing error: {}", e);
                        }
                    }
                    WsMessage::Ping(_) => {
                        if let Err(e) = write.send(WsMessage::Pong(vec![])).await {
                            warn!("Failed to respond to ping: {}", e);
                        }
                    }
                    WsMessage::Close(frame) => {
                        info!("WebSocket closed: {:?}", frame);
                        break;
                    }
                    _ => {}
                },
                Err(e) => {
                    error!("WebSocket message error: {}", e);
                    break;
                }
            }
        }

        // Cleanup
        monitor_handle.abort();
        heartbeat_handle.abort();
        Ok(())
    }

    async fn process_ws_message(&self, text: &str) -> Result<()> {
        self.log_with_config(log::Level::Debug, "Processing WebSocket message");

        let value: Value = serde_json::from_str(text)?;

        if let Some((mint, supply, decimals, is_burnt, is_mutable, is_frozen)) =
            self.extract_token_data(&value)
        {
            info!("🎯 New token detected:");
            info!("📍 Mint: {}", mint);
            info!("💰 Supply: {}", supply);
            info!("🔢 Decimals: {}", decimals);
            info!("🔒 Burnt: {}", is_burnt);
            info!("🔑 Mutable: {}", is_mutable);
            info!("❄️ Frozen: {}", is_frozen);

            // Validate token requirements
            if !is_mutable && is_burnt && !is_frozen && 
               supply >= self.config.token.min_supply {
                
                // Check liquidity
                if let Some(liquidity) = self.check_liquidity(&mint).await? {
                    if liquidity >= 5.0 && liquidity <= 50.0 {
                        info!("✅ Token validated! Starting trade sequence...");
                        
                        match self.execute_trade(&mint, true).await {
                            Ok(signature) => {
                                info!("💎 Buy successful! Signature: {}", signature);
                                
                                // Add to active trades
                                let trade = ActiveTrade {
                                    token_mint: mint.clone(),
                                    entry_price: self.get_token_price(&mint).await?,
                                    amount: self.config.trading.snipe_amount,
                                    start_time: chrono::Utc::now(),
                                    last_price: 0.0,
                                    buy_attempts: 1,
                                    sell_attempts: 0,
                                };
                                
                                self.active_trades.insert(mint.clone(), trade);
                            }
                            Err(e) => warn!("Failed to execute buy: {}", e),
                        }
                    } else {
                        debug!("❌ Token rejected: Liquidity outside range ({} SOL)", liquidity);
                    }
                }
            } else {
                debug!("❌ Token rejected: Does not meet requirements");
            }
        }

        Ok(())
    }

    async fn monitor_active_trades(&self) {
        let mut interval = interval(Duration::from_secs(1));
        
        loop {
            interval.tick().await;
            
            for trade in self.active_trades.iter() {
                if let Ok(current_price) = self.get_token_price(&trade.token_mint).await {
                    let profit_percent = 
                        ((current_price - trade.entry_price) / trade.entry_price * 100.0).round();
                    
                    let status = if profit_percent >= 0.0 {
                        format!("📈 +{}%", profit_percent).green()
                    } else {
                        format!("📉 {}%", profit_percent).red()
                    };
                    
                    info!("💰 {}: {}", trade.token_mint, status);
                    
                    // Check take profit
                    if profit_percent >= self.config.trading.profit_target_percent {
                        info!("🎯 Take profit triggered for {}", trade.token_mint);
                        if let Err(e) = self.execute_trade(&trade.token_mint, false).await {
                            warn!("Failed to execute take profit: {}", e);
                        }
                    }
                    // Check stop loss
                    else if profit_percent <= -self.config.trading.stop_loss_percent {
                        warn!("⚠️ Stop loss triggered for {}", trade.token_mint);
                        if let Err(e) = self.execute_trade(&trade.token_mint, false).await {
                            warn!("Failed to execute stop loss: {}", e);
                        }
                    }
                }
            }
        }
    }

    async fn save_state(&self) -> Result<()> {
        let trades = self.active_trades.iter()
            .map(|trade| trade.clone())
            .collect::<Vec<_>>();

        let state = TradeState {
            active_trades: trades,
            last_update: chrono::Utc::now(),
        };

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

    async fn load_state(&self) -> Result<()> {
        if let Ok(content) = tokio::fs::read_to_string("bot_state.json").await {
            let state: TradeState = serde_json::from_str(&content)?;
            
            for trade in state.active_trades {
                self.active_trades.insert(trade.token_mint.clone(), trade);
            }
            
            info!("📂 Loaded {} active trades", self.active_trades.len());
        }
        Ok(())
    }

    fn extract_token_data(&self, value: &Value) -> Option<(String, u64, u8, bool, bool, bool)> {
        let token_info = value
            .pointer("/params/result/value/account/data/parsed/info")?;
        
        let mint = value
            .pointer("/params/result/value/pubkey")?
            .as_str()?
            .to_string();
        
        let supply = token_info["supply"]
            .as_str()?
            .parse::<u64>()
            .ok()?;
        
        let decimals = token_info["decimals"]
            .as_u64()?
            as u8;
        
        let is_burnt = token_info["mintAuthority"].is_null();
        let is_mutable = !token_info["mintAuthority"].is_null();
        let is_frozen = token_info["freezeAuthority"].is_null();

        Some((mint, supply, decimals, is_burnt, is_mutable, is_frozen))
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    // Load environment variables
    dotenv::dotenv().ok();

    // Initialize logging
    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info"))
        .format(|buf, record| {
            use chrono::Local;
            use std::io::Write;
            writeln!(
                buf,
                "{} [{}] {}",
                Local::now().format("%Y-%m-%d %H:%M:%S"),
                record.level(),
                record.args()
            )
        })
        .init();

    println!("{}", "=====================================".bright_blue());
    println!("{}", "🔫 SOLANA SNIPER ELITE v2.0 🎯".bright_green().bold());
    println!("{}", "=====================================".bright_blue());
    println!("{}", "Starting with Marga Fast + Helius Pro...".bright_yellow());

    // Initialize bot with error handling
    let bot = match Bot::new().await {
        Ok(b) => Arc::new(b),
        Err(e) => {
            error!("Failed to initialize bot: {}", e);
            std::process::exit(1);
        }
    };

    // Check SOL balance
    if bot.config.logging.show_balances {
        match bot.rpc_client.get_balance(&bot.keypair.pubkey()) {
            Ok(balance) => {
                println!("{}", format!("💰 SOL Balance: {} SOL", balance as f64 / 1e9).bright_yellow());
            }
            Err(e) => warn!("Failed to fetch SOL balance: {}", e),
        }
    }

    // Set up graceful shutdown
    let shutdown_bot = bot.clone();
    if let Err(e) = ctrlc::set_handler(move || {
        let shutdown_clone = shutdown_bot.clone();
        tokio::runtime::Runtime::new().unwrap().block_on(async move {
            println!("{}", "\n💾 SAVING STATE & SHUTTING DOWN...".bright_red().bold());
            if let Err(e) = shutdown_clone.save_state().await {
                error!("Failed to save state during shutdown: {}", e);
            }
            println!("✅ State saved, shutting down gracefully...");
            std::process::exit(0);
        });
    }) {
        error!("Failed to set Ctrl-C handler: {}", e);
    }

    // Load previous state
    if let Err(e) = bot.load_state().await {
        warn!("Failed to load previous state: {}", e);
    }

    // Start automatic state saving
    let state_bot = bot.clone();
    tokio::spawn(async move {
        let mut interval = interval(Duration::from_secs(30));
        loop {
            interval.tick().await;
            if let Err(e) = state_bot.save_state().await {
                error!("Failed to auto-save state: {}", e);
            }
        }
    });

    let mut consecutive_errors = 0;
    const MAX_CONSECUTIVE_ERRORS: u32 = 3;

    // Main bot loop with error handling and automatic restart
    loop {
        info!("🚀 Starting bot cycle...");

        match bot.clone().run().await {
            Ok(_) => {
                info!("✅ Bot cycle completed successfully");
                consecutive_errors = 0;
            }
            Err(e) => {
                error!("❌ Bot error: {}", e);
                consecutive_errors += 1;

                if consecutive_errors >= MAX_CONSECUTIVE_ERRORS {
                    error!("🔄 Too many consecutive errors, restarting bot...");
                    // Save state before restart
                    if let Err(e) = bot.save_state().await {
                        error!("Failed to save state before restart: {}", e);
                    }
                    std::process::exit(1); // Process manager should restart the bot
                }

                info!("⏳ Waiting 5 seconds before retry...");
                tokio::time::sleep(Duration::from_secs(5)).await;
            }
        }

        // Short delay between cycles
        tokio::time::sleep(Duration::from_secs(1)).await;
    }
}Sure, I'd be happy to help you troubleshoot your Rust script for buying and selling operations. Let's go through the script step-by-step to identify potential issues and areas that might prevent the buy and sell functionalities from executing as expected.
1. Logging and Monitoring

Issue:

    Logging Levels: Ensure that the logging levels are appropriately set to capture all necessary information. If debug_mode is not enabled, certain logs might be suppressed, making it harder to identify issues.
    Log Outputs: Verify that logs are being generated and monitored correctly. Missing or insufficient logs can obscure the root cause of the problem.

Solution:

    Enable Debug Mode: Make sure debug_mode is set to true in your LoggingConfig to capture detailed logs.
    Check Log Files/Streams: Ensure that your logging setup in the main function is correctly outputting logs to your desired destination (console, file, etc.).

#[derive(Debug, Deserialize, Clone)]
struct LoggingConfig {
    show_balances: bool,
    debug_mode: bool, // Ensure this is set to true
}

2. Configuration Validation

Issue:

    Configuration Parameters: Incorrect or missing configuration parameters can prevent the bot from functioning correctly. Parameters like solana_rpc_url, keypair_path, and trading thresholds are critical.
    Keypair Loading: Ensure that the keypair is loaded correctly from the specified path and that it has sufficient permissions and balance to execute trades.

Solution:

    Verify config.toml: Double-check all configuration values in your config.toml to ensure they are correct.
    Keypair Permissions: Ensure that the keypair file is accessible and correctly formatted. Verify that the wallet has enough SOL to perform buy and sell operations.

3. Token Validation Logic

Issue:

    Validation Conditions: The validate_token function contains several validation checks. Any mismatch between token properties and configuration requirements can prevent trades from executing.
    Logical Errors: The condition if !is_burnt == self.config.token.burnt might not behave as intended. It is better to use != for clarity.

Solution:

    Correct Logical Conditions: Update the condition to use != for better readability and correctness.

// Original
if !is_burnt == self.config.token.burnt {

// Updated
if is_burnt != self.config.token.burnt {

    Ensure Validation Criteria: Make sure that your tokens meet all the criteria defined in TokenRequirements. For example, check if the token's supply, mutability, burned, and frozen status align with your configuration.

4. Liquidity Checks

Issue:

    Liquidity Range: In process_ws_message, there's a check for liquidity between 5.0 and 50.0 SOL. If no tokens fall within this range, no trades will execute.
    Inconsistent Thresholds: Ensure that the liquidity checks in different parts of the code (e.g., validate_token vs. process_ws_message) are consistent with each other.

Solution:

    Adjust Liquidity Range: Consider adjusting the liquidity range to include more tokens, or ensure that the tokens you intend to trade fall within the specified range.

// In process_ws_message
if liquidity >= 5.0 && liquidity <= 50.0 {
    // Proceed with trade
}

    Align Configuration: Make sure that min_liquidity in your configuration matches the checks in the code.

struct TradingConfig {
    // ...
    min_liquidity: u64, // Ensure this aligns with liquidity checks
    // ...
}

5. WebSocket Connection and Message Handling

Issue:

    Subscription Success: Ensure that the WebSocket subscription to token updates is successful. If the subscription fails, the bot won't receive token data to process.
    Heartbeat Mechanism: The heartbeat monitor checks for message timeouts. If messages aren't received within the heartbeat_interval, the connection might drop or malfunction.

Solution:

    Verify WebSocket Connection: Check the logs to confirm that the WebSocket connection is established and that subscription messages are sent and acknowledged.
    Monitor Heartbeat Logs: Ensure that the heartbeat monitor isn't prematurely terminating the connection due to perceived inactivity.

6. Trade Execution Flow

Issue:

    execute_trade Function: This function handles both buy and sell operations. Any errors in obtaining quotes, building transactions, or sending transactions can prevent trades from executing.
    Error Handling: Errors during trade execution might not be adequately handled or could be causing silent failures.

Solution:

    Enhance Error Logging: Add more detailed error logs within the execute_trade function to capture specific failure points.

async fn execute_trade(&self, token_mint: &str, is_buy: bool) -> Result<String> {
    // ...
    let quote = match self.get_quote(input_mint, output_mint, amount).await {
        Ok(q) => q,
        Err(e) => {
            info!("🔄 Retrying quote...");
            tokio::time::sleep(Duration::from_millis(200)).await;
            self.get_quote(input_mint, output_mint, amount).await?
        }
    };

    if !quote["data"]["routesInfos"].as_array().map_or(false, |r| !r.is_empty()) {
        return Err(anyhow!("No valid routes found"));
    }

    // ...
}

    Inspect Transaction Responses: Ensure that the responses from transaction submissions (send_priority_transaction) are as expected and handle any anomalies.

7. State Management

Issue:

    State Loading and Saving: Improper state management can lead to inconsistencies, especially after restarts or failures.

Solution:

    Verify bot_state.json: Ensure that the bot_state.json file is correctly read and written. Corrupted state files can prevent the bot from resuming active trades.
    Handle File I/O Errors: Ensure that any file I/O errors during state loading/saving are properly logged and handled.

8. Potential Deadlocks or Async Issues

Issue:

    Concurrency Control: Using Arc<Mutex<_>> and DashMap should prevent data races, but improper handling can still cause deadlocks or performance bottlenecks.

Solution:

    Review Async Operations: Ensure that asynchronous operations are properly awaited and that there are no asynchronous deadlocks.
    Optimize Concurrency: Make sure that tasks like monitoring trades and handling WebSocket messages are efficiently managed without blocking each other.

9. Testing and Debugging Steps

Recommendations:

    Add Detailed Logs:
        Insert debug statements at critical points in your code to trace the flow of execution.
        Log the results of key functions like validate_token, check_liquidity, get_quote, and execute_trade.

    Validate Configuration:
        Temporarily reduce the number of validation checks to isolate which condition might be failing.
        Ensure that all required environment variables and configuration files are correctly set up.

    Simulate Token Data:
        Create mock WebSocket messages that meet all validation criteria to see if the bot attempts to execute trades.

    Monitor WebSocket Traffic:
        Use tools or additional logging to monitor the incoming WebSocket messages and verify that tokens are being detected.

    Check Dependencies:
        Ensure all external dependencies (e.g., Solana RPC, Helius Pro, Jupiter API) are operational and that your API keys are valid.

    Unit Testing:
        Write unit tests for critical functions to ensure they behave as expected under various scenarios.

10. Code Snippets for Enhanced Logging

Here's how you can enhance logging in some key functions to better trace the bot's behavior:

impl Bot {
    async fn execute_trade(&self, token_mint: &str, is_buy: bool) -> Result<String> {
        info!("🔄 Executing {} trade for token: {}", if is_buy { "buy" } else { "sell" }, token_mint);
        // Existing code...
        
        let swap_data = match self.build_swap_transaction(&quote, priority_fee).await {
            Ok(data) => data,
            Err(e) => {
                error!("❌ Failed to build swap transaction: {}", e);
                return Err(e);
            }
        };
        
        let signature = match self.send_priority_transaction(swap_data, priority_fee).await {
            Ok(sig) => sig,
            Err(e) => {
                error!("❌ Failed to send transaction: {}", e);
                return Err(e);
            }
        };
        
        // Rest of the function...
    }

    async fn process_ws_message(&self, text: &str) -> Result<()> {
        self.log_with_config(log::Level::Debug, "Processing WebSocket message");

        let value: Value = match serde_json::from_str(text) {
            Ok(v) => v,
            Err(e) => {
                error!("❌ Failed to parse WebSocket message: {}", e);
                return Err(anyhow!("Failed to parse message"));
            }
        };

        // Existing code...
    }

    // Additional logging enhancements...
}

11. Final Recommendations

    Review All Async Operations: Ensure that all asynchronous functions are correctly awaited and that there are no orphaned tasks causing unexpected behavior.
    Ensure Sufficient SOL Balance: Confirm that the wallet has enough SOL to cover both trade amounts and transaction fees.
    Monitor External Services: Verify that external services like Solana RPC, Helius Pro, and Jupiter API are reachable and functioning as expected.
    Test in a Controlled Environment: If possible, test your bot in a testnet environment or with small transaction amounts to safely identify and fix issues.

By systematically following these steps and enhancing your logging mechanisms, you should be able to identify why the buy and sell operations aren't executing and address the underlying issues effectively. If you encounter specific errors or need further assistance with particular parts of the code, feel free to share the details!