"""Integration test - end-to-end flow through the bridge with a real MCP server."""

from __future__ import annotations

import json
import tempfile
from pathlib import Path

import pytest

from mcp_bridge.config import settings as settings_mod
from mcp_bridge.credentials.store import create_default_store
from mcp_bridge.instances.manager import InstanceManager
from mcp_bridge.meta_tools import (
    call_tool,
    configure_server,
    deactivate_server,
    discover_servers,
    get_server_status,
    import_mcp_config,
    init_meta_tools,
    list_active_tools,
)
from mcp_bridge.metrics.collector import MetricsCollector
from mcp_bridge.registry.catalog import ServerCatalog
from mcp_bridge.registry.models import ServerCategory, ServerEntry


@pytest.fixture
def tmp_dir():
    with tempfile.TemporaryDirectory() as d:
        yield Path(d)


@pytest.fixture
async def bridge_env(tmp_dir, monkeypatch):
    """Set up a complete bridge environment for integration testing."""
    settings_mod.reset_settings()
    monkeypatch.setenv("MCP_BRIDGE_DATA_DIR", str(tmp_dir))
    monkeypatch.setenv("MCP_BRIDGE_CATALOG_DIR", str(tmp_dir / "catalog"))
    (tmp_dir / "catalog").mkdir()
    settings_mod.reset_settings()

    catalog = ServerCatalog(db_path=tmp_dir / "test.db")
    await catalog.initialize()

    metrics = MetricsCollector(db_path=tmp_dir / "metrics.db")
    await metrics.initialize()

    credentials = create_default_store()
    instance_manager = InstanceManager(catalog=catalog, metrics=metrics, credential_store=credentials)
    # Don't start background tasks for tests
    instance_manager._running = True

    init_meta_tools(catalog, instance_manager, metrics)

    yield catalog, instance_manager, metrics

    await instance_manager.stop()
    await metrics.close()
    await catalog.close()
    settings_mod.reset_settings()


class TestMetaToolsFlow:
    """Test the complete meta-tools flow."""

    @pytest.mark.asyncio
    async def test_discover_empty_catalog(self, bridge_env):
        """Test discovering servers in an empty catalog."""
        result = json.loads(await discover_servers())
        assert result["total_servers"] == 0
        assert "categories" in result

    @pytest.mark.asyncio
    async def test_discover_with_servers(self, bridge_env):
        """Test discovering servers after registering some."""
        catalog, _, _ = bridge_env

        await catalog.register_server(
            ServerEntry(
                id="test-echo",
                name="Echo Server",
                description="A test echo server",
                category=ServerCategory.UTILITIES,
                command="echo",
                tags=["test"],
            )
        )

        # Discover all
        result = json.loads(await discover_servers())
        assert result["total_servers"] == 1

        # Discover by category
        result = json.loads(await discover_servers(category="utilities"))
        assert result["count"] == 1
        assert result["servers"][0]["id"] == "test-echo"

        # Discover by search
        result = json.loads(await discover_servers(search="echo"))
        assert result["count"] == 1

    @pytest.mark.asyncio
    async def test_configure_server(self, bridge_env):
        """Test configuring a server instance."""
        catalog, _, _ = bridge_env

        await catalog.register_server(
            ServerEntry(
                id="test-server",
                name="Test Server",
                category=ServerCategory.UTILITIES,
                command="echo",
            )
        )

        result = json.loads(await configure_server("test-server", config='{"key": "value"}'))
        assert "instance_id" in result
        assert result["state"] == "configured"
        assert result["config"]["key"] == "value"

    @pytest.mark.asyncio
    async def test_configure_unknown_server(self, bridge_env):
        """Test configuring a non-existent server."""
        result = json.loads(await configure_server("nonexistent"))
        assert "error" in result

    @pytest.mark.asyncio
    async def test_import_mcp_config_flow(self, bridge_env):
        """Test importing from mcp.json format."""
        config = json.dumps(
            {
                "mcpServers": {
                    "Test Server A": {"command": "echo", "args": ["hello"]},
                    "Test Server B": {"command": "echo", "args": ["world"]},
                }
            }
        )

        result = json.loads(await import_mcp_config(config))
        assert result["count"] == 2
        assert len(result["imported_servers"]) == 2

        # Verify they show up in discover
        discover_result = json.loads(await discover_servers())
        assert discover_result["total_servers"] == 2

    @pytest.mark.asyncio
    async def test_get_status_no_instances(self, bridge_env):
        """Test status with no active instances."""
        result = json.loads(await get_server_status())
        assert result["count"] == 0

    @pytest.mark.asyncio
    async def test_list_active_tools_empty(self, bridge_env):
        """Test listing tools with no active instances."""
        result = json.loads(await list_active_tools())
        assert result["total_tools"] == 0
        assert result["active_instances"] == 0

    @pytest.mark.asyncio
    async def test_deactivate_nonexistent(self, bridge_env):
        """Test deactivating a non-existent instance."""
        result = json.loads(await deactivate_server("nonexistent"))
        assert "error" in result

    @pytest.mark.asyncio
    async def test_call_tool_nonexistent_instance(self, bridge_env):
        """Test calling a tool on a non-existent instance."""
        result = json.loads(await call_tool("nonexistent", "some_tool"))
        assert "error" in result


class TestInstanceManagerLimits:
    """Test resource limit enforcement."""

    @pytest.mark.asyncio
    async def test_instance_limit_per_server(self, bridge_env, monkeypatch):
        """Test that per-server instance limits are enforced."""
        catalog, instance_manager, _ = bridge_env

        # Set a low limit
        monkeypatch.setenv("MCP_BRIDGE_INSTANCE_MAX_INSTANCES_PER_SERVER", "2")
        settings_mod.reset_settings()

        await catalog.register_server(
            ServerEntry(
                id="limited-server",
                name="Limited",
                category=ServerCategory.UTILITIES,
                command="echo",
                max_instances=2,
            )
        )

        # Configure 2 instances (should work)
        inst1 = await instance_manager.configure_instance("limited-server", "agent-1")
        inst2 = await instance_manager.configure_instance("limited-server", "agent-1")

        # The 3rd should fail (limit is checked against active instances,
        # but configured ones count toward the pool)
        # Note: configured but not active instances are still tracked
        assert inst1.instance_id != inst2.instance_id
