from pathlib import Path
from typing import Any
import asyncio
import json
import logging

try:
    from .utils import load_json, generate_input_schema
    from .utils import get_skill_by_id, process_skill_response, test_sql_with_schema
    from .utils import get_skill_id, get_env_config
    from .utils.logger_config import logger_config
except ImportError:
    from utils import load_json, generate_input_schema
    from utils import get_skill_by_id, process_skill_response, test_sql_with_schema
    from utils import get_skill_id, get_env_config
    from utils.logger_config import logger_config

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


mcp_logger = logger_config.setup_mcp_logging()

DATA_SOURCE_API = "api"
DATA_SOURCE_LOCAL = "local"
DATA_SOURCE_BOTH = "both"
DEFAULT_DATA_SOURCE = DATA_SOURCE_API


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 _extract_user_id(arguments: dict[str, Any]) -> Any:
    """Allow numeric 0, reject None and blank strings."""
    user_id = arguments.get("userId")
    if user_id is None:
        return None
    if isinstance(user_id, str) and not user_id.strip():
        return None
    return user_id


def get_queries():
    """Read local business query config."""
    try:
        current_dir = Path(__file__).parent
        json_path = current_dir / "businessQueries.json"
        mcp_logger.debug(f"正在读取业务查询配置文件: {json_path}")
        queries = load_json(json_path)
        mcp_logger.info(f"成功加载 {len(queries)} 个业务查询配置")
        return queries
    except Exception as e:
        mcp_logger.error(f"加载业务查询配置失败: {e}", exc_info=True)
        raise


def generate_tool_schema_from_query(query: dict) -> types.Tool:
    """Generate an MCP tool definition from one query config."""
    try:
        parameters = query.get("parameters", {})
        input_schema = generate_input_schema(parameters)
        tool_name = query["businessName"]
        description = f"{query['businessName']}: {query['businessDescription']}"

        mcp_logger.debug(f"生成工具模式: {tool_name} - {query['businessName']}")

        return types.Tool(
            name=tool_name,
            description=description,
            inputSchema=input_schema
        )
    except Exception as e:
        mcp_logger.error(
            f"生成工具模式失败: {query.get('id', 'unknown')}, 错误: {e}",
            exc_info=True
        )
        raise


server = Server("lzwcai-mcp-sqlexecutor")
_queries_cache = None


async def get_queries_cache(source: str = None):
    """Get or initialize query config cache."""
    global _queries_cache
    if _queries_cache is None:
        source = source or DEFAULT_DATA_SOURCE
        mcp_logger.info(f"初始化查询配置，数据源: {source}")

        if source == DATA_SOURCE_LOCAL:
            _queries_cache = get_queries()
            mcp_logger.info(f"本地配置: {len(_queries_cache)} 条")
        elif source == DATA_SOURCE_API:
            try:
                _queries_cache = await call_third_party_api()
                mcp_logger.info(f"API 配置: {len(_queries_cache)} 条")
                mcp_logger.info(f"API 配置数组: {_queries_cache}")
            except Exception as e:
                mcp_logger.warning(f"API 获取失败，降级使用本地配置: {e}")
                _queries_cache = get_queries()
        else:
            local = get_queries()
            try:
                api = await call_third_party_api()
            except Exception as e:
                mcp_logger.warning(f"API 获取失败: {e}")
                api = []
            _queries_cache = local + api
            mcp_logger.info(f"配置总数: {len(_queries_cache)} 条，本地 {len(local)} + API {len(api)}")

    return _queries_cache


@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
    """List all dynamically generated MCP tools."""
    try:
        mcp_logger.info("收到列出工具请求")
        queries = await get_queries_cache()
        tools = [generate_tool_schema_from_query(query) for query in queries]
        mcp_logger.info(f"成功生成 {len(tools)} 个 MCP 工具")
        mcp_logger.debug(f"工具列表: {[tool.name for tool in tools]}")
        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: dict[str, Any] | None
) -> list[types.TextContent]:
    """Handle MCP tool invocation."""
    try:
        mcp_logger.info(f"收到工具调用请求: {name}")
        mcp_logger.debug(f"工具参数: {arguments}")

        queries = await get_queries_cache()
        tool_item = next((query for query in queries if query["businessName"] == name), None)

        if not tool_item:
            return _text_response({"error": f"未找到工具 {name} 对应的配置"})

        normalized_parameters = generate_input_schema(tool_item.get("parameters"))
        normalized_arguments = arguments or {}
        user_id = _extract_user_id(normalized_arguments)

        if user_id is None:
            error_msg = f"工具 {name} 缺少必填参数 userId"
            mcp_logger.warning(error_msg)
            return _text_response({"error": error_msg, "required": ["userId"]})

        request_data = {
            "datasourceId": tool_item.get("datasourceId"),
            "businessName": tool_item.get("businessName"),
            "businessDescription": tool_item.get("businessDescription"),
            "sqlTemplate": tool_item.get("sqlTemplate"),
            "parameters": normalized_parameters,
            "testParams": normalized_arguments,
            "userId": user_id
        }

        target_database_name = normalized_arguments.get("targetDatabaseName")
        if target_database_name:
            request_data["targetDatabaseName"] = target_database_name
            mcp_logger.debug(f"添加目标数据库名称: {target_database_name}")

        try:
            mcp_logger.info("正在调用测试 SQL API...")
            result_payload = test_sql_with_schema(request_data)
            mcp_logger.info("测试 SQL API 调用成功")
        except Exception as e:
            error_msg = f"调用测试 SQL API 失败: {str(e)}"
            mcp_logger.error(error_msg, exc_info=True)
            result_payload = {"error": error_msg}

        mcp_logger.debug(f"工具调用结果: {result_payload}")
        return _text_response(result_payload)
    except Exception as e:
        error_msg = f"工具调用失败: {name}, 错误: {e}"
        mcp_logger.error(error_msg, exc_info=True)
        return [types.TextContent(type="text", text=f"错误: {error_msg}")]


async def call_third_party_api(skill_id: str = None) -> list:
    """Call backend API and map the response into query configs."""
    try:
        if skill_id is None:
            skill_id = get_skill_id()

        mcp_logger.info(f"调用第三方 API，skill_id: {skill_id}")
        raw_result = get_skill_by_id(skill_id)
        mcp_logger.info(f"成功获取原始响应: {raw_result}")

        processed_queries = process_skill_response(raw_result)
        mcp_logger.info(f"成功处理 {len(processed_queries)} 条数据")
        return processed_queries
    except Exception as e:
        mcp_logger.error(f"API 调用失败: {e}", exc_info=True)
        raise


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

        env_config = get_env_config()
        mcp_logger.info(f"环境配置 - Database ID: {env_config['database_id']}")
        mcp_logger.info(f"环境配置 - Skill ID: {env_config['skill_id']}")
        mcp_logger.info(f"环境配置 - Backend Base URL: {env_config['backend_base_url']}")
        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-sqlexecutor",
                    server_version="0.1.0",
                    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_sqlexecutor",
            log_level=logging.INFO,
            console_output=False
        )
        mcp_logger.info("开始运行 MCP SQL Executor 服务")
        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()
