# -*- coding: utf-8 -*-
"""Minimal MCP stdio server for Server Manager.

The transport is newline-delimited JSON-RPC over stdin/stdout. Keep stdout
strictly reserved for MCP messages; diagnostics go to stderr.
"""

from __future__ import annotations

import json
import sys
from typing import Any, Dict, Optional

from mcp.tools import ServerManagerToolbox


PROTOCOL_VERSION = "2025-11-25"
SERVER_NAME = "server-manager"
SERVER_VERSION = "1.0.0"


JsonDict = Dict[str, Any]


class McpStdioServer:
    def __init__(self, server_root: Optional[str] = None, config_path: Optional[str] = None,
                 cookie: Optional[str] = None):
        self.toolbox = ServerManagerToolbox(server_root=server_root, config_path=config_path, cookie=cookie)
        self._tools = self.toolbox.tool_map()

    def serve_forever(self) -> None:
        for raw_line in sys.stdin:
            line = raw_line.strip()
            if not line:
                continue
            try:
                message = json.loads(line)
                response = self.handle_message(message)
            except Exception as e:
                response = self._error(None, -32700, f"Parse error: {e}")
            if response is not None:
                self._send(response)

    def handle_message(self, message: JsonDict) -> Optional[JsonDict]:
        if not isinstance(message, dict):
            return self._error(None, -32600, "Invalid Request")
        request_id = message.get("id")
        method = message.get("method")
        if not method:
            return self._error(request_id, -32600, "Invalid Request")

        # Notifications do not receive responses.
        if request_id is None:
            if method in {
                "notifications/initialized",
                "notifications/cancelled",
                "notifications/progress",
            }:
                return None
            return None

        params = message.get("params") or {}
        try:
            if method == "initialize":
                return self._result(request_id, self._initialize_result(params))
            if method == "ping":
                return self._result(request_id, {})
            if method == "tools/list":
                return self._result(request_id, {
                    "tools": [tool.to_mcp_tool() for tool in self._tools.values()],
                })
            if method == "tools/call":
                return self._result(request_id, self._call_tool(params))
            return self._error(request_id, -32601, f"Method not found: {method}")
        except Exception as e:
            return self._error(request_id, -32603, str(e))

    def _initialize_result(self, params: JsonDict) -> JsonDict:
        requested = str(params.get("protocolVersion") or PROTOCOL_VERSION)
        protocol = requested if requested <= PROTOCOL_VERSION else PROTOCOL_VERSION
        return {
            "protocolVersion": protocol,
            "capabilities": {
                "tools": {"listChanged": False},
            },
            "serverInfo": {
                "name": SERVER_NAME,
                "version": SERVER_VERSION,
            },
            "instructions": (
                "Use the server_manager_* tools to inspect and operate local Server Manager "
                "projects. Operations that start/stop/create servers can modify local state."
            ),
        }

    def _call_tool(self, params: JsonDict) -> JsonDict:
        name = params.get("name")
        if not isinstance(name, str) or not name:
            return {
                "content": [{"type": "text", "text": "tools/call requires params.name"}],
                "isError": True,
            }
        arguments = params.get("arguments") or {}
        if not isinstance(arguments, dict):
            return {
                "content": [{"type": "text", "text": "tools/call params.arguments must be an object"}],
                "isError": True,
            }
        return self.toolbox.call_tool(name, arguments)

    def _send(self, response: JsonDict) -> None:
        sys.stdout.write(json.dumps(response, ensure_ascii=False, separators=(",", ":")) + "\n")
        sys.stdout.flush()

    def _result(self, request_id: Any, result: JsonDict) -> JsonDict:
        return {"jsonrpc": "2.0", "id": request_id, "result": result}

    def _error(self, request_id: Any, code: int, message: str) -> JsonDict:
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "error": {"code": code, "message": message},
        }


def run_stdio_server(server_root: Optional[str] = None, config_path: Optional[str] = None,
                     cookie: Optional[str] = None) -> None:
    McpStdioServer(server_root=server_root, config_path=config_path, cookie=cookie).serve_forever()
