import asyncio
import websockets
import json
import logging
from dataclasses import dataclass
from typing import Dict, Set, Optional, List
import time
from datetime import datetime
from PyQt6.QtCore import QTimer, QObject, pyqtSignal

from .gui import QuantumGUI
from .atomic_executor import AtomicExecutor

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

class MarketSignalsWorker(QObject):
    stats_update = pyqtSignal(dict)
    pools_update = pyqtSignal(dict)
    metrics_update = pyqtSignal(dict)
    positions_update = pyqtSignal(dict)

    def __init__(self, config: Dict):
        super().__init__()
        # Core configuration
        self.config = config
        self.ws_url = config['helius']['ws_endpoint']
        self.SOL_MINT = "So11111111111111111111111111111111111111112"
        self.PROGRAM_ID = config['raydium']['program_id']
    
        # Market data tracking
        self.current_price = 0.0
        self.current_volume = 0.0
        self.total_pnl = 0.0
        self.trade_count = 0
        self.win_count = 0
        self.active_trades = {}
        self.pools = {}
    
        # Initialize components
        self._init_trading_params(config)
        self._init_state_tracking()
        self._init_components(config)

    def _init_trading_params(self, config: Dict):
        # Same as before
        trading_config = config['trading']
        self.position_size = trading_config['initial_size']
        self.priority_fee = trading_config['priority_fee']
        self.min_volume = trading_config['min_volume']
        self.min_buyer_ratio = trading_config.get('min_bs_ratio', 0.6)
        self.min_liquidity = trading_config['min_liquidity']
        self.min_lp_locked = trading_config['liquidity_lock_min']
        self.max_holder_pct = trading_config['max_holder_pct']
        self.profit_targets = trading_config.get('profit_tiers', {
            'tier1': {'target': 2.0, 'sell_percent': 20},
            'tier2': {'target': 5.0, 'sell_percent': 30},
            'tier3': {'target': 10.0, 'sell_percent': 30},
            'tier4': {'target': 20.0, 'sell_percent': 20}
        })

    def _init_state_tracking(self):
        # Same as before
        self.untradable_tokens: Set[str] = set()
        self.failed_quotes: Set[str] = set()
        self.price_history: Dict[str, List[float]] = {}
        self.exit_signals: Set[str] = set()
        self.completed_trades: List[Dict] = []

    def _init_components(self, config: Dict):
        """Initialize trading components"""
        self.executor = AtomicExecutor(config)

    def update_ui(self):
        """Synchronous GUI updates"""
        try:
            # Prepare stats
            stats = {
                'price': self.current_price,
                'volume': self.current_volume,
                'pnl': self.total_pnl,
                'trades': self.trade_count,
                'win_rate': (self.win_count / self.trade_count * 100) if self.trade_count > 0 else 0
            }
            
            # Emit signals for UI update
            self.stats_update.emit(stats)
            self.pools_update.emit(self.pools)
            
            # Metrics update
            metrics = {
                'pnl': self.total_pnl,
                'total_trades': self.trade_count,
                'win_rate': (self.win_count / self.trade_count * 100) if self.trade_count > 0 else 0
            }
            self.metrics_update.emit(metrics)
            
            # Positions update
            positions = {token: {
                'token': trade['token'], 
                'size': trade['size'], 
                'entry': trade['entry_price'], 
                'pnl': self._calculate_profit(
                    self.pools.get(token, {}).get('price', trade['entry_price']), 
                    trade['entry_price']
                )
            } for token, trade in self.active_trades.items()}
            self.positions_update.emit(positions)
            
        except Exception as e:
            logging.error(f"GUI update error: {e}")

    async def start(self):
        try:
            async with websockets.connect(
                self.ws_url,
                extra_headers={"Authorization": f"Bearer {self.config['helius']['api_key']}"},
                ping_interval=30,
                ping_timeout=10
            ) as ws:
                await self._subscribe_to_program(ws)
                await self._process_messages(ws)
        except Exception as e:
            logging.error(f"Websocket error: {e}")

    async def _subscribe_to_program(self, ws):
        # Same as before
        subscription = {
            "jsonrpc": "2.0",
            "id": 1,
            "method": "programSubscribe",
            "params": [
                self.PROGRAM_ID,
                {
                    "encoding": "base64",
                    "commitment": "confirmed",
                    "filters": [{"memcmp": {"offset": 0, "bytes": "3"}}]
                }
            ]
        }
        await ws.send(json.dumps(subscription))
        logging.info("🚀 Connected to Raydium feed")

    async def _process_messages(self, ws):
        while True:
            try:
                msg = await ws.recv()
                await self.process_update(json.loads(msg))
            except Exception as e:
                logging.error(f"Message processing error: {e}")
                raise

    # Rest of the methods remain the same as in the original implementation

class MarketSignals:
    def __init__(self, config: Dict):
        # Ensure only one GUI is created
        if not hasattr(MarketSignals, '_instance'):
            MarketSignals._instance = self
            
            # Initialize GUI
            self.dash = QuantumGUI()
            self.dash.show()
            
            # Create worker
            from PyQt6.QtCore import QThread
            self.worker_thread = QThread()
            self.worker = MarketSignalsWorker(config)
            self.worker.moveToThread(self.worker_thread)
            
            # Connect signals
            self.worker.stats_update.connect(self.dash.update_gui_async)
            self.worker.pools_update.connect(self.dash.update_pools)
            self.worker.metrics_update.connect(self.dash.update_metrics_display)
            self.worker.positions_update.connect(self.dash.update_positions_display)
            
            # Setup periodic UI updates
            self.update_timer = QTimer()
            self.update_timer.timeout.connect(self.worker.update_ui)
            self.update_timer.start(1000)
            
            # Start worker thread
            self.worker_thread.started.connect(self.worker.start)
            self.worker_thread.start()
        else:
            # Return existing instance if already created
            return MarketSignals._instance

    async def cleanup(self):
        # Cleanup method
        if hasattr(self, 'worker'):
            await self.worker.executor.cleanup()
        if hasattr(self, 'dash'):
            self.dash.close()
        if hasattr(self, 'worker_thread'):
            self.worker_thread.quit()
            self.worker_thread.wait()    u see this script here