"""Market data client for prices and order books."""

from __future__ import annotations

from typing import Any, Callable, Coroutine, Dict, List, Optional

from zenotc.clients.base import BaseClient
from zenotc.models.market_data import OrderBook, Price, PriceUpdate


class MarketDataClient(BaseClient):
    """Client for market data access."""

    async def get_prices(self, assets: Optional[List[str]] = None) -> List[Price]:
        """Get current prices for assets."""
        params: Dict[str, Any] = {}
        if assets:
            params["assets"] = ",".join(a.upper() for a in assets)

        await self._rate_limiter.acquire()
        response = await self._http.get("/api/v1/market-data/prices", params=params)

        # Handle both list response and dict with "prices" key
        if isinstance(response, list):
            prices_data = response
        else:
            prices_data = response.get("prices", response.get("data", []))
        return [Price.model_validate(p) for p in prices_data]

    async def get_price(self, asset: str) -> Price:
        """Get current price for a single asset."""
        prices = await self.get_prices([asset])
        if not prices:
            raise ValueError(f"No price available for {asset}")
        return prices[0]

    async def get_orderbook(self, asset: str, depth: int = 10) -> OrderBook:
        """Get order book for an asset."""
        params = {"depth": min(depth, 100)}

        await self._rate_limiter.acquire()
        response = await self._http.get(
            f"/api/v1/market-data/orderbook/{asset.upper()}",
            params=params,
        )
        return OrderBook.model_validate(response)

    async def get_orderbooks(
        self, assets: List[str], depth: int = 10
    ) -> Dict[str, OrderBook]:
        """Get order books for multiple assets."""
        params = {
            "assets": ",".join(a.upper() for a in assets),
            "depth": min(depth, 100),
        }

        await self._rate_limiter.acquire()
        response = await self._http.get("/api/v1/market-data/orderbooks", params=params)

        orderbooks = response.get("orderbooks", {})
        return {asset: OrderBook.model_validate(ob) for asset, ob in orderbooks.items()}

    async def subscribe_prices(
        self,
        assets: List[str],
        callback: Callable[[PriceUpdate], Coroutine[Any, Any, None]],
    ) -> None:
        """Subscribe to real-time price updates."""
        async def handler(data: Dict[str, Any]) -> None:
            price = PriceUpdate.model_validate(data.get("data", data))
            await callback(price)

        await self._websocket.subscribe(
            channel="prices",
            symbols=[a.upper() for a in assets],
            handler=handler,
        )

    async def subscribe_orderbook(
        self,
        asset: str,
        callback: Callable[[OrderBook], Coroutine[Any, Any, None]],
        depth: int = 10,
    ) -> None:
        """Subscribe to real-time order book updates."""
        async def handler(data: Dict[str, Any]) -> None:
            orderbook = OrderBook.model_validate(data.get("data", data))
            await callback(orderbook)

        await self._websocket.subscribe(
            channel=f"orderbook:{depth}",
            symbols=[asset.upper()],
            handler=handler,
        )

    async def unsubscribe_prices(self, assets: Optional[List[str]] = None) -> None:
        """Unsubscribe from price updates."""
        await self._websocket.unsubscribe(
            channel="prices",
            symbols=[a.upper() for a in assets] if assets else None,
        )

    async def unsubscribe_orderbook(self, asset: str) -> None:
        """Unsubscribe from order book updates."""
        await self._websocket.unsubscribe(channel="orderbook", symbols=[asset.upper()])

    async def get_trading_pairs(self) -> List[Dict[str, Any]]:
        """Get available trading pairs and their configurations."""
        await self._rate_limiter.acquire()
        response = await self._http.get("/api/v1/market-data/trading-pairs")
        return response if isinstance(response, list) else response.get("pairs", [])

    async def get_24h_stats(self, asset: Optional[str] = None) -> List[Dict[str, Any]]:
        """Get 24-hour trading statistics."""
        params: Dict[str, Any] = {}
        if asset:
            params["asset"] = asset.upper()

        await self._rate_limiter.acquire()
        response = await self._http.get("/api/v1/market-data/stats/24h", params=params)
        return response.get("stats", [])
