"""Integration tests for murl with mcp-proxy.

These tests verify that murl can successfully interact with MCP servers
that have been proxied from stdio to HTTP using mcp-proxy.
"""

import json
import pytest
import subprocess
import time
import sys
import requests
from pathlib import Path
from click.testing import CliRunner
from murl.cli import main


# Test server configuration for mcp-proxy simulation
PROXY_TEST_PORT = 8766
PROXY_TEST_URL = f"http://localhost:{PROXY_TEST_PORT}"


@pytest.fixture(scope="module")
def mcp_proxy_server():
    """Start a simulated mcp-proxy server for integration tests.
    
    This simulates what mcp-proxy does: it takes a stdio MCP server
    and exposes it via HTTP. For testing purposes, we use the same
    test server but on a different port to verify the pattern works.
    """
    # Get path to test server
    test_dir = Path(__file__).parent
    server_script = test_dir / "mcp_test_server.py"
    
    # Start server process (simulating mcp-proxy's HTTP output)
    # In real usage, this would be: mcp-proxy --sse-port 8766 stdio-mcp-server
    process = subprocess.Popen(
        [sys.executable, str(server_script)],
        env={'TEST_PORT': str(PROXY_TEST_PORT)},
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True
    )
    
    # Wait for server to start with health check
    max_retries = 10
    retry_delay = 0.2
    
    for attempt in range(max_retries):
        if process.poll() is not None:
            stdout, stderr = process.communicate()
            pytest.fail(f"Proxy server failed to start:\nSTDOUT: {stdout}\nSTDERR: {stderr}")
        
        try:
            # Try to connect to server
            response = requests.post(
                PROXY_TEST_URL,
                json={"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}},
                timeout=1
            )
            if response.status_code == 200:
                break
        except (requests.ConnectionError, requests.Timeout):
            time.sleep(retry_delay)
    else:
        process.terminate()
        pytest.fail(f"Proxy server failed to start after {max_retries} attempts")
    
    yield PROXY_TEST_URL
    
    # Cleanup: stop server
    process.terminate()
    try:
        process.wait(timeout=5)
    except subprocess.TimeoutExpired:
        process.kill()
        process.wait()


# Test cases simulating mcp-proxy usage patterns

def test_mcp_proxy_list_tools(mcp_proxy_server):
    """Test listing tools from a proxied stdio MCP server.
    
    This simulates:
    $ mcp-proxy --sse-port 8766 my-stdio-mcp-server
    $ murl http://localhost:8766/tools
    """
    runner = CliRunner()
    result = runner.invoke(main, [f"{mcp_proxy_server}/tools"])
    
    assert result.exit_code == 0
    output = [json.loads(line) for line in result.output.strip().split('\n') if line.strip()]
    assert len(output) == 2
    assert output[0]["name"] == "echo"
    assert output[1]["name"] == "weather"
    # Verify the output structure matches MCP protocol
    assert "description" in output[0]
    assert "inputSchema" in output[0]


def test_mcp_proxy_call_tool(mcp_proxy_server):
    """Test calling a tool on a proxied stdio MCP server.
    
    This simulates:
    $ mcp-proxy --sse-port 8766 my-stdio-mcp-server
    $ murl http://localhost:8766/tools/echo -d message="Hello from mcp-proxy"
    """
    runner = CliRunner()
    result = runner.invoke(main, [
        f"{mcp_proxy_server}/tools/echo",
        "-d", "message=Hello from mcp-proxy"
    ])
    
    assert result.exit_code == 0
    output = [json.loads(line) for line in result.output.strip().split('\n') if line.strip()]
    assert isinstance(output, list)
    assert len(output) > 0
    assert output[0]["type"] == "text"
    assert output[0]["text"] == "Hello from mcp-proxy"


def test_mcp_proxy_multiple_args(mcp_proxy_server):
    """Test calling a tool with multiple arguments via proxy.
    
    This simulates:
    $ mcp-proxy --sse-port 8766 weather-mcp-server
    $ murl http://localhost:8766/tools/weather -d city=Tokyo -d metric=true
    """
    runner = CliRunner()
    result = runner.invoke(main, [
        f"{mcp_proxy_server}/tools/weather",
        "-d", "city=Tokyo",
        "-d", "metric=true"
    ])
    
    assert result.exit_code == 0
    output = [json.loads(line) for line in result.output.strip().split('\n') if line.strip()]
    assert isinstance(output, list)
    assert len(output) > 0
    assert output[0]["type"] == "text"
    assert "Tokyo" in output[0]["text"]


def test_mcp_proxy_list_resources(mcp_proxy_server):
    """Test listing resources from a proxied stdio MCP server.
    
    This simulates:
    $ mcp-proxy --sse-port 8766 my-stdio-mcp-server
    $ murl http://localhost:8766/resources
    """
    runner = CliRunner()
    result = runner.invoke(main, [f"{mcp_proxy_server}/resources"])
    
    assert result.exit_code == 0
    output = [json.loads(line) for line in result.output.strip().split('\n') if line.strip()]
    assert len(output) == 2
    assert "uri" in output[0]
    assert "name" in output[0]
    assert "mimeType" in output[0]


def test_mcp_proxy_read_resource(mcp_proxy_server):
    """Test reading a resource from a proxied stdio MCP server.
    
    This simulates:
    $ mcp-proxy --sse-port 8766 my-stdio-mcp-server
    $ murl http://localhost:8766/resources/data/file.txt
    """
    runner = CliRunner()
    result = runner.invoke(main, [
        f"{mcp_proxy_server}/resources/data/file.txt"
    ])
    
    assert result.exit_code == 0
    output = [json.loads(line) for line in result.output.strip().split('\n') if line.strip()]
    assert isinstance(output, list)
    assert len(output) > 0
    assert output[0]["uri"] == "file:///data/file.txt"
    assert "text" in output[0]


def test_mcp_proxy_list_prompts(mcp_proxy_server):
    """Test listing prompts from a proxied stdio MCP server.
    
    This simulates:
    $ mcp-proxy --sse-port 8766 my-stdio-mcp-server
    $ murl http://localhost:8766/prompts
    """
    runner = CliRunner()
    result = runner.invoke(main, [f"{mcp_proxy_server}/prompts"])
    
    assert result.exit_code == 0
    output = [json.loads(line) for line in result.output.strip().split('\n') if line.strip()]
    assert len(output) == 2
    assert output[0]["name"] == "greeting"
    assert "description" in output[0]


def test_mcp_proxy_get_prompt(mcp_proxy_server):
    """Test getting a prompt from a proxied stdio MCP server.
    
    This simulates:
    $ mcp-proxy --sse-port 8766 my-stdio-mcp-server
    $ murl http://localhost:8766/prompts/greeting -d name=User
    """
    runner = CliRunner()
    result = runner.invoke(main, [
        f"{mcp_proxy_server}/prompts/greeting",
        "-d", "name=User"
    ])
    
    assert result.exit_code == 0
    output = [json.loads(line) for line in result.output.strip().split('\n') if line.strip()]
    assert isinstance(output, list)
    assert len(output) > 0
    assert output[0]["role"] == "user"
    assert "User" in output[0]["content"]["text"]


def test_mcp_proxy_with_json_data(mcp_proxy_server):
    """Test sending complex JSON data to a proxied server.
    
    This simulates:
    $ mcp-proxy --sse-port 8766 my-stdio-mcp-server
    $ murl http://localhost:8766/tools/echo -d '{"message": "complex data", "nested": {"key": "value"}}'
    """
    runner = CliRunner()
    result = runner.invoke(main, [
        f"{mcp_proxy_server}/tools/echo",
        "-d", '{"message": "complex data"}'
    ])
    
    assert result.exit_code == 0
    output = [json.loads(line) for line in result.output.strip().split('\n') if line.strip()]
    assert isinstance(output, list)
    assert len(output) > 0
    assert output[0]["type"] == "text"
    assert output[0]["text"] == "complex data"


def test_mcp_proxy_verbose_mode(mcp_proxy_server):
    """Test verbose mode with proxied server.
    
    This simulates:
    $ mcp-proxy --sse-port 8766 my-stdio-mcp-server
    $ murl http://localhost:8766/tools -v
    """
    runner = CliRunner()
    result = runner.invoke(main, [
        f"{mcp_proxy_server}/tools",
        "-v"
    ])
    
    assert result.exit_code == 0
    # Verbose mode should succeed and contain the result
    # Just verify it executed successfully
    assert len(result.output) > 0


def test_mcp_proxy_workflow_simulation():
    """Test a complete workflow simulating real-world mcp-proxy usage.
    
    This demonstrates the pattern described in the README:
    1. Start mcp-proxy (simulated by our test server)
    2. Discover tools
    3. Call a tool
    4. List resources
    
    In practice, this would be:
    $ mcp-proxy --sse-port 3000 python my_mcp_server.py
    $ murl http://localhost:3000/tools | jq '.[] | {name, description}'
    $ murl http://localhost:3000/tools/process_data -d input="Hello World"
    """
    # Note: This test documents the pattern but doesn't run a full integration
    # since we're using a simplified test server. The other tests verify each step.
    assert True  # Pattern documented in other tests
