"""
MCP Configuration System

Pydantic models for MCP server configuration with YAML file loading
and environment variable overrides.
"""

import os
from enum import Enum
from pathlib import Path
from typing import Any

import yaml
from pydantic import BaseModel, Field, field_validator


class TransportType(str, Enum):
    """Supported MCP transport types."""

    HTTP = "http"
    STDIO = "stdio"
    SSE = "sse"


class MCPServerConfig(BaseModel):
    """Configuration for a single MCP server."""

    url: str = Field(..., description="Server URL (supports ${ENV_VAR} syntax)")
    transport: TransportType = Field(
        default=TransportType.HTTP,
        description="Transport protocol to use",
    )
    timeout: int = Field(
        default=30,
        ge=1,
        le=600,
        description="Request timeout in seconds",
    )
    retry_attempts: int = Field(
        default=3,
        ge=0,
        le=10,
        description="Number of retry attempts on failure",
    )
    retry_delay: float = Field(
        default=1.0,
        ge=0.1,
        le=60.0,
        description="Initial delay between retries in seconds",
    )
    retry_max_delay: float = Field(
        default=30.0,
        ge=1.0,
        le=300.0,
        description="Maximum delay between retries in seconds",
    )
    circuit_breaker_threshold: int = Field(
        default=5,
        ge=1,
        le=50,
        description="Number of failures before opening circuit",
    )
    circuit_breaker_timeout: float = Field(
        default=30.0,
        ge=5.0,
        le=300.0,
        description="Seconds to wait before attempting to close circuit",
    )
    enabled: bool = Field(
        default=True,
        description="Whether this server is enabled",
    )
    description: str | None = Field(
        default=None,
        description="Human-readable description of the server",
    )

    @field_validator("url", mode="before")
    @classmethod
    def expand_env_vars(cls, v: str) -> str:
        """Expand environment variables in URL using ${VAR:-default} syntax."""
        if not isinstance(v, str):
            return v

        result = v
        # Find all ${VAR} or ${VAR:-default} patterns
        import re

        pattern = r"\$\{([^}]+)\}"
        matches = re.findall(pattern, v)

        for match in matches:
            if ":-" in match:
                var_name, default = match.split(":-", 1)
            else:
                var_name, default = match, ""

            env_value = os.environ.get(var_name.strip(), default)
            result = result.replace(f"${{{match}}}", env_value)

        return result


class MCPConfig(BaseModel):
    """Root configuration for all MCP servers."""

    mcp_servers: dict[str, MCPServerConfig] = Field(
        default_factory=dict,
        description="Map of server names to their configurations",
    )

    # Global defaults
    default_timeout: int = Field(
        default=30,
        description="Default timeout for all servers",
    )
    default_retry_attempts: int = Field(
        default=3,
        description="Default retry attempts for all servers",
    )
    connection_pool_size: int = Field(
        default=10,
        ge=1,
        le=100,
        description="Maximum connections per server",
    )
    health_check_interval: int = Field(
        default=30,
        ge=5,
        le=300,
        description="Seconds between health checks",
    )

    @classmethod
    def from_yaml(cls, path: str | Path) -> "MCPConfig":
        """Load configuration from a YAML file."""
        path = Path(path)
        if not path.exists():
            raise FileNotFoundError(f"MCP config file not found: {path}")

        with path.open("r") as f:
            data = yaml.safe_load(f)

        if data is None:
            data = {}

        return cls.model_validate(data)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "MCPConfig":
        """Load configuration from a dictionary."""
        return cls.model_validate(data)

    def get_server(self, name: str) -> MCPServerConfig | None:
        """Get a server configuration by name."""
        return self.mcp_servers.get(name)

    def get_enabled_servers(self) -> dict[str, MCPServerConfig]:
        """Get all enabled server configurations."""
        return {
            name: config for name, config in self.mcp_servers.items() if config.enabled
        }

    def list_server_names(self) -> list[str]:
        """Get list of all configured server names."""
        return list(self.mcp_servers.keys())


# Default configuration path
DEFAULT_CONFIG_PATH = Path(__file__).parent.parent.parent.parent / "mcp_servers.yaml"


def load_mcp_config(path: str | Path | None = None) -> MCPConfig:
    """
    Load MCP configuration from file or environment.

    Priority:
    1. Explicit path parameter
    2. MCP_CONFIG_PATH environment variable
    3. Default path (backend/mcp_servers.yaml)
    4. Empty config if no file exists
    """
    if path is None:
        path = os.environ.get("MCP_CONFIG_PATH", str(DEFAULT_CONFIG_PATH))

    path = Path(path)

    if not path.exists():
        # Return empty config if no file exists (allows runtime registration)
        return MCPConfig()

    return MCPConfig.from_yaml(path)


def create_default_config() -> MCPConfig:
    """
    Create a default MCP configuration with standard servers.

    This is useful for development and as a template.
    """
    return MCPConfig(
        mcp_servers={
            "llm-gateway": MCPServerConfig(
                url="${LLM_GATEWAY_URL:-http://localhost:8001}",
                transport=TransportType.HTTP,
                timeout=60,
                description="LLM Gateway for multi-provider AI interactions",
            ),
            "knowledge-base": MCPServerConfig(
                url="${KNOWLEDGE_BASE_URL:-http://localhost:8002}",
                transport=TransportType.HTTP,
                timeout=30,
                description="Knowledge Base for RAG and document retrieval",
            ),
            "git-ops": MCPServerConfig(
                url="${GIT_OPS_URL:-http://localhost:8003}",
                transport=TransportType.HTTP,
                timeout=120,
                description="Git Operations for repository management",
            ),
            "issues": MCPServerConfig(
                url="${ISSUES_URL:-http://localhost:8004}",
                transport=TransportType.HTTP,
                timeout=30,
                description="Issue Tracker for Gitea/GitHub/GitLab",
            ),
        },
        default_timeout=30,
        default_retry_attempts=3,
        connection_pool_size=10,
        health_check_interval=30,
    )
