"""Client for prediction market endpoints (series, markets, candles, lob)."""

from __future__ import annotations

from pathlib import Path
from typing import Any

from therminal._http import HttpSession, normalize_date, to_dataframe
from therminal.config import TherminalConfig
from therminal.models import Candle, LOBSnapshot, Market, Series


class MarketsClient:
    """Client for prediction market endpoints."""

    def __init__(
        self,
        config: TherminalConfig | None = None,
        _session: HttpSession | None = None,
    ) -> None:
        """Create a MarketsClient.

        Args:
            config: SDK configuration. If None, loads from default locations.
            _session: Shared HttpSession (internal, for facade pattern).
        """
        self._config = config or TherminalConfig()
        self._http = _session or HttpSession(self._config)
        self._owns_session = _session is None

    def close(self) -> None:
        """Close the underlying HTTP session if owned."""
        if self._owns_session:
            self._http.close()

    def __enter__(self) -> MarketsClient:
        return self

    def __exit__(self, *a: Any) -> None:
        self.close()

    # ── Series ───────────────────────────────────────────────

    def series(
        self,
        active: bool | None = None,
        limit: int = 100,
        offset: int = 0,
        as_dataframe: bool = False,
    ) -> list[Series] | Any:
        """List event series.

        Args:
            active: Filter by active status.
            limit: Max results (default 100).
            offset: Pagination offset.
            as_dataframe: Return as Pandas DataFrame.

        Returns:
            list[Series] or DataFrame if as_dataframe.
        """
        params: dict[str, Any] = {
            "active": str(active).lower() if active is not None else None,
            "limit": limit,
            "offset": offset,
        }
        data = self._http.get("/api/v1/series", params)

        if as_dataframe:
            return to_dataframe(data)

        return [Series.from_api_dict(d) for d in data]

    def series_detail(self, ticker: str) -> Series:
        """Get a single series by ticker.

        Args:
            ticker: Series ticker string.

        Returns:
            Series dataclass instance.
        """
        data = self._http.get(f"/api/v1/series/{ticker}")
        return Series.from_api_dict(data)

    # ── Markets ──────────────────────────────────────────────

    def markets(
        self,
        series: str | None = None,
        station: str | None = None,
        from_date: str | None = None,
        to_date: str | None = None,
        limit: int = 1000,
        offset: int = 0,
        as_dataframe: bool = False,
    ) -> list[Market] | Any:
        """List markets.

        Args:
            series: Filter by series ticker.
            station: Filter by station code.
            from_date: Filter by close_time >= (RFC3339 or YYYY-MM-DD).
            to_date: Filter by close_time <= (RFC3339 or YYYY-MM-DD).
            limit: Max results (default 1000).
            offset: Pagination offset.
            as_dataframe: Return as Pandas DataFrame.

        Returns:
            list[Market] or DataFrame if as_dataframe.
        """
        resolved = self._config.resolve(station=station)
        params: dict[str, Any] = {
            "series": series,
            "station": resolved["station"],
            "from": normalize_date(from_date),
            "to": normalize_date(to_date),
            "limit": limit,
            "offset": offset,
        }
        data = self._http.get("/api/v1/markets", params)

        if as_dataframe:
            return to_dataframe(data)

        return [Market.from_api_dict(d) for d in data]

    def market(self, ticker: str) -> Market:
        """Get a single market by ticker.

        Args:
            ticker: Market ticker string.

        Returns:
            Market dataclass instance.
        """
        data = self._http.get(f"/api/v1/markets/{ticker}")
        return Market.from_api_dict(data)

    # ── Candles ──────────────────────────────────────────────

    def candles(
        self,
        market: str | None = None,
        event: str | None = None,
        station: str | None = None,
        series: str | None = None,
        from_date: str | None = None,
        to_date: str | None = None,
        interval: int | None = None,
        fill: bool = True,
        aggregate: int | None = None,
        tz: str | None = None,
        format: str | None = None,
        columns: list[str] | None = None,
        limit: int = 10000,
        offset: int = 0,
        as_dataframe: bool = False,
        save_path: str | Path | None = None,
    ) -> list[Candle] | Path | Any:
        """Get OHLCV candles for prediction markets.

        Args:
            market: Market ticker (e.g., KXHIGHNY-26MAR20-T50).
            event: Event ticker.
            station: Station code (e.g., NYC).
            series: Series ticker.
            from_date: Start date (RFC3339 or YYYY-MM-DD).
            to_date: End date (RFC3339 or YYYY-MM-DD).
            interval: Candle interval in minutes (1, 5, 15, 30, 60, 1440).
            fill: Forward-fill gaps (default True).
            aggregate: Aggregate to larger interval (minutes).
            tz: Timezone (UTC, station, or IANA name).
            format: Output format: None/json (default), csv, parquet.
            columns: List of columns to include (e.g., ["close", "volume"]).
            as_dataframe: Return as Pandas DataFrame.
            save_path: File path for csv/parquet output.

        Returns:
            list[Candle] for JSON, Path for csv/parquet, DataFrame if as_dataframe.
        """
        resolved = self._config.resolve(tz=tz)
        params: dict[str, Any] = {
            "market": market,
            "event": event,
            "station": station,
            "series": series,
            "from": normalize_date(from_date),
            "to": normalize_date(to_date),
            "interval": interval,
            "fill": "false" if not fill else None,
            "aggregate": aggregate,
            "tz": resolved["tz"],
            "offset": offset,
        }

        if format in ("csv", "parquet"):
            params["limit"] = limit
            return self._http.handle_format(
                "/api/v1/candles", params, format, columns,
                as_dataframe, "end_period_ts", "candles", save_path,
            )

        # JSON path
        if limit != 10000:
            params["limit"] = limit
        if columns:
            params["columns"] = ",".join(columns)
        data = self._http.get_all("/api/v1/candles", params)

        if as_dataframe:
            return to_dataframe(data, index_col="end_period_ts")

        return [Candle.from_api_dict(d) for d in data]

    # ── LOB (Limit Order Book) ───────────────────────────────

    def lob(
        self,
        market: str | None = None,
        series: str | None = None,
        source: str = "kalshi",
        date: str | None = None,
        from_date: str | None = None,
        to_date: str | None = None,
        interval: int = 60,
        levels: int = 10,
        hour: int | None = None,
        format: str | None = None,
        columns: list[str] | None = None,
        as_dataframe: bool = False,
        save_path: str | Path | None = None,
    ) -> list[LOBSnapshot] | Path | Any:
        """Get limit order book snapshots.

        Reconstructs order book state from delta data at the specified
        snapshot interval. Returns bid/ask levels at each timestamp.

        Args:
            market: Market ticker (e.g. 'KXHIGHNY-26MAR04-B51').
            series: Series ticker to get all markets in series.
            source: Data source -- 'kalshi' (default) or 'polymarket'.
            date: Single date (YYYY-MM-DD).
            from_date: Range start (YYYY-MM-DD).
            to_date: Range end (YYYY-MM-DD, max 31 days from start).
            interval: Snapshot frequency in seconds (1-3600, default 60).
            levels: Book depth per side (1-50, default 10).
            hour: Filter to single hour (0-23).
            format: Response format -- 'json', 'csv', 'parquet', 'ndjson'.
            columns: Subset of fields to return (csv/parquet only).
            as_dataframe: Return as Pandas DataFrame.
            save_path: File path for csv/parquet output.

        Returns:
            list[LOBSnapshot] for JSON, Path for csv/parquet, DataFrame if as_dataframe.
        """
        params: dict[str, Any] = {
            "market": market,
            "series": series,
            "source": source,
            "date": date,
            "from": from_date,
            "to": to_date,
            "interval": interval,
            "levels": levels,
            "hour": hour,
        }

        if format in ("csv", "parquet"):
            return self._http.handle_format(
                "/api/v1/lob", params, format, columns,
                as_dataframe, "ts", "lob", save_path,
            )

        # JSON path
        if columns:
            params["columns"] = ",".join(columns)
        data = self._http.get_all("/api/v1/lob", params)

        if as_dataframe:
            return to_dataframe(data, index_col="ts")

        return [LOBSnapshot.from_api_dict(d) for d in data]
