from __future__ import annotations

import asyncio
import json
from typing import List
import contextlib

from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Query

from app.streaming.binance_hub import hub as binance_hub
from app.streaming.alpha_hub import alpha_hub

router = APIRouter(prefix="/stream", tags=["Stream"])


@router.websocket("/klines")
async def stream_klines_ws(
    websocket: WebSocket,
    symbols: str = Query("BTCUSDT,XAUUSD"),
    timeframe: str = Query("1m"),
):
    await websocket.accept()

    syms: List[str] = [s.strip().upper().replace("/", "") for s in symbols.split(",") if s.strip()]


    async def forward_alpha(sym: str):
        queue, unsubscribe = await alpha_hub.subscribe(sym, timeframe="1m")
        try:
            while True:
                evt = await queue.get()
                if evt is None:
                    break
                try:
                    await websocket.send_text(json.dumps(evt))
                except WebSocketDisconnect:
                    break
                except Exception:
                    await asyncio.sleep(0)
        finally:
            try:
                await unsubscribe()
            except Exception:
                pass

    async def forward_binance(sym: str):
        queue, unsubscribe = await binance_hub.subscribe(sym, timeframe="1m")
        try:
            while True:
                evt = await queue.get()
                if evt is None:
                    break
                # evt already normalized with iso timestamps
                try:
                    await websocket.send_text(json.dumps(evt))
                except WebSocketDisconnect:
                    break
                except Exception:
                    await asyncio.sleep(0)
        finally:
            try:
                await unsubscribe()
            except Exception:
                pass

    tasks: List[asyncio.Task] = []
    try:
        for s in syms:
            if s == "XAUUSD" or s.startswith("XAU"):
                tasks.append(asyncio.create_task(forward_alpha("XAUUSD")))
            else:
                tasks.append(asyncio.create_task(forward_binance(s)))

        # Wait for disconnect
        done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
    except WebSocketDisconnect:
        pass
    finally:
        for t in tasks:
            t.cancel()
            with contextlib.suppress(Exception):
                await t
        with contextlib.suppress(Exception):
            await websocket.close()
