import asyncio
import json
import logging
import websockets
from typing import Callable, Optional

logger = logging.getLogger(__name__)

BINANCE_WS_BASE = "wss://stream.binance.com:9443/ws"


class BinanceWebSocketFeed:
    """
    Connects to Binance WebSocket streams for real-time price data.
    Supports individual symbol mini-ticker streams.
    """

    def __init__(self):
        self._running = False
        self._ws: Optional[websockets.WebSocketClientProtocol] = None

    async def subscribe_ticker(self, symbol: str, callback: Callable):
        """
        Subscribe to a symbol's mini-ticker stream.
        Calls `callback(data: dict)` on each message.
        """
        stream = f"{symbol.lower().replace('/', '')}@miniTicker"
        url = f"{BINANCE_WS_BASE}/{stream}"
        self._running = True

        while self._running:
            try:
                async with websockets.connect(url) as ws:
                    self._ws = ws
                    logger.info(f"Connected to Binance WS stream: {stream}")
                    async for raw_message in ws:
                        if not self._running:
                            break
                        data = json.loads(raw_message)
                        await callback(data)
            except websockets.ConnectionClosed:
                if self._running:
                    logger.warning(f"WS connection closed for {stream}, reconnecting in 5s...")
                    await asyncio.sleep(5)
            except Exception as e:
                logger.error(f"WS error for {stream}: {e}")
                await asyncio.sleep(5)

    async def stop(self):
        """Gracefully stop the WebSocket feed."""
        self._running = False
        if self._ws:
            await self._ws.close()


ws_feed = BinanceWebSocketFeed()
