"""
Smoke tests for the hosted MCP server HTTP (streamable-http) transport.

Connects to the live server via the MCP streamable-http client and verifies
the health endpoint, tool listing, and tool invocation over the wire. These
tests only verify that the HTTP transport and deployed server are working —
that tools are advertised and callable via the protocol. Tool correctness
(CRUD, error handling, all operations) is covered by test_server_e2e.py.

All tests are @pytest.mark.integration and skip when SHAPED_MCP_URL is not set
(e.g. on PRs and unit-test-only runs). Requires both SHAPED_MCP_URL and
SHAPED_API_KEY to be set for the async transport tests.
"""

import json
import os

import httpx
import pytest

from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamablehttp_client

MCP_URL = os.environ.get("SHAPED_MCP_URL", "")
API_KEY = os.environ.get("SHAPED_API_KEY", "")

pytestmark = pytest.mark.skipif(not MCP_URL, reason="SHAPED_MCP_URL not set")


@pytest.mark.integration
def test_http_health_endpoint():
    """GET /health returns {"status": "ok"}."""
    response = httpx.get(f"{MCP_URL}/health", timeout=10)
    assert response.status_code == 200
    assert response.json()["status"] == "ok"


@pytest.mark.integration
async def test_http_list_tools():
    """Connect via streamable-http and verify expected tools are advertised."""
    headers = {"Authorization": f"Bearer {API_KEY}"}
    async with streamablehttp_client(MCP_URL, headers=headers) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()
            result = await session.list_tools()
            tool_names = {t.name for t in result.tools}
            assert "shaped_list_engines" in tool_names
            assert "shaped_query" in tool_names
            assert "shaped_fetch_docs" in tool_names


@pytest.mark.integration
async def test_http_list_resources():
    """Connect via streamable-http and verify expected resources are advertised."""
    headers = {"Authorization": f"Bearer {API_KEY}"}
    async with streamablehttp_client(MCP_URL, headers=headers) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()
            result = await session.list_resources()
            uris = {str(r.uri) for r in result.resources}
            assert "shaped://account" in uris
            assert "shaped://docs/shapedql" in uris


@pytest.mark.integration
async def test_http_list_prompts():
    """Connect via streamable-http and verify expected prompts are advertised."""
    headers = {"Authorization": f"Bearer {API_KEY}"}
    async with streamablehttp_client(MCP_URL, headers=headers) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()
            result = await session.list_prompts()
            prompt_names = {p.name for p in result.prompts}
            assert "shaped-build-query" in prompt_names
            assert "shaped-engine-data-summary" in prompt_names


@pytest.mark.integration
async def test_http_call_validate_engine_config():
    """Call shaped_validate_engine_config via MCP HTTP transport end-to-end.

    Uses offline validation (no Shaped API call) so the test checks transport
    and tool dispatch only. Hosted HTTP sessions run the MCP loop in a separate
    task where Bearer auth may not reach _get_client(); list_engines would hit
    the API with the wrong key. Full API coverage stays in test_server_e2e.py.
    """
    headers = {"Authorization": f"Bearer {API_KEY}"}
    minimal_valid = json.dumps(
        {"version": "v2", "name": "http_smoke_engine", "data": {}}
    )
    async with streamablehttp_client(MCP_URL, headers=headers) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()
            result = await session.call_tool(
                "shaped_validate_engine_config",
                {"engine_config": minimal_valid},
            )
            data = json.loads(result.content[0].text)
            assert data.get("valid") is True
            assert "parsed" in data
