"""
V11 — Feeds: Binance (precio spot) y CLOB (orderbook Polymarket).
"""
import json, time, websocket


class BinanceFeed:
    def __init__(self, ws_url: str):
        self.ws_url  = ws_url
        self.last_px = 0.0
        self._ws     = None
        self._stop   = False

    def run(self):
        def on_msg(ws, msg):
            try:
                self.last_px = float(json.loads(msg)["p"])
            except Exception:
                pass
        backoff = 2
        while not self._stop:
            try:
                self._ws = websocket.WebSocketApp(self.ws_url, on_message=on_msg)
                self._ws.run_forever(ping_interval=20, ping_timeout=10)
                backoff = 2
            except Exception as e:
                print(f"[binance] ws error: {e}")
            if not self._stop:
                time.sleep(backoff)
                backoff = min(backoff * 2, 60)

    def stop(self):
        self._stop = True
        try:
            self._ws.close()
        except Exception:
            pass


class CLOBFeed:
    """Tracks best bid/ask for a single token via CLOB websocket."""

    def __init__(self, token_id: str, ws_url: str):
        self.token_id = token_id
        self.ws_url   = ws_url
        self.best_bid = 0.0
        self.best_ask = 0.0
        self._ws      = None
        self._stop    = False

    def _on_open(self, ws):
        ws.send(json.dumps({"type": "market", "assets_ids": [self.token_id]}))

    def _on_msg(self, ws, msg):
        try:
            it    = json.loads(msg)
            items = it if isinstance(it, list) else [it]
            for i in items:
                if i.get("event_type") == "book" or "bids" in i:
                    b = i.get("bids", [])
                    a = i.get("asks", [])
                    if b:
                        self.best_bid = max(float(x["price"]) for x in b)
                    if a:
                        self.best_ask = min(float(x["price"]) for x in a)
        except Exception:
            pass

    def run(self):
        backoff = 2
        while not self._stop:
            try:
                self._ws = websocket.WebSocketApp(
                    self.ws_url, on_open=self._on_open, on_message=self._on_msg)
                self._ws.run_forever(ping_interval=20, ping_timeout=10)
                backoff = 2
            except Exception as e:
                print(f"[clob:{self.token_id[:8]}] reconnect: {e}")
            if not self._stop:
                time.sleep(backoff)
                backoff = min(backoff * 2, 60)

    def stop(self):
        self._stop = True
        try:
            self._ws.close()
        except Exception:
            pass
