"""
MCP Protocol Integration Test
==============================

Verifies that the Entroly MCP server actually speaks JSON-RPC over stdio.
This catches issues that unit tests miss — like broken tool registration,
import errors at startup, or malformed responses.
"""

import json
import subprocess
import sys
import time
import pytest


def _send_jsonrpc(proc, method, params=None, id=1):
    """Send a JSON-RPC request and read the response."""
    request = {
        "jsonrpc": "2.0",
        "method": method,
        "id": id,
    }
    if params is not None:
        request["params"] = params

    msg = json.dumps(request)
    # MCP uses Content-Length header framing
    header = f"Content-Length: {len(msg)}\r\n\r\n"
    proc.stdin.write(header + msg)
    proc.stdin.flush()


def _read_response(proc, timeout=10):
    """Read a JSON-RPC response with Content-Length framing."""
    import select
    start = time.time()

    # Read headers
    headers = ""
    while time.time() - start < timeout:
        line = proc.stdout.readline()
        if not line:
            time.sleep(0.05)
            continue
        headers += line
        if headers.endswith("\r\n\r\n") or headers.endswith("\n\n"):
            break

    # Parse Content-Length
    content_length = 0
    for h in headers.strip().split("\n"):
        if h.lower().startswith("content-length:"):
            content_length = int(h.split(":")[1].strip())
            break

    if content_length == 0:
        return None

    # Read body
    body = proc.stdout.read(content_length)
    return json.loads(body)


@pytest.fixture(scope="module")
def mcp_server():
    """Start the MCP server as a subprocess."""
    proc = subprocess.Popen(
        [sys.executable, "-m", "entroly.server"],
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True,
        env={
            **__import__("os").environ,
            "ENTROLY_NO_DOCKER": "1",
        },
    )
    time.sleep(2)  # Give it time to start

    # Check it didn't crash
    if proc.poll() is not None:
        stderr = proc.stderr.read()
        pytest.skip(f"MCP server failed to start: {stderr[:500]}")

    yield proc

    proc.terminate()
    try:
        proc.wait(timeout=5)
    except subprocess.TimeoutExpired:
        proc.kill()


def test_mcp_server_starts(mcp_server):
    """The MCP server process should be running."""
    assert mcp_server.poll() is None, "MCP server process died"


def test_mcp_initialize(mcp_server):
    """Send initialize request and verify the server responds."""
    _send_jsonrpc(mcp_server, "initialize", {
        "protocolVersion": "2024-11-05",
        "capabilities": {},
        "clientInfo": {"name": "test", "version": "1.0"},
    })

    response = _read_response(mcp_server)
    if response is None:
        pytest.skip("MCP server did not respond to initialize (may use different framing)")

    assert "result" in response or "error" in response
    if "result" in response:
        assert "serverInfo" in response["result"]


def test_mcp_list_tools(mcp_server):
    """Request the list of available tools."""
    _send_jsonrpc(mcp_server, "tools/list", {}, id=2)

    response = _read_response(mcp_server)
    if response is None:
        pytest.skip("No response to tools/list")

    if "result" in response:
        tools = response["result"].get("tools", [])
        tool_names = [t["name"] for t in tools]
        # Verify core tools are registered
        assert "remember_fragment" in tool_names or "optimize_context" in tool_names, (
            f"Expected core tools, got: {tool_names}"
        )
