import asyncio
import logging
import json
import time
import os
import base64
import websockets
import torch
from typing import Dict, Optional
from solana_rust_bot import TradingCore

# RPC endpoints
HELIUS_RPC = "https://marga-e56m84-fast-mainnet.helius-rpc.com/"
QUICKNODE_WS = "wss://prettiest-bold-cherry.solana-mainnet.quiknode.pro/8144a2ac13c8301886abcf2ac35ad129d478b554"
RAYDIUM_PROGRAM = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"
SOL_WSOL_POOL = "HJPjoWUrhoZzkNfRpHuieeFk9WcZWjwy6PBjZ81ngndJ"

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s.%(msecs)03d [%(levelname)s] %(funcName)s: %(message)s',
    handlers=[logging.StreamHandler(), logging.FileHandler('marga_trading.log')]
)
logger = logging.getLogger(__name__)

class MargaTrader:
    def __init__(self):
        if not os.getenv('SOLANA_PRIVATE_KEY'):
            raise ValueError("SOLANA_PRIVATE_KEY not set!")

        # Initialize trading core
        self.marga = TradingCore(
            secret_key=os.getenv('SOLANA_PRIVATE_KEY'),
            rpc_url=HELIUS_RPC
        )
        
        # Trading parameters
        self.position_size = 0.015     # 0.015 SOL position
        self.min_profit = 0.015      # 1.5% minimum
        self.max_profit = 0.05       # 5% maximum
        self.stop_loss = 0.012       # 1.2% stop loss
        self.max_position_size = 0.2  # 0.2 SOL maximum size
        
        # Performance tracking
        self.max_positions = 1
        self.active_trades = {}
        self.trade_interval = 0.2
        self.last_trade_time = 0
        self.trades_this_minute = 0
        self.successful_trades = 0
        
        # Initialize GPU
        self.setup_gpu()

    def setup_gpu(self):
        """Initialize GPU acceleration"""
        if torch.cuda.is_available():
            self.device = torch.device("cuda")
            self.stream = torch.cuda.Stream()
            
            with torch.cuda.stream(self.stream):
                self.price_history = torch.zeros(1000, device=self.device)
                self.volume_history = torch.zeros(1000, device=self.device)
                
            logger.info(f"GPU acceleration enabled: {torch.cuda.get_device_name()}")
            logger.info(f"CUDA Memory: {torch.cuda.memory_allocated()/1e9:.2f}GB allocated")
        else:
            self.device = torch.device("cpu")
            logger.warning("GPU not available, using CPU")

    async def analyze_opportunity(self, data: bytes) -> Optional[Dict]:
        """Analyze trading opportunity with more aggressive parameters"""
        try:
            amount_in = int.from_bytes(data[0:8], 'little')
            amount_out = int.from_bytes(data[8:16], 'little')
            
            # Basic validation
            if amount_in == 0 or amount_out == 0:
                return None

            # Convert to SOL terms
            amount_in_sol = amount_in / 1e9
            amount_out_sol = amount_out / 1e9
            
            # More lenient size validation
            if not (0.005 <= amount_in_sol <= self.max_position_size):  # Lowered min size
                return None

            # Calculate profit
            profit = (amount_out - amount_in) / amount_in
            
            # GPU pattern analysis
            with torch.cuda.stream(self.stream):
                price = amount_out_sol / amount_in_sol
                self.price_history = torch.roll(self.price_history, -1)
                self.price_history[-1] = price

                # Faster volatility calculation with shorter window
                recent_prices = self.price_history[-20:]  # Shorter window
                valid_mask = recent_prices > 0
                valid_prices = recent_prices[valid_mask]
                
                if len(valid_prices) >= 3:  # Reduced minimum samples
                    mean_price = torch.mean(valid_prices)
                    if mean_price > 0:
                        returns = valid_prices[1:] / valid_prices[:-1] - 1
                        volatility = torch.std(returns, unbiased=True)
                    else:
                        volatility = torch.tensor(float('inf'))
                else:
                    volatility = torch.tensor(float('inf'))

                # Quick trend check
                if len(valid_prices) >= 5:
                    short_ma = torch.mean(valid_prices[-3:])
                    long_ma = torch.mean(valid_prices[-5:])
                    trend = (short_ma / long_ma - 1) if long_ma > 0 else 0
                else:
                    trend = 0

            # More aggressive validation
            valid_opportunity = (
                0.01 <= profit <= 0.05 and      # 1% to 5% profit range
                volatility < 0.05 and           # Increased volatility tolerance
                amount_in_sol >= 0.005 and      # Lower minimum size
                abs(trend) < 0.02               # More trend tolerance
            )

            if valid_opportunity:
                logger.info(f"""
                🎯 Valid Opportunity Found:
                Profit: {profit*100:.2f}%
                Size: {amount_in_sol:.6f} SOL -> {amount_out_sol:.6f} SOL
                Volatility: {volatility:.4f}
                Trend: {trend:.4f}
                =============================
                """)

                return {
                    'amount_in': amount_in,
                    'amount_out': amount_out,
                    'expected_profit': float(profit),
                    'volatility': float(volatility),
                    'trend': float(trend)
                }
            elif profit > 0.01:  # Log near-misses for tuning
                logger.debug(f"""
                Near Miss:
                Profit: {profit*100:.2f}%
                Size: {amount_in_sol:.6f} SOL
                Volatility: {volatility:.4f}
                """)

            return None

        except Exception as e:
            logger.error(f"Opportunity analysis error: {e}")
            return None

async def process_mempool_data(self, tx_data: dict):
        """Process mempool with debug logging"""
        try:
            logs = tx_data.get('value', {}).get('logs', [])
            opportunity_count = 0
            
            for log in logs:
                if "ray_log:" in log:
                    opportunity_count += 1
                    b64_str = log.split('ray_log: ')[1].strip()
                    data = base64.b64decode(b64_str)
                    
                    opportunity = await self.analyze_opportunity(data)
                    if opportunity:
                        await self.execute_trade(opportunity)
            
            if opportunity_count > 0:
                logger.debug(f"Processed {opportunity_count} potential opportunities")

        except Exception as e:
            logger.error(f"Mempool processing error: {e}")

async def execute_trade(self, opportunity: dict) -> bool:
        """Execute trade with aggressive settings"""
        try:
            current_time = time.time()
            if current_time - self.last_trade_time < self.trade_interval:
                return False

            if len(self.active_trades) >= self.max_positions:
                return False

            # Prepare optimized trade parameters
            position_size = min(self.position_size, opportunity['amount_in'] / 1e9)
            min_out_buffer = 1.001  # 0.1% buffer for success

            trade_params = {
                "pool_address": SOL_WSOL_POOL,
                "amount_in": int(position_size * 1e9),
                "min_amount_out": int(position_size * (1 + opportunity['expected_profit']) * min_out_buffer * 1e9),
                "priority_fee": 75000,
                "compute_limit": 1400000
            }

            logger.info(f"""
            � Executing Trade:
            Expected Profit: {opportunity['expected_profit']*100:.2f}%
            Size: {position_size} SOL
            Min Out: {trade_params['min_amount_out']/1e9:.6f} SOL
            Volatility: {opportunity['volatility']:.4f}
            =============================
            """)

            signature = self.marga.execute_trade(trade_params)
            
            if signature:
                self.last_trade_time = current_time
                self.trades_this_minute += 1
                self.successful_trades += 1
                
                self.active_trades[signature] = {
                    'entry_time': current_time,
                    'amount': trade_params['amount_in'],
                    'expected_profit': opportunity['expected_profit']
                }
                
                logger.info(f"✅ Trade executed! Signature: {signature}")
                return True

            return False

        except Exception as e:
            logger.error(f"Trade execution error: {e}")
            return False
    async def monitor_performance(self):
        """Monitor trading performance"""
        while True:
            try:
                await asyncio.sleep(60)
            
                logger.info(f"""
                === Performance Metrics ===
                Successful Trades: {self.successful_trades}
                Trades This Minute: {self.trades_this_minute}
                Active Positions: {len(self.active_trades)}
                GPU Memory: {torch.cuda.memory_allocated()/1e9:.2f}GB
                """)
            
                self.trades_this_minute = 0

            except Exception as e:
                logger.error(f"Monitoring error: {e}")

    async def run(self):
        """Main trading loop"""
        logger.info("Starting Marga trading system...")
        monitor_task = asyncio.create_task(self.monitor_performance())
    
        connection_retries = 0
        max_retries = 3
    
        try:
            while True:
                try:
                    async with websockets.connect(
                        QUICKNODE_WS,
                        ping_interval=115,
                        ping_timeout=60,
                        close_timeout=60,
                        max_size=2**24
                    ) as ws:
                        subscribe_msg = {
                            "jsonrpc": "2.0",
                            "id": "marga-trading",
                            "method": "logsSubscribe",
                            "params": [
                                {"mentions": [RAYDIUM_PROGRAM]},
                                {"commitment": "confirmed"}
                            ]
                        }

                        await ws.send(json.dumps(subscribe_msg))
                        response = await ws.recv()
                        response_data = json.loads(response)
                    
                        if "error" in response_data:
                            logger.error(f"Subscription error: {response_data['error']}")
                            connection_retries += 1
                            if connection_retries >= max_retries:
                                break
                            continue

                        logger.info("Successfully connected to mempool")
                        connection_retries = 0

                        while True:
                            msg = await ws.recv()
                            data = json.loads(msg)
                        
                            if data.get("method") == "logsNotification":
                                result = data.get("params", {}).get("result", {})
                                if result:
                                    await self.process_mempool_data(result)

                except websockets.exceptions.ConnectionClosed:
                    logger.warning("WebSocket disconnected - reconnecting...")
                    await asyncio.sleep(1)
                except Exception as e:
                    logger.error(f"Connection error: {e}")
                    await asyncio.sleep(1)

        finally:
            monitor_task.cancel()
            if torch.cuda.is_available():
                torch.cuda.empty_cache()

    async def main():
        """Entry point"""
        os.environ['RUST_BACKTRACE'] = 'full'
    
        try:
            trader = MargaTrader()
            initial_balance = trader.marga.get_balance()
        
            logger.info(f"""
            === Starting Marga Trading ===
            Balance: {initial_balance} SOL
            Position Size: {trader.position_size} SOL
            Min Profit: {trader.min_profit*100}%
            Max Profit: {trader.max_profit*100}%
            Stop Loss: {trader.stop_loss*100}%
            Max Position Size: {trader.max_position_size} SOL
            GPU: {torch.cuda.get_device_name() if torch.cuda.is_available() else "CPU"}
            """)
        
            await trader.run()
        
        except KeyboardInterrupt:
            logger.info("Shutting down gracefully...")
            if torch.cuda.is_available():
                torch.cuda.empty_cache()
        except Exception as e:
            logger.error(f"Fatal error: {e}")

    if __name__ == "__main__":
        asyncio.run(main()) fix spacing and write debug loggign throughout