"""CoinGecko price client for ERG market data."""

import logging
from typing import Optional

import coingecko_sdk
from coingecko_sdk import Coingecko

from boxtime.models.price.price import PriceHistory, PricePoint

logger = logging.getLogger(__name__)

COIN_ID = "ergo"


class CoinGeckoClient:
    """
    Client for fetching ERG price data from the CoinGecko API.

    Uses the official ``coingecko-sdk`` library.  A free Demo API key
    is required and can be obtained at https://www.coingecko.com/en/api

    :param api_key: CoinGecko Demo API key.
    """

    def __init__(self, api_key: str):
        self._client = Coingecko(
            demo_api_key=api_key, environment="demo"
        )

    # ------------------------------------------------------------------
    # Current price
    # ------------------------------------------------------------------

    def get_current_price(self, vs_currency: str = "usd") -> Optional[float]:
        """Return the current ERG price in *vs_currency*."""
        try:
            data = self._client.simple.price.get(
                ids=COIN_ID, vs_currencies=vs_currency
            )
            item = data.get(COIN_ID)
            if item is None:
                return None
            return getattr(item, vs_currency, None)
        except coingecko_sdk.APIError as exc:
            logger.error("CoinGecko API error: %s", exc)
            return None

    # ------------------------------------------------------------------
    # Historical prices
    # ------------------------------------------------------------------

    def get_price_history(
        self, days: int, vs_currency: str = "usd"
    ) -> Optional[PriceHistory]:
        """
        Return ERG price history for the last *days* days.

        Granularity is determined automatically by CoinGecko:
        ≤1 day → 5-min, 1–90 days → hourly, >90 days → daily.
        """
        try:
            data = self._client.coins.market_chart.get(
                COIN_ID, days=str(days), vs_currency=vs_currency
            )
            return _parse_price_list(data.prices, vs_currency)
        except coingecko_sdk.APIError as exc:
            logger.error("CoinGecko API error: %s", exc)
            return None

    def get_price_history_range(
        self, from_ts: int, to_ts: int, vs_currency: str = "usd"
    ) -> Optional[PriceHistory]:
        """
        Return ERG price history between two UNIX timestamps (seconds).
        """
        try:
            data = self._client.coins.market_chart.get_range(
                COIN_ID,
                from_=str(from_ts),
                to=str(to_ts),
                vs_currency=vs_currency,
            )
            return _parse_price_list(data.prices, vs_currency)
        except coingecko_sdk.APIError as exc:
            logger.error("CoinGecko API error: %s", exc)
            return None

    # ------------------------------------------------------------------
    # Price at a specific date
    # ------------------------------------------------------------------

    def get_price_at_date(
        self, date: str, vs_currency: str = "usd"
    ) -> Optional[float]:
        """
        Return the ERG price on a specific *date* (``dd-mm-yyyy`` format).
        """
        try:
            data = self._client.coins.history.get(
                COIN_ID, date=date, localization=False
            )
            if data.market_data is None or data.market_data.current_price is None:
                return None
            return getattr(data.market_data.current_price, vs_currency, None)
        except coingecko_sdk.APIError as exc:
            logger.error("CoinGecko API error: %s", exc)
            return None


# ------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------


def _parse_price_list(
    raw_prices: Optional[list], vs_currency: str
) -> Optional[PriceHistory]:
    """Convert ``[[unix_ms, price], ...]`` into a ``PriceHistory``."""
    if raw_prices is None:
        return None
    points = [
        PricePoint(timestamp=int(pair[0]), price=pair[1])
        for pair in raw_prices
    ]
    return PriceHistory(
        coin_id=COIN_ID, vs_currency=vs_currency, prices=points
    )
