"""Tests for boxtime.clients.coingecko_client — CoinGeckoClient."""

from types import SimpleNamespace
from unittest.mock import MagicMock, patch

import coingecko_sdk
import httpx

from boxtime.clients.coingecko_client import CoinGeckoClient, _parse_price_list
from boxtime.models.price.price import PriceHistory, PricePoint


def _make_client():
    """Create a CoinGeckoClient with a mocked SDK."""
    with patch("boxtime.clients.coingecko_client.Coingecko"):
        client = CoinGeckoClient("fake-key")
    return client


# ------------------------------------------------------------------
# get_current_price
# ------------------------------------------------------------------


def test_get_current_price():
    client = _make_client()
    client._client.simple.price.get.return_value = {
        "ergo": SimpleNamespace(usd=1.23),
    }
    result = client.get_current_price("usd")
    assert result == 1.23


def test_get_current_price_missing_coin():
    client = _make_client()
    client._client.simple.price.get.return_value = {}
    result = client.get_current_price("usd")
    assert result is None


def test_get_current_price_api_error():
    client = _make_client()
    client._client.simple.price.get.side_effect = coingecko_sdk.APIError("err", httpx.Request("GET", "http://test"), body=None)
    result = client.get_current_price("usd")
    assert result is None


# ------------------------------------------------------------------
# get_price_history
# ------------------------------------------------------------------


def test_get_price_history():
    client = _make_client()
    client._client.coins.market_chart.get.return_value = SimpleNamespace(
        prices=[[1700000000000, 1.5], [1700000060000, 1.6]]
    )
    result = client.get_price_history(7, "usd")
    assert isinstance(result, PriceHistory)
    assert len(result.prices) == 2
    assert result.prices[0].price == 1.5


def test_get_price_history_api_error():
    client = _make_client()
    client._client.coins.market_chart.get.side_effect = coingecko_sdk.APIError("err", httpx.Request("GET", "http://test"), body=None)
    result = client.get_price_history(7, "usd")
    assert result is None


# ------------------------------------------------------------------
# get_price_history_range
# ------------------------------------------------------------------


def test_get_price_history_range():
    client = _make_client()
    client._client.coins.market_chart.get_range.return_value = SimpleNamespace(
        prices=[[1700000000000, 2.0]]
    )
    result = client.get_price_history_range(1700000000, 1700100000, "usd")
    assert isinstance(result, PriceHistory)
    assert result.prices[0].price == 2.0


def test_get_price_history_range_api_error():
    client = _make_client()
    client._client.coins.market_chart.get_range.side_effect = coingecko_sdk.APIError("err", httpx.Request("GET", "http://test"), body=None)
    result = client.get_price_history_range(1700000000, 1700100000, "usd")
    assert result is None


# ------------------------------------------------------------------
# get_price_at_date
# ------------------------------------------------------------------


def test_get_price_at_date():
    client = _make_client()
    client._client.coins.history.get.return_value = SimpleNamespace(
        market_data=SimpleNamespace(
            current_price=SimpleNamespace(usd=1.75)
        )
    )
    result = client.get_price_at_date("01-01-2024", "usd")
    assert result == 1.75


def test_get_price_at_date_missing_market_data():
    client = _make_client()
    client._client.coins.history.get.return_value = SimpleNamespace(
        market_data=None
    )
    result = client.get_price_at_date("01-01-2024", "usd")
    assert result is None


def test_get_price_at_date_api_error():
    client = _make_client()
    client._client.coins.history.get.side_effect = coingecko_sdk.APIError("err", httpx.Request("GET", "http://test"), body=None)
    result = client.get_price_at_date("01-01-2024", "usd")
    assert result is None


# ------------------------------------------------------------------
# _parse_price_list
# ------------------------------------------------------------------


def test_parse_price_list_none():
    result = _parse_price_list(None, "usd")
    assert result is None


def test_parse_price_list_valid():
    raw = [[1700000000000, 1.5], [1700000060000, 1.6]]
    result = _parse_price_list(raw, "usd")
    assert isinstance(result, PriceHistory)
    assert result.coin_id == "ergo"
    assert result.vs_currency == "usd"
    assert len(result.prices) == 2
    assert result.prices[0] == PricePoint(timestamp=1700000000000, price=1.5)


def test_parse_price_list_empty():
    result = _parse_price_list([], "usd")
    assert isinstance(result, PriceHistory)
    assert result.prices == []
