"""
Testy integracyjne Gateway.

Testują wyłącznie zachowanie warstwy MCP (tools/list, tools/call przez protokół).
Nie powtarzają testów Registry, Executor, ConnectionPool.
"""

import threading
import time

import httpx
import pytest
import uvicorn

from ..connection_pool import ConnectionPool
from ..executor import Executor
from ..gateway import Gateway
from ..models import Backend, ToolDefinition
from ..registry import Registry

GATEWAY_HOST = "127.0.0.1"
GATEWAY_PORT = 18124
GATEWAY_URL = f"http://{GATEWAY_HOST}:{GATEWAY_PORT}/mcp/"


@pytest.fixture(scope="module")
def gateway_url(mcp_server_url):
    """Uruchamia Gateway z jednym zarejestrowanym backendem testowym."""
    registry = Registry()
    pool = ConnectionPool()
    executor = Executor(pool)
    gateway = Gateway(registry, executor)

    # Rejestrujemy backend ręcznie (bez Orchestratora) — nie testujemy go tutaj
    backend = Backend(id="test", url=mcp_server_url)
    registry.add_backend(backend)
    for name, description, schema in [
        ("echo", "Zwraca podany tekst", {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]}),
        ("add", "Dodaje dwie liczby", {"type": "object", "properties": {"a": {"type": "integer"}, "b": {"type": "integer"}}, "required": ["a", "b"]}),
        ("fail", "Zawsze rzuca wyjątek", {"type": "object", "properties": {}}),
    ]:
        registry.register_tool(backend, ToolDefinition(name=name, description=description, input_schema=schema))

    app = gateway.create_app()
    config = uvicorn.Config(app, host=GATEWAY_HOST, port=GATEWAY_PORT, log_level="warning")
    server = uvicorn.Server(config)
    thread = threading.Thread(target=server.run, daemon=True)
    thread.start()

    deadline = time.time() + 5
    while time.time() < deadline:
        try:
            httpx.get(f"http://{GATEWAY_HOST}:{GATEWAY_PORT}/")
            break
        except Exception:
            time.sleep(0.1)

    yield GATEWAY_URL

    server.should_exit = True


@pytest.mark.anyio
async def test_tools_list_returns_registered_tools(gateway_url):
    from mcp import ClientSession
    from mcp.client.streamable_http import streamable_http_client

    async with streamable_http_client(gateway_url) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.list_tools()
            names = [t.name for t in result.tools]
            assert "echo" in names
            assert "add" in names


@pytest.mark.anyio
async def test_call_tool_via_gateway(gateway_url):
    from mcp import ClientSession
    from mcp.client.streamable_http import streamable_http_client

    async with streamable_http_client(gateway_url) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool("echo", {"message": "hello"})
            assert result.isError is False
            assert result.content[0].text == "hello"


@pytest.mark.anyio
async def test_call_unknown_tool_returns_error(gateway_url):
    from mcp import ClientSession
    from mcp.client.streamable_http import streamable_http_client

    async with streamable_http_client(gateway_url) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool("nonexistent", {})
            assert result.isError is True


@pytest.mark.anyio
async def test_tool_error_propagates_as_mcp_error(gateway_url):
    from mcp import ClientSession
    from mcp.client.streamable_http import streamable_http_client

    async with streamable_http_client(gateway_url) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool("fail", {})
            assert result.isError is True
