"""Tests for TherminalClient."""

import pytest
from pytest_httpx import HTTPXMock

from therminal import NotFoundError, RateLimitError, ServerError, TherminalClient, ValidationError

# ── Health ───────────────────────────────────────────────────

def test_health(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json={"status": "ok", "duckdb": "ok", "supabase": "ok"})
    result = client.health()
    assert result["status"] == "ok"
    assert result["duckdb"] == "ok"


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

def test_series_list(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json=[
        {"ticker": "KXHIGHNY", "measure_type": "high", "station_code": "NYC", "active": True},
    ])
    result = client.series()
    assert len(result) == 1
    assert result[0]["ticker"] == "KXHIGHNY"


def test_series_detail(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json={"ticker": "KXHIGHNY", "station_code": "NYC"})
    result = client.series_detail("KXHIGHNY")
    assert result["ticker"] == "KXHIGHNY"


def test_series_not_found(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(status_code=404, json={"error": "series not found"})
    with pytest.raises(NotFoundError):
        client.series_detail("NONEXISTENT")


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

def test_markets_list(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json=[
        {"ticker": "KXHIGHNY-26MAR20-T50", "series_ticker": "KXHIGHNY", "status": "active"},
    ])
    result = client.markets(series="KXHIGHNY")
    assert len(result) == 1


def test_market_detail(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json={"ticker": "KXHIGHNY-26MAR20-T50", "status": "active"})
    result = client.market("KXHIGHNY-26MAR20-T50")
    assert result["status"] == "active"


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

def test_candles(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json=[
        {"market_ticker": "T1", "period_interval": 5, "end_period_ts": "2026-03-20T10:00:00Z",
         "open": 42, "high": 45, "low": 40, "close": 43, "volume": 100, "open_interest": 500,
         "filled": False},
    ])
    result = client.candles(market="T1", from_date="2026-03-20", to_date="2026-03-20")
    assert len(result) == 1
    assert result[0]["open"] == 42


def test_candles_date_normalization(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json=[])
    client.candles(from_date="2026-03-01", to_date="2026-03-20")
    request = httpx_mock.get_request()
    assert "from=2026-03-01T00%3A00%3A00Z" in str(request.url)


def test_candles_fill_false(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json=[])
    client.candles(fill=False)
    request = httpx_mock.get_request()
    assert "fill=false" in str(request.url)


# ── Observations ─────────────────────────────────────────────

def test_observations(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json=[
        {"station_code": "NYC", "observed_at": "2026-03-20T12:00:00Z",
         "observation_type": "METAR", "temp_f": 51.1},
    ])
    result = client.observations(station="NYC")
    assert result[0]["temp_f"] == 51.1


def test_observations_metric(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json=[])
    client.observations(station="NYC", units="metric")
    request = httpx_mock.get_request()
    assert "units=metric" in str(request.url)


# ── Climate ──────────────────────────────────────────────────

def test_climate(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json=[
        {"station_code": "NYC", "observation_date": "2026-03-19",
         "high_temp_f": 44, "low_temp_f": 32, "report_type": "final"},
    ])
    result = client.climate(station="NYC", from_date="2026-03-19")
    assert result[0]["high_temp_f"] == 44


# ── Climate Gaps ─────────────────────────────────────────────

def test_climate_gaps(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json=[
        {
            "station_code": "NYC", "gap_start": "2026-03-20",
            "gap_end": "2026-03-20", "missing_days": 1,
        },
    ])
    result = client.climate_gaps(station="NYC")
    assert result[0]["missing_days"] == 1


# ── Downloads ────────────────────────────────────────────────

def test_download_parquet(httpx_mock: HTTPXMock, client: TherminalClient, tmp_path):
    httpx_mock.add_response(json={
        "url": "https://r2.example.com/test.parquet",
        "key": "test", "expires_in": "5m",
    })
    httpx_mock.add_response(content=b"PARQUET_BYTES")

    out = tmp_path / "test.parquet"
    path = client.download_parquet(
        "observations", station="NYC", year=2024, path=out,
    )
    assert path.exists()
    assert path.read_bytes() == b"PARQUET_BYTES"


# ── Error Handling ───────────────────────────────────────────

def test_rate_limit(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(
        status_code=429,
        headers={"Retry-After": "5"},
        json={"error": "rate limit exceeded"},
    )
    with pytest.raises(RateLimitError) as exc_info:
        client.health()
    assert exc_info.value.retry_after == 5


def test_validation_error(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(status_code=400, json={"error": "interval must be an integer"})
    with pytest.raises(ValidationError):
        client.candles(interval=999)


def test_server_error(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(status_code=500, json={"error": "internal server error"})
    with pytest.raises(ServerError):
        client.health()


# ── DataFrame ────────────────────────────────────────────────

def test_as_dataframe(httpx_mock: HTTPXMock, client: TherminalClient):
    httpx_mock.add_response(json=[
        {"market_ticker": "T1", "end_period_ts": "2026-03-20T10:00:00Z", "open": 42,
         "high": 45, "low": 40, "close": 43, "volume": 100, "open_interest": 500, "filled": False},
        {"market_ticker": "T1", "end_period_ts": "2026-03-20T10:05:00Z", "open": 43,
         "high": 46, "low": 41, "close": 44, "volume": 50, "open_interest": 510, "filled": False},
    ])
    df = client.candles(as_dataframe=True)
    assert df.index.name == "end_period_ts"
    assert len(df) == 2
    assert df.iloc[0]["open"] == 42


# ── Context Manager ──────────────────────────────────────────

def test_context_manager(httpx_mock: HTTPXMock):
    httpx_mock.add_response(json={"status": "ok"})
    with TherminalClient(base_url="https://test.api") as client:
        result = client.health()
    assert result["status"] == "ok"


# ── Helpers ──────────────────────────────────────────────────

def test_normalize_date():
    assert TherminalClient._normalize_date(None) is None
    assert TherminalClient._normalize_date("2026-03-01") == "2026-03-01T00:00:00Z"
    assert TherminalClient._normalize_date("2026-03-01T12:00:00Z") == "2026-03-01T12:00:00Z"
