import asyncio
import websockets
import json

# 📍 CONFIGURACIÓN DINÁMICA
# Cada entrada: (nombre, exchange, symbol)
PAIRS_TO_MONITOR = [
    # DOGE
    # ("DOGE-USD", "coinbase", "DOGE-USD"),
    # ("DOGEUSDT", "binance", "dogeusdt"),
    # ("DOGE/USDT", "kraken", "DOGE/USDT"),
    # ("DOGEUSDT", "bybit", "DOGEUSDT"),
    # ("DOGEUSD", "bitfinex", "tDOGEUSD"),
    
    # # SHIB
    # ("SHIB-USD", "coinbase", "SHIB-USD"),
    # ("SHIBUSDT", "binance", "shibusdt"),
    # ("SHIBUSDT", "bybit", "SHIBUSDT"),
    # ("SHIBUSD", "bitfinex", "tSHIBUSD"),

    # # PEPE
    # ("PEPEUSDT", "binance", "pepeusdt"),
    # ("PEPEUSDT", "bybit", "PEPEUSDT"),

    # BONK
    ("BONKUSDT", "binance", "bonkusdt"),
    ("BONKUSDT", "bybit", "BONKUSDT"),

    # FLOKI
    # ("FLOKIUSDT", "binance", "flokusdt"),
    # ("FLOKIUSDT", "bybit", "FLOKIUSDT"),
]

threshold_pct = 0.5
threshold_proximity = 0.2

latest_prices = {}
last_printed = {}

# 📡 Binance WebSocket
async def listen_binance(name, symbol):
    uri = f"wss://stream.binance.com:9443/ws/{symbol}@bookTicker"
    async with websockets.connect(uri) as websocket:
        print(f"🔄 Conectado Binance {symbol.upper()}")
        async for message in websocket:
            data = json.loads(message)
            bid = float(data["b"])
            latest_prices[name] = bid

# 📡 Coinbase WebSocket
async def listen_coinbase(name, symbol):
    uri = "wss://ws-feed.exchange.coinbase.com"
    async with websockets.connect(uri) as websocket:
        print(f"🔄 Conectado Coinbase {symbol}")
        subscribe = {
            "type": "subscribe",
            "channels": [
                {"name": "ticker", "product_ids": [symbol]}
            ]
        }
        await websocket.send(json.dumps(subscribe))
        async for message in websocket:
            data = json.loads(message)
            if data["type"] == "ticker":
                if data.get("best_bid"):
                    bid = float(data["best_bid"])
                elif data.get("price"):
                    bid = float(data["price"])
                else:
                    continue
                latest_prices[name] = bid

# 📡 Kraken WebSocket
async def listen_kraken(name, symbol):
    uri = "wss://ws.kraken.com/"
    async with websockets.connect(uri) as websocket:
        print(f"🔄 Conectado Kraken {symbol}")
        subscribe = {
            "event": "subscribe",
            "pair": [symbol],
            "subscription": {"name": "ticker"}
        }
        await websocket.send(json.dumps(subscribe))
        async for message in websocket:
            data = json.loads(message)
            if isinstance(data, list) and len(data) > 1:
                ticker = data[1]
                bid = float(ticker["b"][0])
                latest_prices[name] = bid

# 📡 Bybit WebSocket
async def listen_bybit(name, symbol):
    uri = f"wss://stream.bybit.com/v5/public/spot"
    async with websockets.connect(uri) as websocket:
        print(f"🔄 Conectado Bybit {symbol}")
        subscribe = {
            "op": "subscribe",
            "args": [f"orderbook.1.{symbol}"]
        }
        await websocket.send(json.dumps(subscribe))
        async for message in websocket:
            data = json.loads(message)
            if data.get("topic", "").startswith("orderbook"):
                bid = float(data["data"]["b"][0][0])
                latest_prices[name] = bid

# 📡 Bitfinex WebSocket
async def listen_bitfinex(name, symbol):
    uri = "wss://api-pub.bitfinex.com/ws/2"
    async with websockets.connect(uri) as websocket:
        print(f"🔄 Conectado Bitfinex {symbol}")
        subscribe = {
            "event": "subscribe",
            "channel": "ticker",
            "symbol": symbol
        }
        await websocket.send(json.dumps(subscribe))
        chan_id = None
        async for message in websocket:
            data = json.loads(message)
            if isinstance(data, dict):
                if data.get("event") == "subscribed":
                    chan_id = data["chanId"]
            elif isinstance(data, list):
                if chan_id and data[0] == chan_id and isinstance(data[1], list):
                    bid = float(data[1][0])
                    latest_prices[name] = bid

# 🧠 Monitor diferencias
async def monitor_diff():
    while True:
        names = list(latest_prices.keys())
        for i in range(len(names)):
            for j in range(i + 1, len(names)):
                n1, n2 = names[i], names[j]
                p1, p2 = latest_prices[n1], latest_prices[n2]

                if p1 and p2:
                    pct_diff = ((p2 - p1) / p1) * 100
                    abs_diff = abs(pct_diff)
                    key = f"{n1}-{n2}"
                    last_pct = last_printed.get(key, None)
                    delta_diff = abs((last_pct or 0) - pct_diff)
                    relevant_change = delta_diff >= 0.05
                    near_threshold = abs_diff >= (threshold_pct - threshold_proximity)

                    if relevant_change or near_threshold:
                        # Mostrar exchange entre corchetes
                        e1 = next(e for n, e, s in PAIRS_TO_MONITOR if n == n1)
                        e2 = next(e for n, e, s in PAIRS_TO_MONITOR if n == n2)

                        print(
                            f"[{n1}] ({e1}) {p1:.8f} vs [{n2}] ({e2}) {p2:.8f} | Δ: {pct_diff:.2f}%"
                        )
                        last_printed[key] = pct_diff

                        if abs_diff > threshold_pct:
                            print(
                                f"🚨 DESFASE entre {n1} ({e1}) y {n2} ({e2}) ({pct_diff:.2f}%)"
                            )
        await asyncio.sleep(0.2)


# 🚀 Lanzador
async def main():
    tasks = []
    for name, exchange, symbol in PAIRS_TO_MONITOR:
        latest_prices[name] = None
        if exchange == "binance":
            tasks.append(listen_binance(name, symbol))
        elif exchange == "coinbase":
            tasks.append(listen_coinbase(name, symbol))
        elif exchange == "kraken":
            tasks.append(listen_kraken(name, symbol))
        elif exchange == "bybit":
            tasks.append(listen_bybit(name, symbol))
        elif exchange == "bitfinex":
            tasks.append(listen_bitfinex(name, symbol))
        else:
            print(f"⚠️ Exchange no soportado: {exchange}")
    tasks.append(monitor_diff())
    await asyncio.gather(*tasks)

if __name__ == "__main__":
    asyncio.run(main())
