"""Tests for the HTTP gateway."""

from __future__ import annotations

import pytest
from starlette.testclient import TestClient

from a2a_mesh.gateway import RateLimiter, create_gateway
from a2a_mesh.mesh import Mesh
from a2a_mesh.models import AgentCard


@pytest.fixture
def mesh() -> Mesh:
    """Create a test mesh."""
    m = Mesh(port=9000, log_level="WARNING")
    m.register(AgentCard(name="test-agent", capabilities=["testing"]))
    return m


@pytest.fixture
def client(mesh: Mesh) -> TestClient:
    """Create a Starlette test client."""
    app = create_gateway(mesh)
    return TestClient(app)


class TestGateway:
    """Tests for the HTTP gateway endpoints."""

    def test_health(self, client: TestClient) -> None:
        resp = client.get("/health")
        assert resp.status_code == 200
        data = resp.json()
        assert data["status"] == "healthy"
        assert data["agents"] == 1

    def test_list_agents(self, client: TestClient) -> None:
        resp = client.get("/agents")
        assert resp.status_code == 200
        data = resp.json()
        assert len(data["agents"]) == 1
        assert data["agents"][0]["name"] == "test-agent"

    def test_register_agent(self, client: TestClient) -> None:
        resp = client.post("/agents/register", json={
            "name": "new-agent",
            "capabilities": ["new_cap"],
        })
        assert resp.status_code == 201
        data = resp.json()
        assert data["name"] == "new-agent"

    def test_register_duplicate(self, client: TestClient) -> None:
        resp = client.post("/agents/register", json={
            "name": "test-agent",
            "capabilities": ["testing"],
        })
        assert resp.status_code == 409

    def test_register_invalid(self, client: TestClient) -> None:
        resp = client.post("/agents/register", json={"invalid": True})
        assert resp.status_code == 400

    def test_jsonrpc_dispatch(self, client: TestClient) -> None:
        resp = client.post("/rpc", json={
            "jsonrpc": "2.0",
            "id": 1,
            "method": "tasks/send",
            "params": {
                "input": "test task",
                "capabilities": ["testing"],
            },
        })
        assert resp.status_code == 200
        data = resp.json()
        assert "result" in data

    def test_jsonrpc_list_agents(self, client: TestClient) -> None:
        resp = client.post("/rpc", json={
            "jsonrpc": "2.0",
            "id": 1,
            "method": "agents/list",
            "params": {},
        })
        assert resp.status_code == 200
        data = resp.json()
        assert "result" in data
        assert "agents" in data["result"]

    def test_jsonrpc_unknown_method(self, client: TestClient) -> None:
        resp = client.post("/rpc", json={
            "jsonrpc": "2.0",
            "id": 1,
            "method": "unknown/method",
            "params": {},
        })
        assert resp.status_code == 200
        data = resp.json()
        assert "error" in data

    def test_jsonrpc_invalid_json(self, client: TestClient) -> None:
        resp = client.post(
            "/rpc",
            content=b"not json",
            headers={"content-type": "application/json"},
        )
        assert resp.status_code == 400

    def test_traces_endpoint(self, client: TestClient) -> None:
        resp = client.get("/traces")
        assert resp.status_code == 200
        data = resp.json()
        assert "spans" in data
        assert "total_cost" in data


class TestRateLimiter:
    """Tests for the rate limiter."""

    def test_allows_under_limit(self) -> None:
        rl = RateLimiter(max_requests=5, window_seconds=60.0)
        for _ in range(5):
            assert rl.allow("client1") is True

    def test_blocks_over_limit(self) -> None:
        rl = RateLimiter(max_requests=2, window_seconds=60.0)
        assert rl.allow("client1") is True
        assert rl.allow("client1") is True
        assert rl.allow("client1") is False

    def test_independent_clients(self) -> None:
        rl = RateLimiter(max_requests=1, window_seconds=60.0)
        assert rl.allow("client1") is True
        assert rl.allow("client2") is True
        assert rl.allow("client1") is False
