"""Exchanges resource for catalog operations."""

from __future__ import annotations

import builtins
from typing import TYPE_CHECKING

from ticksupply.models.catalog import (
    Exchange,
    PaginatedDatastreams,
    PaginatedInstruments,
)
from ticksupply.resources.base import AsyncResource, SyncResource

if TYPE_CHECKING:
    from ticksupply._base import AsyncHTTPClient, SyncHTTPClient


class ExchangesResource(SyncResource):
    """Synchronous resource for exchange and catalog operations.

    Provides access to exchanges, instruments, stream types, and datastreams.
    """

    def __init__(self, client: SyncHTTPClient) -> None:
        super().__init__(client)

    def list(self) -> builtins.list[Exchange]:
        """List all available exchanges.

        Returns:
            List of exchanges.

        Example:
            >>> for exchange in client.exchanges.list():
            ...     print(f"{exchange.code}: {exchange.display_name}")
        """
        response = self._client.get("/exchanges")
        data = response.json()
        return [Exchange.model_validate(item) for item in data]

    def list_instruments(
        self,
        exchange: str,
        *,
        search: str | None = None,
        base: str | None = None,
        quote: str | None = None,
        instrument_type: str | None = None,
        limit: int = 100,
        page_token: str | None = None,
    ) -> PaginatedInstruments:
        """List instruments for an exchange with pagination.

        Args:
            exchange: Exchange code (e.g., "binance").
            search: Optional search term to filter instruments by symbol.
            base: Filter by base asset (e.g., "BTC").
            quote: Filter by quote asset (e.g., "USDT").
            instrument_type: Filter by instrument type (e.g., "spot", "perpetual").
            limit: Maximum number of instruments per page (1-1000, default 100).
            page_token: Pagination cursor from previous response.

        Returns:
            Paginated list of instruments.

        Example:
            >>> result = client.exchanges.list_instruments("binance", base="BTC", limit=10)
            >>> for inst in result.items:
            ...     print(f"{inst.symbol}: {inst.base}/{inst.quote}")
            >>> if result.has_next:
            ...     next_page = client.exchanges.list_instruments(
            ...         "binance", base="BTC", page_token=result.next_page_token
            ...     )
        """
        response = self._client.get(
            f"/exchanges/{exchange}/instruments",
            params={
                "search": search,
                "base": base,
                "quote": quote,
                "instrument_type": instrument_type,
                "limit": limit,
                "page_token": page_token,
            },
        )
        return PaginatedInstruments.model_validate(response.json())

    def list_datastreams(
        self,
        exchange: str,
        instrument: str,
        *,
        stream_type: str | None = None,
        wire_format: str | None = None,
        limit: int = 100,
        page_token: str | None = None,
    ) -> PaginatedDatastreams:
        """List datastreams for an exchange and instrument.

        Args:
            exchange: Exchange code (e.g., "binance").
            instrument: Instrument symbol (e.g., "BTCUSDT").
            stream_type: Optional stream type code to filter by (e.g., "trade").
            wire_format: Optional wire format code to filter by (e.g., "json").
            limit: Maximum number of results per page (1-1000, default 100).
            page_token: Pagination cursor from previous response.

        Returns:
            Paginated list of datastreams.

        Example:
            >>> # Get all datastreams for an instrument
            >>> result = client.exchanges.list_datastreams("binance", "BTCUSDT")
            >>> for ds in result.items:
            ...     print(f"{ds.stream_type}/{ds.wire_format}: {ds.datastream_id}")
            >>> # Filter by stream type
            >>> trades = client.exchanges.list_datastreams(
            ...     "binance", "BTCUSDT", stream_type="trade"
            ... )
        """
        response = self._client.get(
            f"/exchanges/{exchange}/instruments/{instrument}/datastreams",
            params={
                "stream_type": stream_type,
                "wire_format": wire_format,
                "limit": limit,
                "page_token": page_token,
            },
        )
        return PaginatedDatastreams.model_validate(response.json())


class AsyncExchangesResource(AsyncResource):
    """Asynchronous resource for exchange and catalog operations.

    Provides access to exchanges, instruments, stream types, and datastreams.
    """

    def __init__(self, client: AsyncHTTPClient) -> None:
        super().__init__(client)

    async def list(self) -> builtins.list[Exchange]:
        """List all available exchanges.

        Returns:
            List of exchanges.

        Example:
            >>> async for exchange in await client.exchanges.list():
            ...     print(f"{exchange.code}: {exchange.display_name}")
        """
        response = await self._client.get("/exchanges")
        data = response.json()
        return [Exchange.model_validate(item) for item in data]

    async def list_instruments(
        self,
        exchange: str,
        *,
        search: str | None = None,
        base: str | None = None,
        quote: str | None = None,
        instrument_type: str | None = None,
        limit: int = 100,
        page_token: str | None = None,
    ) -> PaginatedInstruments:
        """List instruments for an exchange with pagination.

        Args:
            exchange: Exchange code (e.g., "binance").
            search: Optional search term to filter instruments by symbol.
            base: Filter by base asset (e.g., "BTC").
            quote: Filter by quote asset (e.g., "USDT").
            instrument_type: Filter by instrument type (e.g., "spot", "perpetual").
            limit: Maximum number of instruments per page (1-1000, default 100).
            page_token: Pagination cursor from previous response.

        Returns:
            Paginated list of instruments.

        Example:
            >>> result = await client.exchanges.list_instruments("binance", base="BTC")
            >>> for inst in result.items:
            ...     print(f"{inst.symbol}: {inst.base}/{inst.quote}")
            >>> if result.has_next:
            ...     next_page = await client.exchanges.list_instruments(
            ...         "binance", base="BTC", page_token=result.next_page_token
            ...     )
        """
        response = await self._client.get(
            f"/exchanges/{exchange}/instruments",
            params={
                "search": search,
                "base": base,
                "quote": quote,
                "instrument_type": instrument_type,
                "limit": limit,
                "page_token": page_token,
            },
        )
        return PaginatedInstruments.model_validate(response.json())

    async def list_datastreams(
        self,
        exchange: str,
        instrument: str,
        *,
        stream_type: str | None = None,
        wire_format: str | None = None,
        limit: int = 100,
        page_token: str | None = None,
    ) -> PaginatedDatastreams:
        """List datastreams for an exchange and instrument.

        Args:
            exchange: Exchange code (e.g., "binance").
            instrument: Instrument symbol (e.g., "BTCUSDT").
            stream_type: Optional stream type code to filter by (e.g., "trade").
            wire_format: Optional wire format code to filter by (e.g., "json").
            limit: Maximum number of results per page (1-1000, default 100).
            page_token: Pagination cursor from previous response.

        Returns:
            Paginated list of datastreams.

        Example:
            >>> # Get all datastreams for an instrument
            >>> result = await client.exchanges.list_datastreams("binance", "BTCUSDT")
            >>> for ds in result.items:
            ...     print(f"{ds.stream_type}/{ds.wire_format}: {ds.datastream_id}")
            >>> # Filter by stream type
            >>> trades = await client.exchanges.list_datastreams(
            ...     "binance", "BTCUSDT", stream_type="trade"
            ... )
        """
        response = await self._client.get(
            f"/exchanges/{exchange}/instruments/{instrument}/datastreams",
            params={
                "stream_type": stream_type,
                "wire_format": wire_format,
                "limit": limit,
                "page_token": page_token,
            },
        )
        return PaginatedDatastreams.model_validate(response.json())
