"""MCP server configuration loading.

Loads MCP server configurations from JSON files:
- ~/.ieum/mcp_servers.json (global)
- .ieum/mcp_servers.json (project-level)

Project-level config overrides global config for servers with the same name.
"""

from __future__ import annotations

import json
import os
from pathlib import Path
from typing import Any, TypedDict


class StdioTransportConfig(TypedDict, total=False):
    """Configuration for stdio transport."""

    transport: str  # "stdio"
    command: str
    args: list[str]
    env: dict[str, str]


class HttpTransportConfig(TypedDict, total=False):
    """Configuration for HTTP transport."""

    transport: str  # "http"
    url: str
    headers: dict[str, str]


MCPServerConfig = StdioTransportConfig | HttpTransportConfig


def get_global_mcp_config_path() -> Path:
    """Get the global MCP config file path.

    Returns:
        Path to ~/.ieum/mcp_servers.json
    """
    return Path.home() / ".ieum" / "mcp_servers.json"


def get_project_mcp_config_path() -> Path | None:
    """Get the project-level MCP config file path.

    Returns:
        Path to .ieum/mcp_servers.json if it exists, None otherwise
    """
    project_config = Path.cwd() / ".ieum" / "mcp_servers.json"
    if project_config.exists():
        return project_config
    return None


def _load_config_file(path: Path) -> dict[str, MCPServerConfig]:
    """Load MCP server config from a JSON file.

    Args:
        path: Path to the JSON config file

    Returns:
        Dictionary mapping server names to their configurations
    """
    if not path.exists():
        return {}

    try:
        with open(path, encoding="utf-8") as f:
            data = json.load(f)

        servers = data.get("mcpServers", {})

        # Validate and normalize configs
        result: dict[str, MCPServerConfig] = {}
        for name, config in servers.items():
            if not isinstance(config, dict):
                continue

            transport = config.get("transport", "stdio")

            if transport == "stdio":
                if "command" not in config:
                    continue
                result[name] = {
                    "transport": "stdio",
                    "command": config["command"],
                    "args": config.get("args", []),
                    "env": config.get("env", {}),
                }
            elif transport == "http":
                if "url" not in config:
                    continue
                result[name] = {
                    "transport": "http",
                    "url": config["url"],
                    "headers": config.get("headers", {}),
                }

        return result

    except (json.JSONDecodeError, OSError):
        return {}


def get_builtin_mcp_servers() -> dict[str, MCPServerConfig]:
    """Get built-in MCP server configurations.

    Built-in servers are enabled when their required environment variables are set.

    Returns:
        Dictionary mapping server names to their configurations
    """
    servers: dict[str, MCPServerConfig] = {}

    # GitHub MCP Server - enabled when GITHUB_PAT is set
    github_pat = os.environ.get("GITHUB_PAT") or os.environ.get("GITHUB_PERSONAL_ACCESS_TOKEN")
    github_host = os.environ.get("GITHUB_HOST", "https://github.com")

    if github_pat:
        # Check if it's GitHub Enterprise with ghe.com domain
        if "ghe.com" in github_host:
            # GitHub Enterprise Cloud with Data Residency
            # Use HTTP transport to Copilot API
            host_base = github_host.replace("https://", "").replace("http://", "")
            servers["github"] = {
                "transport": "http",
                "url": f"https://copilot-api.{host_base}/mcp",
                "headers": {
                    "Authorization": f"Bearer {github_pat}",
                },
            }
        else:
            # Standard GitHub or GitHub Enterprise Server
            env: dict[str, str] = {
                "GITHUB_PERSONAL_ACCESS_TOKEN": github_pat,
            }
            if github_host != "https://github.com":
                env["GITHUB_HOST"] = github_host

            # Transport: docker (default, official), npx (Node.js fallback)
            # uvx not yet available - no Python GitHub MCP server on PyPI
            transport = os.environ.get("GITHUB_MCP_TRANSPORT", "docker")

            if transport == "npx":
                servers["github"] = {
                    "transport": "stdio",
                    "command": "npx",
                    "args": [
                        "-y", "@modelcontextprotocol/server-github",
                    ],
                    "env": env,
                }
            else:
                # Docker-based (default) - official GitHub MCP server
                servers["github"] = {
                    "transport": "stdio",
                    "command": "docker",
                    "args": [
                        "run", "-i", "--rm",
                        "-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
                        "-e", "GITHUB_HOST",
                        "ghcr.io/github/github-mcp-server",
                    ],
                    "env": env,
                }

    return servers


def load_mcp_config() -> dict[str, MCPServerConfig]:
    """Load MCP server configurations from global and project config files.

    Built-in servers are loaded first, then global, then project configs.
    Later configs override earlier ones for servers with the same name.

    Returns:
        Dictionary mapping server names to their configurations
    """
    # Start with built-in servers
    config = get_builtin_mcp_servers()

    # Load global config
    global_config = _load_config_file(get_global_mcp_config_path())
    config.update(global_config)

    # Load project config (overrides global)
    project_path = get_project_mcp_config_path()
    if project_path:
        project_config = _load_config_file(project_path)
        config.update(project_config)

    # Also check environment variable for additional config path
    env_config_path = os.environ.get("MCP_SERVERS_CONFIG")
    if env_config_path:
        env_config = _load_config_file(Path(env_config_path))
        config.update(env_config)

    return config
