"""
Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com

Integration test: two servers (proxy + backend), adapter client invokes tools.

- Proxy (3005) and backend (8080) are started automatically by integration_test_servers.
- Backend registers with proxy (one server uses the other's commands: register/heartbeat).
- Client (JsonRpcClient from adapter) calls proxy_list on proxy, then invokes echo on backend.
All start/stop is automatic via pytest fixtures.
"""

from __future__ import annotations

from pathlib import Path
import sys
from urllib.parse import urlparse

import pytest

# Add project root
if str(Path(__file__).resolve().parents[1]) not in sys.path:
    sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

from mcp_proxy_adapter.client.jsonrpc_client import JsonRpcClient  # noqa: E402

PROXY_PORT = 3005
BACKEND_PORT = 8080


async def _proxy_available() -> bool:
    """Check if proxy is listening."""
    try:
        client = JsonRpcClient(protocol="http", host="127.0.0.1", port=PROXY_PORT)
        await client.health()
        await client.close()
        return True
    except Exception:
        return False


def _is_connect_error(exc: BaseException) -> bool:
    """True if exception is a connection error (e.g. server not reachable)."""
    name = type(exc).__name__
    return "Connect" in name or "connect" in str(exc).lower()


def _echo_message_from_result(extracted: dict) -> str:
    """Get echoed message from adapter echo result shape."""
    if extracted.get("data") and isinstance(extracted["data"], dict):
        return extracted["data"].get("message") or ""
    return extracted.get("message") or ""


@pytest.mark.asyncio
async def test_two_servers_client_invokes_backend_tools(
    integration_test_servers: None,
) -> None:
    """
    Two servers (proxy + backend) start automatically; client uses adapter client
    to list servers via proxy and invoke backend commands.
    """
    if not await _proxy_available():
        pytest.skip(
            "Proxy not available on 127.0.0.1:3005 (integration_test_servers starts it)"
        )

    client_proxy = JsonRpcClient(protocol="http", host="127.0.0.1", port=PROXY_PORT)
    client_backend = JsonRpcClient(protocol="http", host="127.0.0.1", port=BACKEND_PORT)

    try:
        try:
            list_resp = await client_proxy.jsonrpc_call("proxy_list", {})
        except Exception as e:
            if _is_connect_error(e):
                pytest.skip(
                    "Proxy connection failed (integration_test_servers may not have proxy)"
                )
            raise
        result = client_proxy._extract_result(list_resp)
        servers = result.get("servers") or result.get("data", {}).get("servers") or []
        assert isinstance(servers, list), "proxy_list returns a list"

        try:
            echo_resp = await client_backend.jsonrpc_call(
                "echo", {"message": "from_adapter_client"}
            )
        except Exception as e:
            if _is_connect_error(e):
                pytest.skip("Backend connection failed (integration_test_servers)")
            raise
        echo_result = client_backend._extract_result(echo_resp)
        msg = _echo_message_from_result(echo_result)
        assert "from_adapter_client" in msg or echo_result.get("success") is True
    finally:
        await client_proxy.close()
        await client_backend.close()


@pytest.mark.asyncio
async def test_client_discovers_backend_via_proxy_then_calls_echo(
    integration_test_servers: None,
) -> None:
    """
    Client discovers backend via proxy_list, then invokes echo on backend.
    Demonstrates: two servers (proxy uses backend's registration; client uses both).
    """
    if not await _proxy_available():
        pytest.skip("Proxy not available (integration_test_servers)")

    proxy_client = JsonRpcClient(protocol="http", host="127.0.0.1", port=PROXY_PORT)
    try:
        try:
            list_resp = await proxy_client.jsonrpc_call("proxy_list", {})
        except Exception as e:
            if _is_connect_error(e):
                pytest.skip("Proxy connection failed (integration_test_servers)")
            raise
        data = proxy_client._extract_result(list_resp)
        servers = data.get("servers") or data.get("data", {}).get("servers") or []
        backend_url = None
        for s in servers:
            url = s.get("server_url") or ""
            if "8080" in url or "localhost" in url:
                backend_url = url
                break
    finally:
        await proxy_client.close()

    if not backend_url:
        backend_url = f"http://127.0.0.1:{BACKEND_PORT}"

    parsed = urlparse(backend_url)
    host = parsed.hostname or "127.0.0.1"
    port = parsed.port or BACKEND_PORT

    backend_client = JsonRpcClient(protocol="http", host=host, port=port)
    try:
        try:
            echo_resp = await backend_client.jsonrpc_call(
                "echo", {"message": "discovered_via_proxy"}
            )
        except Exception as e:
            if _is_connect_error(e):
                pytest.skip("Backend connection failed (integration_test_servers)")
            raise
        out = backend_client._extract_result(echo_resp)
        msg = _echo_message_from_result(out)
        assert "discovered_via_proxy" in msg or out.get("success") is True
    finally:
        await backend_client.close()
