"""
Integration tests for the Phase 21 API server.
Uses FastAPI's TestClient for real HTTP request/response testing.
"""

import pytest
from fastapi.testclient import TestClient


@pytest.fixture(scope="module")
def client():
    from brynq.api_server import app
    return TestClient(app)


@pytest.fixture(scope="module")
def api_key(client):
    """Register a test agent and return its API key."""
    resp = client.post("/auth/register", json={
        "name": "test-agent",
        "platform": "pytest",
        "capabilities": ["testing", "python"],
    })
    assert resp.status_code == 200
    data = resp.json()
    assert "api_key" in data
    return data["api_key"]


# ── Health & Public Endpoints ────────────────────────────────────────────


class TestPublicEndpoints:
    def test_health(self, client):
        resp = client.get("/health")
        assert resp.status_code == 200
        data = resp.json()
        assert data["status"] in ("ok", "healthy")

    def test_register_agent(self, client):
        resp = client.post("/auth/register", json={
            "name": "integration-agent",
            "platform": "claude",
            "capabilities": ["code_review"],
        })
        assert resp.status_code == 200
        data = resp.json()
        assert "api_key" in data
        assert data["name"] == "integration-agent"
        assert "session_id" in data

    def test_register_missing_name_fails(self, client):
        resp = client.post("/auth/register", json={
            "platform": "claude",
        })
        assert resp.status_code == 422  # Validation error


# ── Authenticated Endpoints ──────────────────────────────────────────────


class TestAuthenticatedEndpoints:
    def test_unauthenticated_rejected(self, client):
        resp = client.get("/channels")
        assert resp.status_code == 401

    def test_bad_key_rejected(self, client):
        resp = client.get("/channels", headers={"X-API-Key": "invalid"})
        assert resp.status_code == 403

    def test_list_channels(self, client, api_key):
        resp = client.get("/channels", headers={"X-API-Key": api_key})
        assert resp.status_code == 200
        data = resp.json()
        # API may return {"channels": [...]} or a raw list
        channels = data.get("channels", data) if isinstance(data, dict) else data
        assert isinstance(channels, list)

    def test_post_message(self, client, api_key):
        resp = client.post("/channels/test-channel/messages",
            headers={"X-API-Key": api_key},
            json={"message": "Hello from integration test", "msg_type": "info"},
        )
        assert resp.status_code == 200
        data = resp.json()
        assert data.get("ok") is True or "message_id" in data or "id" in data

    def test_read_messages(self, client, api_key):
        # Post first, then read
        client.post("/channels/test-read/messages",
            headers={"X-API-Key": api_key},
            json={"message": "Test message for reading"},
        )
        resp = client.get("/channels/test-read/messages",
            headers={"X-API-Key": api_key},
        )
        assert resp.status_code == 200
        data = resp.json()
        msgs = data.get("messages", data) if isinstance(data, dict) else data
        assert isinstance(msgs, list)
        assert len(msgs) >= 1

    def test_list_tasks(self, client, api_key):
        resp = client.get("/tasks", headers={"X-API-Key": api_key})
        assert resp.status_code == 200
        data = resp.json()
        tasks = data.get("tasks", data) if isinstance(data, dict) else data
        assert isinstance(tasks, list)

    def test_create_task(self, client, api_key):
        resp = client.post("/tasks",
            headers={"X-API-Key": api_key},
            json={
                "title": "Integration test task",
                "description": "Created by pytest",
                "priority": "normal",
            },
        )
        assert resp.status_code == 200
        data = resp.json()
        assert "task_id" in data

    def test_list_agents(self, client, api_key):
        resp = client.get("/agents", headers={"X-API-Key": api_key})
        assert resp.status_code == 200
        data = resp.json()
        agents = data.get("agents", data) if isinstance(data, dict) else data
        assert isinstance(agents, list)
        assert len(agents) >= 1

    def test_inbox(self, client, api_key):
        resp = client.get("/inbox", headers={"X-API-Key": api_key})
        assert resp.status_code == 200

    def test_stats(self, client, api_key):
        resp = client.get("/stats", headers={"X-API-Key": api_key})
        assert resp.status_code == 200
        data = resp.json()
        assert isinstance(data, dict)


# ── Hardware Declaration ─────────────────────────────────────────────────


class TestHardware:
    def test_declare_hardware(self, client, api_key):
        resp = client.put("/agents/me/hardware",
            headers={"X-API-Key": api_key},
            json={"gpu": "RTX4090", "ram_gb": 32, "cpu_cores": 16},
        )
        assert resp.status_code == 200


# ── Task Lifecycle ──────────────────────────────────────────────────────


class TestTaskLifecycle:
    def test_create_accept_complete(self, client, api_key):
        """Full task lifecycle: create -> accept -> complete."""
        headers = {"X-API-Key": api_key}
        # Create
        create_resp = client.post("/tasks", headers=headers, json={
            "title": "Lifecycle test task",
            "priority": "high",
        })
        assert create_resp.status_code == 200
        task_id = create_resp.json().get("task_id", "")
        assert task_id

        # Accept
        accept_resp = client.post(f"/tasks/{task_id}/accept", headers=headers)
        assert accept_resp.status_code == 200

        # Complete
        complete_resp = client.post(f"/tasks/{task_id}/complete", headers=headers)
        assert complete_resp.status_code == 200

    def test_accept_nonexistent_task(self, client, api_key):
        headers = {"X-API-Key": api_key}
        resp = client.post("/tasks/nonexistent_xyz/accept", headers=headers)
        assert resp.status_code in (200, 400, 404)


# ── Capabilities ────────────────────────────────────────────────────────


class TestCapabilities:
    def test_list_capabilities(self, client, api_key):
        headers = {"X-API-Key": api_key}
        resp = client.get("/capabilities", headers=headers)
        assert resp.status_code == 200

    def test_find_capability(self, client, api_key):
        headers = {"X-API-Key": api_key}
        resp = client.get("/capabilities/find?skill=python", headers=headers)
        assert resp.status_code == 200


# ── Leaderboard ─────────────────────────────────────────────────────────


class TestLeaderboard:
    def test_leaderboard(self, client, api_key):
        headers = {"X-API-Key": api_key}
        resp = client.get("/leaderboard", headers=headers)
        assert resp.status_code == 200
        data = resp.json()
        assert isinstance(data, (list, dict))


# ── Edge Cases ──────────────────────────────────────────────────────────


class TestEdgeCases:
    def test_empty_channel_messages(self, client, api_key):
        headers = {"X-API-Key": api_key}
        resp = client.get("/channels/totally-empty-channel/messages", headers=headers)
        assert resp.status_code == 200
        data = resp.json()
        assert data.get("total", 0) == 0

    def test_get_specific_agent(self, client, api_key):
        """Register then lookup by session_id."""
        headers = {"X-API-Key": api_key}
        # Register a new agent to get a known session_id
        reg = client.post("/auth/register", json={
            "name": "lookup-target",
            "platform": "test",
        })
        sid = reg.json()["session_id"]
        resp = client.get(f"/agents/{sid}", headers=headers)
        assert resp.status_code == 200

    def test_post_message_all_types(self, client, api_key):
        """Verify all message types are accepted."""
        headers = {"X-API-Key": api_key}
        for msg_type in ["info", "request", "alert", "status", "question"]:
            resp = client.post("/channels/type-test/messages", headers=headers, json={
                "message": f"Testing {msg_type}",
                "msg_type": msg_type,
            })
            assert resp.status_code == 200, f"Failed for msg_type={msg_type}"
