"""MCP server entrypoint for Agile DB third-party datasource APIs."""

import asyncio
import json
import logging
from typing import Any, Dict, List, Optional

try:
    from .tools import list_tools, get_tool
    from .utils import DataSourceAPIClient, get_env_config, get_api_key
    from .utils.logger_config import logger_config
except ImportError:
    from tools import list_tools, get_tool
    from utils import DataSourceAPIClient, get_env_config, get_api_key
    from utils.logger_config import logger_config

from mcp.server import NotificationOptions, Server
from mcp.server.models import InitializationOptions
import mcp.types as types

mcp_logger = logger_config.setup_mcp_logging()


def _text_response(payload: Dict[str, Any]) -> List[types.TextContent]:
    """Build a JSON text response."""
    return [
        types.TextContent(
            type="text",
            text=json.dumps(payload, ensure_ascii=False, indent=2),
        )
    ]


def _build_tool(tool_def: Dict[str, Any]) -> types.Tool:
    """Build an MCP Tool from a tool definition."""
    return types.Tool(
        name=tool_def["name"],
        description=tool_def["description"],
        inputSchema=tool_def["inputSchema"],
    )


server = Server("lzwcai-mcp-agile-db-third")
_api_client: Optional[DataSourceAPIClient] = None


def _get_api_client() -> DataSourceAPIClient:
    """Get or create the default API client."""
    global _api_client
    if _api_client is None:
        env = get_env_config()
        _api_client = DataSourceAPIClient(base_url=env.get("backend_base_url"))
    return _api_client


@server.list_tools()
async def handle_list_tools() -> List[types.Tool]:
    """List all available MCP tools."""
    try:
        mcp_logger.info("收到列出工具请求")
        tools = [_build_tool(tool_def) for tool_def in list_tools()]
        mcp_logger.info(f"成功生成 {len(tools)} 个 MCP 工具")
        return tools
    except Exception as e:
        mcp_logger.error(f"列出工具失败: {e}", exc_info=True)
        raise


@server.call_tool()
async def handle_call_tool(
    name: str,
    arguments: Optional[Dict[str, Any]],
) -> List[types.TextContent]:
    """Handle MCP tool invocation by proxying to the backend API."""
    try:
        mcp_logger.info(f"收到工具调用请求: {name}")
        mcp_logger.debug(f"工具参数: {arguments}")

        tool_def = get_tool(name)
        if tool_def is None:
            error_msg = f"未找到工具: {name}"
            mcp_logger.warning(error_msg)
            return _text_response({"error": error_msg})

        # Validate required parameters
        args = arguments or {}
        schema = tool_def["inputSchema"]
        required = schema.get("required", [])
        missing = [key for key in required if key not in args or args[key] is None]
        if missing:
            error_msg = f"工具 {name} 缺少必填参数: {', '.join(missing)}"
            mcp_logger.warning(error_msg)
            return _text_response({"error": error_msg, "missing": missing})

        # Categorize parameters
        path_params: Dict[str, Any] = {}
        query_params: Dict[str, Any] = {}
        body_params: Dict[str, Any] = {}
        file_path: Optional[str] = None
        api_key: Optional[str] = None

        categories = tool_def["paramCategories"]
        for key, value in args.items():
            if value is None:
                continue
            category = categories.get(key)
            if category == "path":
                path_params[key] = value
            elif category == "query":
                query_params[key] = value
            elif category == "body":
                body_params[key] = value
            elif category == "file":
                file_path = value
            elif category == "header":
                api_key = value

        # Apply schema-defined defaults for parameters the caller omitted,
        # so "有默认值的参数不填就用默认值"（如 datasourceType、target、分页）。
        properties = schema.get("properties", {})
        for key, prop in properties.items():
            if "default" not in prop:
                continue
            if args.get(key) is not None:
                continue
            default_value = prop["default"]
            category = categories.get(key)
            if category == "path":
                path_params[key] = default_value
            elif category == "query":
                query_params[key] = default_value
            elif category == "body":
                body_params[key] = default_value
            elif category == "header" and not api_key:
                api_key = default_value

        # Fall back to the environment-configured API key when the tool call
        # doesn't carry an explicit header value.
        if not api_key:
            api_key = get_api_key() or None
            if api_key:
                mcp_logger.info("工具调用未带 API Key，已回退到环境变量 datasourceApiKey")

        client = _get_api_client()
        result = client.request(
            method=tool_def["method"],
            path_template=tool_def["path"],
            path_params=path_params,
            query_params=query_params,
            body=body_params if body_params else None,
            file_path=file_path,
            api_key=api_key,
        )

        return _text_response(result)
    except Exception as e:
        error_msg = f"工具调用失败: {name}, 错误: {e}"
        mcp_logger.error(error_msg, exc_info=True)
        return _text_response({"error": error_msg})


async def async_main():
    """Async entry for the MCP server."""
    try:
        mcp_logger.info("=" * 60)
        mcp_logger.info("正在启动 MCP 服务: lzwcai-mcp-agile-db-third")
        mcp_logger.info("版本: 0.1.0")
        mcp_logger.info("=" * 60)

        env = get_env_config()
        mcp_logger.info(f"环境配置 - Backend Base URL: {env.get('backend_base_url')}")
        mcp_logger.info(f"环境配置 - API Key: {'已设置' if env.get('api_key') else '未设置'}")
        mcp_logger.info("=" * 60)

        from mcp.server.stdio import stdio_server

        async with stdio_server() as (read_stream, write_stream):
            mcp_logger.info("MCP 服务已启动，等待客户端连接...")
            await server.run(
                read_stream,
                write_stream,
                InitializationOptions(
                    server_name="lzwcai-mcp-agile-db-third",
                    server_version="0.1.2",
                    capabilities=server.get_capabilities(
                        notification_options=NotificationOptions(),
                        experimental_capabilities={},
                    ),
                ),
            )

        mcp_logger.info("MCP 服务已关闭")
    except Exception as e:
        mcp_logger.error(f"MCP 服务运行失败: {e}", exc_info=True)
        raise


def main():
    """Console entrypoint."""
    try:
        logger_config.setup_logging(
            app_name="lzwcai_mcp_agile_db_third",
            log_level=logging.INFO,
            console_output=False,
        )
        mcp_logger.info("开始运行 MCP Agile DB Third 服务")
        asyncio.run(async_main())
    except KeyboardInterrupt:
        mcp_logger.info("收到中断信号，正在关闭服务...")
    except Exception as e:
        mcp_logger.error(f"程序运行失败: {e}", exc_info=True)
        raise


if __name__ == "__main__":
    main()
