"""Unit tests for the agentrouter Python SDK.

Uses httpx.MockTransport to stand in for the cluster: the SDK serializes
the request, MockTransport asserts on it and replies, the SDK decodes the
response into the typed protobuf message.
"""

from __future__ import annotations

import json

import httpx
import pytest

from agentrouter_sdk import Client, AgentrouterError, Endpoints, RetryPolicy


def _mock_transport(responder):
    """Wrap an httpx.MockTransport around the responder, returning an httpx.Client."""
    transport = httpx.MockTransport(responder)
    return httpx.Client(transport=transport)


# -- Construction -----------------------------------------------------


def test_rejects_both_credentials():
    with pytest.raises(AgentrouterError):
        Client(api_key="k", session_token="t")


def test_exposes_every_accessor():
    c = Client(base_url="http://127.0.0.1:1", httpx_client=httpx.Client())
    assert c.me is not None
    assert c.identity is not None
    assert c.customers is not None
    assert c.tenancy is c.customers
    assert c.projects is not None
    assert c.catalog is not None
    assert c.aikeys is not None
    assert c.inference is not None
    assert c.clients is not None
    assert c.telemetry is not None
    assert c.mcp is not None
    assert c.mcp.profiles is not None
    assert c.mcp.catalog is not None
    c.close()


# -- Catalog round-trip -----------------------------------------------


def test_list_providers_roundtrip():
    captured = {}

    def responder(request: httpx.Request) -> httpx.Response:
        captured["url"] = str(request.url)
        captured["method"] = request.method
        captured["auth"] = request.headers.get("Authorization")
        captured["xkey"] = request.headers.get("X-Api-Key")
        return httpx.Response(
            200,
            json={
                "providers": [
                    {"id": "openai", "name": "openai", "displayName": "OpenAI", "baseUrl": "https://api.openai.com"},
                ]
            },
        )

    httpc = _mock_transport(responder)
    c = Client(base_url="https://example.test", api_key="tat_live_xyz", httpx_client=httpc)
    resp = c.catalog.list_providers()
    providers = list(resp.providers)
    assert len(providers) == 1
    assert providers[0].name == "openai"
    assert captured["method"] == "POST"
    assert captured["url"] == "https://example.test/tars.catalog.v1.CatalogService/ListProviders"
    assert captured["auth"] == "tat_live_xyz"
    assert captured["xkey"] == "tat_live_xyz"


def test_session_token_sets_bearer_header():
    captured = {}

    def responder(request: httpx.Request) -> httpx.Response:
        captured["auth"] = request.headers.get("Authorization")
        captured["xkey"] = request.headers.get("X-Api-Key")
        return httpx.Response(200, json={"providers": []})

    c = Client(base_url="https://example.test", session_token="session.jwt", httpx_client=_mock_transport(responder))
    c.catalog.list_providers()
    assert captured["auth"] == "Bearer session.jwt"
    assert captured["xkey"] is None


# -- Error handling ---------------------------------------------------


def test_non_ok_raises_agentrouter_error():
    def responder(_request):
        return httpx.Response(401, json={"code": "unauthenticated", "message": "not allowed"})

    c = Client(base_url="https://example.test", httpx_client=_mock_transport(responder))
    with pytest.raises(AgentrouterError) as ei:
        c.catalog.list_providers()
    assert ei.value.code == "unauthenticated"
    assert ei.value.is_auth_required()


def test_retry_on_unavailable():
    calls = {"n": 0}

    def responder(_request):
        calls["n"] += 1
        if calls["n"] < 3:
            return httpx.Response(503, json={"code": "unavailable", "message": "flaky"})
        return httpx.Response(200, json={"providers": []})

    c = Client(
        base_url="https://example.test",
        retry=RetryPolicy(max_attempts=3, initial_backoff_s=0, max_backoff_s=0),
        httpx_client=_mock_transport(responder),
    )
    c.catalog.list_providers()
    assert calls["n"] == 3


# -- Endpoints override -----------------------------------------------


def test_endpoint_override_wins_over_base_url():
    captured = {}

    def responder(request):
        captured["url"] = str(request.url)
        return httpx.Response(200, json={"providers": []})

    c = Client(
        base_url="https://dead.test",
        endpoints=Endpoints(catalog="https://catalog.test"),
        httpx_client=_mock_transport(responder),
    )
    c.catalog.list_providers()
    assert captured["url"].startswith("https://catalog.test/")
