"""Sirius Prediction Market API client — zero dependencies."""

import json
import urllib.request
import urllib.error
import urllib.parse
from typing import Any, Dict, List, Optional, Union

from sirius_prediction_api.exceptions import (
    SiriusAPIError,
    SiriusAuthError,
    SiriusForbiddenError,
    SiriusNotFoundError,
    SiriusRateLimitError,
    SiriusServerError,
)

_BASE_URL = "https://sirius-prediction-market-api.p.rapidapi.com"
_HOST = "sirius-prediction-market-api.p.rapidapi.com"


class SiriusAPI:
    """Client for the Sirius Prediction Market API.

    Args:
        api_key: Your RapidAPI key.
        base_url: Override the default API base URL (for testing).
        timeout: Request timeout in seconds. Defaults to 30.

    Example::

        api = SiriusAPI("your-rapidapi-key")
        print(api.health())
        markets = api.markets()
        for m in markets:
            print(m["question"], m["odds"])
    """

    def __init__(
        self,
        api_key: str,
        base_url: str = _BASE_URL,
        timeout: int = 30,
    ) -> None:
        if not api_key:
            raise ValueError("api_key must be a non-empty string")
        self._api_key = api_key
        self._base_url = base_url.rstrip("/")
        self._timeout = timeout

    # ------------------------------------------------------------------
    # Internal helpers
    # ------------------------------------------------------------------

    def _request(
        self,
        path: str,
        params: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Perform a GET request and return the parsed JSON response."""
        url = self._base_url + path
        if params:
            # Filter out None values so callers can pass optionals directly
            filtered = {k: v for k, v in params.items() if v is not None}
            if filtered:
                url += "?" + urllib.parse.urlencode(filtered)

        headers = {
            "X-RapidAPI-Key": self._api_key,
            "X-RapidAPI-Host": _HOST,
            "Accept": "application/json",
        }

        req = urllib.request.Request(url, headers=headers, method="GET")

        try:
            with urllib.request.urlopen(req, timeout=self._timeout) as resp:
                body = resp.read().decode("utf-8")
                return json.loads(body) if body else {}
        except urllib.error.HTTPError as exc:
            body = ""
            try:
                body = exc.read().decode("utf-8", errors="replace")
            except Exception:
                pass

            msg = "API request failed"
            # Try to extract a message from JSON body
            try:
                data = json.loads(body)
                if isinstance(data, dict):
                    msg = data.get("message", data.get("error", msg))
            except (json.JSONDecodeError, ValueError):
                if body:
                    msg = body[:200]

            code = exc.code
            if code == 401:
                raise SiriusAuthError(msg, code, body) from exc
            if code == 403:
                raise SiriusForbiddenError(msg, code, body) from exc
            if code == 404:
                raise SiriusNotFoundError(msg, code, body) from exc
            if code == 429:
                raise SiriusRateLimitError(msg, code, body) from exc
            if code >= 500:
                raise SiriusServerError(msg, code, body) from exc
            raise SiriusAPIError(msg, code, body) from exc
        except urllib.error.URLError as exc:
            raise SiriusAPIError(
                "Connection error: {}".format(exc.reason)
            ) from exc

    # ------------------------------------------------------------------
    # Public API — Free tier
    # ------------------------------------------------------------------

    def health(self) -> Dict[str, Any]:
        """Check API status.

        Returns:
            Dict with API health information.
        """
        result = self._request("/v1/health")
        return result  # type: ignore[return-value]

    def markets(
        self,
        category: Optional[str] = None,
        min_liquidity: Optional[float] = None,
        limit: Optional[int] = None,
        offset: Optional[int] = None,
    ) -> Any:
        """Get active prediction markets with current odds.

        Args:
            category: Filter by market category.
            min_liquidity: Minimum liquidity threshold.
            limit: Maximum number of markets to return.
            offset: Number of items to skip for pagination.

        Returns:
            List of market objects with questions, odds, and metadata.
        """
        return self._request(
            "/v1/markets",
            params={
                "category": category,
                "min_liquidity": min_liquidity,
                "limit": limit,
                "offset": offset,
            },
        )

    def signals(
        self,
        limit: Optional[int] = None,
        layer: Optional[str] = None,
        min_gap: Optional[float] = None,
        source: Optional[str] = None,
        sort_by: Optional[str] = None,
        offset: Optional[int] = None,
    ) -> Any:
        """Get current trading signals.

        Args:
            limit: Maximum number of signals to return.
            layer: Filter by signal layer (e.g. ``"L1"``, ``"L2"``).
            min_gap: Minimum price gap to filter signals.
            source: Filter by source (comma-separated): price_lag, news, weather, kalshi, espn, manifold, odds_api, predictit.
            sort_by: Sort by: "time", "gap", "confidence" (default: "time").
            offset: Number of items to skip for pagination.

        Returns:
            List of trading signal objects.
        """
        return self._request(
            "/v1/signals",
            params={
                "limit": limit,
                "layer": layer,
                "min_gap": min_gap,
                "source": source,
                "sort_by": sort_by,
                "offset": offset,
            },
        )

    def signals_history(
        self,
        layer: Optional[str] = None,
        limit: Optional[int] = None,
        offset: Optional[int] = None,
    ) -> Any:
        """Get historical trading signals.

        Args:
            layer: Filter by signal layer (e.g. ``"L1"``, ``"L2"``).
            limit: Maximum number of signals to return.
            offset: Number of items to skip for pagination.

        Returns:
            List of past signal objects with outcomes.
        """
        return self._request(
            "/v1/signals/history",
            params={"layer": layer, "limit": limit, "offset": offset},
        )

    def sentiment(self) -> Dict[str, Any]:
        """Get market sentiment data.

        Returns Fear & Greed indices (CoinMarketCap, Alternative.me)
        and Binance Futures long/short ratios.

        Returns:
            Dict with sentiment indicators.
        """
        result = self._request("/v1/sentiment")
        return result  # type: ignore[return-value]

    def sports(self) -> Any:
        """Get sports odds from ESPN and Kalshi.

        Returns:
            List of upcoming sports events with odds.
        """
        return self._request("/v1/sports")

    def weather(self) -> Any:
        """Get weather-related prediction data.

        Returns:
            Weather forecast data relevant to prediction markets.
        """
        return self._request("/v1/weather")

    def odds(self) -> Any:
        """Get cross-platform odds comparison.

        Returns:
            Odds data across multiple prediction platforms.
        """
        return self._request("/v1/odds")

    # ------------------------------------------------------------------
    # Public API — Basic tier
    # ------------------------------------------------------------------

    def performance(self) -> Dict[str, Any]:
        """Get bot performance / track record (Basic tier).

        Returns:
            Dict with win rate, PnL, and other performance metrics.

        Raises:
            SiriusForbiddenError: If your subscription does not include
                this endpoint.
        """
        result = self._request("/v1/performance")
        return result  # type: ignore[return-value]

    def trades(self) -> Any:
        """Get trade history (Basic tier).

        Returns:
            List of executed trades with entry/exit details.

        Raises:
            SiriusForbiddenError: If your subscription does not include
                this endpoint.
        """
        return self._request("/v1/trades")

    # ------------------------------------------------------------------
    # Public API — Pro tier
    # ------------------------------------------------------------------

    def performance_history(self) -> Dict[str, Any]:
        """Get equity curve / daily PnL history (Pro tier).

        Returns:
            Dict with daily_pnl, cumulative, total_days.

        Raises:
            SiriusForbiddenError: If your subscription does not include
                this endpoint.
        """
        result = self._request("/v1/performance/history")
        return result  # type: ignore[return-value]

    def brain(self) -> Dict[str, Any]:
        """Get AI brain decisions and reasoning (Pro tier).

        Returns:
            Dict with AI optimization parameters and rationale.

        Raises:
            SiriusForbiddenError: If your subscription does not include
                this endpoint.
        """
        result = self._request("/v1/brain")
        return result  # type: ignore[return-value]
