import asyncio
import base64
import json
import logging
import os
import time

import torch
import torch.cuda.amp as amp
from dataclasses import dataclass
from datetime import datetime

from solana_rust_bot import TradingCore, TradingConfig

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    handlers=[
        logging.StreamHandler(),
        logging.FileHandler("quantum_beast.log", encoding="utf-8"),
    ],
)
logger = logging.getLogger(__name__)

@dataclass
class TradeMetrics:
    timestamp: float = time.time()
    confidence: float = 0.95
    impact: float = 0.0015

class QuantumBeast:
    def __init__(self):
        self.RAYDIUM_V4 = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"
        self.TOKEN_PROGRAM = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
        self.WSOL = "So11111111111111111111111111111111111111112"
        self.SOL_WSOL_POOL = "Ewk6c9s5PsvBotzwK1J9rbiWE5gYom6U3161FCgVym"

        self.WS_URL = "wss://marga-e56m84-fast-mainnet.helius-rpc.com"
        self.RPC_URL = "https://marga-e56m84-fast-mainnet.helius-rpc.com"

        self.position_size = 0.01  # 0.01 SOL per trade
        self.max_tps = 5
        self.min_interval = 1 / self.max_tps
        self.slippage = 0.001  # 0.1% slippage
        self.max_position = 0.04  # Max 0.04 SOL position
        self.min_profit = 0.00001  # Min profit in SOL

        self.active_trades = {}
        self.total_profit = 0
        self.trades_count = 0
        self.last_trade_time = 0

        self.device = None
        self.price_buffer = None
        self.cuda_stream = None

        self._setup_gpu()
        self._setup_trading_core()
        self._log_initial_status()

    def _setup_gpu(self):
        if torch.cuda.is_available():
            self.device = torch.device("cuda")
            torch.backends.cudnn.benchmark = True
            torch.backends.cuda.matmul.allow_tf32 = True
            torch.backends.cudnn.allow_tf32 = True
            self.cuda_stream = torch.cuda.Stream()
            self.price_buffer = torch.zeros(1024, device=self.device, dtype=torch.float16)
            logger.info(f"GPU initialized - {torch.cuda.get_device_name()}")

    def _setup_trading_core(self):
        solana_private_key = os.getenv("SOLANA_PRIVATE_KEY")
        if not solana_private_key:
            logger.error("SOLANA_PRIVATE_KEY environment variable not set!")
            raise ValueError("SOLANA_PRIVATE_KEY is required.")

        self.trading = TradingCore(solana_private_key, self.RPC_URL)
        self._setup_trading_config()

    def _setup_trading_config(self):
        config = TradingConfig()
        config.rpc_url = self.RPC_URL
        config.program_id = self.RAYDIUM_V4
        config.token_program = self.TOKEN_PROGRAM
        config.compute_budget = 1_400_000
        config.priority_fee_level = "HIGH"
        self.trading.update_config(config)

    def _log_initial_Seducer(self):
        try:
            balance = self.trading.get_balance()
            logger.info(f"Initial Balance: {balance:.6f} SOL")
        except Exception as e:
            logger.error(f"Failed to fetch initial balance: {e}")

    async def health_check(self) -> bool:
        logger.info("Performing health check...")
        try:
            balance = self.trading.get_balance()
            if balance < 0.01:
                logger.error(f"Low balance: {balance} SOL")
                return False

            if self.device:
                with torch.cuda.stream(self.cuda_stream):
                    test_tensor = torch.zeros(1, device=self.device, dtype=torch.float16)

            async with websockets.connect(self.WS_URL) as ws:
                await ws.close()

            return True

        except Exception as e:
            logger.error(f"Health check failed: {e}")
            return False

    async def execute_trade(self, trade_data):
        current_time = time.time()
        if current_time - self.last_trade_time < self.min_interval:
            return False

        balance = self.trading.get_balance()
        if balance < self.position_size + 0.01:
            logger.warning(f"Low balance: {balance} SOL")
            return False

        priority_fee = 65000
        momentum = abs(trade_data.get('momentum', 0))
        if momentum > 0.002:
            priority_fee = 75000

        trade_params = {
            'pool_address': self.SOL_WSOL_POOL,
            'amount_in': self.position_size,
            'min_amount_out': self.position_size * (1 - self.slippage),
            'priority_fee': priority_fee
        }

        logger.info(f"🚀 Executing Trade: Pool: {trade_params['pool_address']} Size: {trade_params['amount_in']} SOL Price: ${trade_data['price']:.4f} Priority: {priority_fee}")

        signature = self.trading.execute_trade(trade_params)
        if signature:
            self.active_trades[trade_params['pool_address']] = {
                'entry_time': time.time(),
                'amount': trade_params['amount_in'],
                'entry_price': trade_data['price'],
                'signature': signature
            }
            self.last_trade_time = current_time
            self.trades_count += 1
            logger.info(f"Trade executed! Signature: {signature}")

            await asyncio.sleep(0.5)
            await self.check_trade_profit(trade_params['pool_address'])
            return True

        return False

    async def check_trade_profit(self, pool_address):
        if pool_address not in self.active_trades:
            return

        trade = self.active_trades[pool_address]
        current_price = self.last_price

        if not current_price:
            return

        profit_pct = ((current_price / trade['entry_price']) - 1) * 100
        profit_usd = trade['amount'] * current_price * (profit_pct / 100)

        logger.info(f"📈 Trade Profit: Entry: ${trade['entry_price']:.4f} Current: ${current_price:.4f} Profit: ${profit_usd:.4f} ({profit_pct:.2f}%)")

        self.total_profit += profit_usd

    async def process_pool_update(self, data):
    base_supply, quote_supply = self._extract_pool_metrics(data)

    if base_supply > 0 and quote_supply > 0:
        price = quote_supply / base_supply
        logger.info(f"Price: ${price:.4f}")

        if self.device:
            with torch.cuda.stream(self.cuda_stream):
                if self.price_buffer is None:
                    self.price_buffer = torch.zeros(1024, device=self.device, dtype=torch.float16)
                self.price_buffer[:-1] = self.price_buffer[1:].clone()
                self.price_buffer[-1] = torch.tensor(price, device=self.device, dtype=torch.float16)

                if len(self.price_buffer) > 20:
                    momentum = (self.price_buffer[-1] - self.price_buffer[-20]) / self.price_buffer[-20]
                    momentum_val = momentum.item()
                    logger.info(f"Momentum: {momentum_val:.4%}")

                    if abs(momentum_val) > 0.001:
                        trade_data = {
                            'pool_address': self.SOL_WSOL_POOL,
                            'price': float(price),
                            'momentum': momentum_val,
                        }
                        await self.execute_trade(trade_data)

                # Update pool metrics in trading core
                self.trading.update_pool_metrics(
                    pool_address=self.SOL_WSOL_POOL,
                    base_supply=int(base_supply * 1e9),
                    quote_supply=int(quote_supply * 1e9),
                    volume_24h=0,  # Calculate separately
                    liquidity=int(quote_supply * 2 * 1e9),
                    holders=0,
                    whale_metrics=0,
                    price=float(price),
                )

    else:
        logger.warning("Invalid pool metrics. Base supply or quote supply is 0.")

def _extract_pool_metrics(self, data):
    # Extract base supply and quote supply from data
    try:
        base_supply = int.from_bytes(data[8:16], byteorder='little') / 1e9
        quote_supply = int.from_bytes(data[16:24], byteorder='little') / 1e9
    except ValueError as e:
        logger.error(f"Error extracting pool metrics: {e}")
        base_supply, quote_supply = 0, 0
    return base_supply, quote_supply

async def run(self):
    logger.info("Quantum Beast Online - SOL/WSOL Raydium V4")

    while True:
        try:
            async with websockets.connect(self.WS_URL, ping_interval=20, ping_timeout=10, close_timeout=10) as ws:
                subscribe_msg = {
                    "jsonrpc": "2.0",
                    "id": "quantum_sub",
                    "method": "accountSubscribe",
                    "params": [
                        self.SOL_WSOL_POOL,
                        {"encoding": "base64"}
                    ]
                }

                await ws.send(json.dumps(subscribe_msg))
                response = await ws.recv()
                data = json.loads(response)

                if "result" in data:
                    logger.info("Subscription successful.")
                    while True:
                        try:
                            msg = await ws.recv()
                            pool_update_data = json.loads(msg)
                            if "params" in pool_update_data:
                                account_data = pool_update_data["params"]["result"]
                                decoded_data = base64.b64decode(account_data)
                                await self.process_pool_update(decoded_data)
                        except websockets.exceptions.ConnectionClosed as e:
                            logger.warning("Connection closed. Reconnecting...")
                            break
                else:
                    logger.error("Subscription failed.")
                    await asyncio.sleep(1)
        except Exception as e:
            logger.error(f"Connection error: {e}")
            await asyncio.sleep(1)

def cleanup(self):
    logger.info("Cleaning up resources...")
    try:
        if self.device:
            torch.cuda.empty_cache()
            if self.cuda_stream:
                self.cuda_stream.synchronize()
        logger.info("Cleanup complete.")
    except Exception as e:
        logger.error(f"Cleanup error: {e}")

async def main():
    beast = QuantumBeast()
    try:
        if not await beast.health_check():
            logger.error("Health check failed. Exiting.")
            return
        await beast.run()
    except KeyboardInterrupt:
        logger.info("Received interrupt. Shutting down...")
    finally:
        beast.cleanup()
        logger.info(f"Trading Session Summary:")
        logger.info(f"Total Trades: {beast.trades_count}")
        logger.info(f"Total Profit: ${beast.total_profit:.4f}")

if __name__ == "__main__":
    asyncio.run(main())
 ADD THE ABSOLUTE MOST TRACING AND LOGGING AND DEBUG LOGGING U CAN POSSBILY ADD TO THIS SCRIPT HERE AND FIX THE SPACING ISSUES PLEASE