"""
Tests for MCP Configuration System
"""

import os
import tempfile
from pathlib import Path

import pytest
import yaml

from app.services.mcp.config import (
    MCPConfig,
    MCPServerConfig,
    TransportType,
    create_default_config,
    load_mcp_config,
)


class TestTransportType:
    """Tests for TransportType enum."""

    def test_transport_types(self):
        """Test that all transport types are defined."""
        assert TransportType.HTTP == "http"
        assert TransportType.STDIO == "stdio"
        assert TransportType.SSE == "sse"

    def test_transport_type_from_string(self):
        """Test creating transport type from string."""
        assert TransportType("http") == TransportType.HTTP
        assert TransportType("stdio") == TransportType.STDIO
        assert TransportType("sse") == TransportType.SSE


class TestMCPServerConfig:
    """Tests for MCPServerConfig model."""

    def test_minimal_config(self):
        """Test creating config with only required fields."""
        config = MCPServerConfig(url="http://localhost:8000")
        assert config.url == "http://localhost:8000"
        assert config.transport == TransportType.HTTP
        assert config.timeout == 30
        assert config.retry_attempts == 3
        assert config.enabled is True

    def test_full_config(self):
        """Test creating config with all fields."""
        config = MCPServerConfig(
            url="http://localhost:8000",
            transport=TransportType.SSE,
            timeout=60,
            retry_attempts=5,
            retry_delay=2.0,
            retry_max_delay=60.0,
            circuit_breaker_threshold=10,
            circuit_breaker_timeout=60.0,
            enabled=False,
            description="Test server",
        )
        assert config.timeout == 60
        assert config.transport == TransportType.SSE
        assert config.retry_attempts == 5
        assert config.retry_delay == 2.0
        assert config.retry_max_delay == 60.0
        assert config.circuit_breaker_threshold == 10
        assert config.circuit_breaker_timeout == 60.0
        assert config.enabled is False
        assert config.description == "Test server"

    def test_env_var_expansion_simple(self):
        """Test simple environment variable expansion."""
        os.environ["TEST_SERVER_URL"] = "http://test-server:9000"
        try:
            config = MCPServerConfig(url="${TEST_SERVER_URL}")
            assert config.url == "http://test-server:9000"
        finally:
            del os.environ["TEST_SERVER_URL"]

    def test_env_var_expansion_with_default(self):
        """Test environment variable expansion with default."""
        # Ensure env var is not set
        os.environ.pop("NONEXISTENT_URL", None)
        config = MCPServerConfig(url="${NONEXISTENT_URL:-http://default:8000}")
        assert config.url == "http://default:8000"

    def test_env_var_expansion_override_default(self):
        """Test environment variable override of default."""
        os.environ["TEST_OVERRIDE_URL"] = "http://override:9000"
        try:
            config = MCPServerConfig(url="${TEST_OVERRIDE_URL:-http://default:8000}")
            assert config.url == "http://override:9000"
        finally:
            del os.environ["TEST_OVERRIDE_URL"]

    def test_timeout_validation(self):
        """Test timeout validation bounds."""
        # Valid bounds
        config = MCPServerConfig(url="http://localhost", timeout=1)
        assert config.timeout == 1

        config = MCPServerConfig(url="http://localhost", timeout=600)
        assert config.timeout == 600

        # Invalid bounds
        with pytest.raises(ValueError):
            MCPServerConfig(url="http://localhost", timeout=0)

        with pytest.raises(ValueError):
            MCPServerConfig(url="http://localhost", timeout=601)

    def test_retry_attempts_validation(self):
        """Test retry attempts validation bounds."""
        config = MCPServerConfig(url="http://localhost", retry_attempts=0)
        assert config.retry_attempts == 0

        config = MCPServerConfig(url="http://localhost", retry_attempts=10)
        assert config.retry_attempts == 10

        with pytest.raises(ValueError):
            MCPServerConfig(url="http://localhost", retry_attempts=-1)

        with pytest.raises(ValueError):
            MCPServerConfig(url="http://localhost", retry_attempts=11)


class TestMCPConfig:
    """Tests for MCPConfig model."""

    def test_empty_config(self):
        """Test creating empty config."""
        config = MCPConfig()
        assert config.mcp_servers == {}
        assert config.default_timeout == 30
        assert config.default_retry_attempts == 3
        assert config.connection_pool_size == 10
        assert config.health_check_interval == 30

    def test_config_with_servers(self):
        """Test creating config with servers."""
        config = MCPConfig(
            mcp_servers={
                "server-1": MCPServerConfig(url="http://server1:8000"),
                "server-2": MCPServerConfig(url="http://server2:8000"),
            }
        )
        assert len(config.mcp_servers) == 2
        assert "server-1" in config.mcp_servers
        assert "server-2" in config.mcp_servers

    def test_get_server(self):
        """Test getting server by name."""
        config = MCPConfig(
            mcp_servers={
                "server-1": MCPServerConfig(url="http://server1:8000"),
            }
        )
        server = config.get_server("server-1")
        assert server is not None
        assert server.url == "http://server1:8000"

        missing = config.get_server("nonexistent")
        assert missing is None

    def test_get_enabled_servers(self):
        """Test getting only enabled servers."""
        config = MCPConfig(
            mcp_servers={
                "enabled-1": MCPServerConfig(url="http://e1:8000", enabled=True),
                "disabled-1": MCPServerConfig(url="http://d1:8000", enabled=False),
                "enabled-2": MCPServerConfig(url="http://e2:8000", enabled=True),
            }
        )
        enabled = config.get_enabled_servers()
        assert len(enabled) == 2
        assert "enabled-1" in enabled
        assert "enabled-2" in enabled
        assert "disabled-1" not in enabled

    def test_list_server_names(self):
        """Test listing server names."""
        config = MCPConfig(
            mcp_servers={
                "server-a": MCPServerConfig(url="http://a:8000"),
                "server-b": MCPServerConfig(url="http://b:8000"),
            }
        )
        names = config.list_server_names()
        assert sorted(names) == ["server-a", "server-b"]

    def test_from_dict(self):
        """Test creating config from dictionary."""
        data = {
            "mcp_servers": {
                "test-server": {
                    "url": "http://test:8000",
                    "timeout": 45,
                }
            },
            "default_timeout": 60,
        }
        config = MCPConfig.from_dict(data)
        assert config.default_timeout == 60
        assert config.mcp_servers["test-server"].timeout == 45

    def test_from_yaml(self):
        """Test loading config from YAML file."""
        yaml_content = """
mcp_servers:
  test-server:
    url: http://test:8000
    timeout: 45
    transport: http
    enabled: true
default_timeout: 60
connection_pool_size: 20
"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".yaml", delete=False
        ) as f:
            f.write(yaml_content)
            f.flush()

            try:
                config = MCPConfig.from_yaml(f.name)
                assert config.default_timeout == 60
                assert config.connection_pool_size == 20
                assert "test-server" in config.mcp_servers
                assert config.mcp_servers["test-server"].timeout == 45
            finally:
                os.unlink(f.name)

    def test_from_yaml_file_not_found(self):
        """Test error when YAML file not found."""
        with pytest.raises(FileNotFoundError):
            MCPConfig.from_yaml("/nonexistent/path/config.yaml")


class TestLoadMCPConfig:
    """Tests for load_mcp_config function."""

    def test_load_with_explicit_path(self):
        """Test loading config with explicit path."""
        yaml_content = """
mcp_servers:
  explicit-server:
    url: http://explicit:8000
"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".yaml", delete=False
        ) as f:
            f.write(yaml_content)
            f.flush()

            try:
                config = load_mcp_config(f.name)
                assert "explicit-server" in config.mcp_servers
            finally:
                os.unlink(f.name)

    def test_load_with_env_var(self):
        """Test loading config from environment variable path."""
        yaml_content = """
mcp_servers:
  env-server:
    url: http://env:8000
"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".yaml", delete=False
        ) as f:
            f.write(yaml_content)
            f.flush()

            os.environ["MCP_CONFIG_PATH"] = f.name
            try:
                config = load_mcp_config()
                assert "env-server" in config.mcp_servers
            finally:
                del os.environ["MCP_CONFIG_PATH"]
                os.unlink(f.name)

    def test_load_returns_empty_config_if_missing(self):
        """Test that missing file returns empty config."""
        os.environ.pop("MCP_CONFIG_PATH", None)
        config = load_mcp_config("/nonexistent/path/config.yaml")
        assert config.mcp_servers == {}


class TestCreateDefaultConfig:
    """Tests for create_default_config function."""

    def test_creates_standard_servers(self):
        """Test that default config has standard servers."""
        config = create_default_config()

        assert "llm-gateway" in config.mcp_servers
        assert "knowledge-base" in config.mcp_servers
        assert "git-ops" in config.mcp_servers
        assert "issues" in config.mcp_servers

    def test_servers_have_correct_defaults(self):
        """Test that servers have correct default values."""
        config = create_default_config()

        llm = config.mcp_servers["llm-gateway"]
        assert llm.timeout == 60  # LLM has longer timeout
        assert llm.transport == TransportType.HTTP

        git = config.mcp_servers["git-ops"]
        assert git.timeout == 120  # Git ops has longest timeout

    def test_servers_are_enabled(self):
        """Test that all default servers are enabled."""
        config = create_default_config()

        for name, server in config.mcp_servers.items():
            assert server.enabled is True, f"Server {name} should be enabled"
