"""Agent 工具定义

本模块已废弃，请使用 src.agent.tools
保留此模块仅为向后兼容
"""

# 使用相对导入
# LangChain 格式的工具（保持旧 API）
from langchain.tools import tool

from .tools.builtin import CalculatorTool as _CalculatorTool


# 创建 LangChain @tool 装饰器版本
@tool
def calculator(expression: str) -> str:
    """执行数学计算。

    支持:
    - 基本运算: +, -, *, /, ^, %
    - 数学函数: sqrt, sin, cos, tan, log, log10, floor, ceil
    - 常量: pi, e

    示例:
    - "2 + 3 * 4" 返回 14
    - "sqrt(16)" 返回 4.0
    - "sin(pi/2)" 返回 1.0
    """
    tool_instance = _CalculatorTool()
    result = tool_instance.execute({"expression": expression})
    if result.success:
        return str(result.result)
    return f"计算错误: {result.error}"


# RAG 工具 - 使用全局变量保持懒加载
_rag_retriever = None


def _init_rag():
    """初始化 RAG 组件"""
    global _rag_retriever

    if _rag_retriever is not None:
        return _rag_retriever

    try:
        import sys
        from pathlib import Path

        from langchain_chroma import Chroma
        from langchain_ollama import OllamaEmbeddings

        # 找到项目根目录
        project_root = Path(__file__).parent.parent.parent
        if str(project_root) not in sys.path:
            sys.path.insert(0, str(project_root))

        from src.rag.config import config as rag_config
        from src.rag.retriever import create_retriever

        from src.config.agent import config as agent_config

        vector_store = Chroma(
            persist_directory=agent_config.chroma_dir,
            embedding_function=OllamaEmbeddings(
                model=rag_config.embedding_model
            ),
        )

        _rag_retriever = create_retriever(
            vector_store=vector_store,
            top_k=rag_config.top_k,
        )

        return _rag_retriever

    except Exception as e:
        import logging
        logging.getLogger("agent").warning(f"RAG 初始化失败: {e}")
        return None


@tool
def search_documents(query: str) -> str:
    """搜索知识库中的相关文档。

    当用户询问关于项目文档、技术细节、
    或需要从知识库中获取信息时使用此工具。

    参数:
        query: 搜索查询关键词或问题
    """
    retriever = _init_rag()

    if retriever is None:
        return "知识库未初始化，请先运行 agent init"

    try:
        docs = retriever.invoke(query)

        if not docs:
            return "未找到相关内容"

        results = []
        for i, doc in enumerate(docs, 1):
            content = doc.page_content[:500]
            source = doc.metadata.get("source", "未知来源")
            results.append(f"--- 文档 {i} (来源: {source}) ---\n{content}")

        return "\n\n".join(results)

    except Exception as e:
        import logging
        logging.getLogger("agent").error(f"[Tool: search_documents] 检索错误: {e}")
        return f"检索出错: {str(e)}"


# 兼容旧 API
class ToolRegistry:
    """工具注册表（兼容旧 API）"""

    def __init__(self):
        self._tools = {}

    def register(self, tool):
        self._tools[tool.name] = tool

    def get(self, name: str):
        return self._tools.get(name)

    def list_tools(self):
        return list(self._tools.values())


def get_default_tools():
    """获取默认工具列表"""
    return [calculator, search_documents]


def create_default_tools(enable_rag=True, enable_calculator=True, **kwargs):
    """创建默认工具注册表"""
    registry = ToolRegistry()
    if enable_calculator:
        registry.register(calculator)
    if enable_rag:
        registry.register(search_documents)
    return registry


# 新架构集成
def get_tools(config_path=None):
    """获取工具加载器（新架构）"""
    from .tools.loader import get_tool_loader
    return get_tool_loader(config_path)


# MCP 警告标志（确保只显示一次）
_mcp_warning_shown = False
_mcp_loaded_servers = set()  # 跟踪已加载的 MCP 服务器


def load_mcp_tools(mcp_servers=None):
    """从 MCP 配置加载工具"""
    import logging

    from src.config.agent import config

    logger = logging.getLogger("agent")

    global _mcp_warning_shown, _mcp_loaded_servers

    if not mcp_servers:
        mcp_servers = config.mcp_servers

    if not mcp_servers:
        return []

    all_tools = []

    try:
        import asyncio

        from langchain_mcp_adapters.sessions import SSEConnection, StdioConnection
        from langchain_mcp_adapters.tools import load_mcp_tools as langchain_load_mcp

        async def load_tools():
            tools = []
            for server_name, server_config in mcp_servers.items():
                # 避免重复加载同一服务器
                if server_name in _mcp_loaded_servers:
                    continue

                _mcp_loaded_servers.add(server_name)
                transport = server_config.get("transport", "stdio")
                logger.debug(f"加载 MCP 服务器: {server_name}, transport: {transport}")

                try:
                    if transport == "stdio":
                        connection = StdioConnection(
                            command=server_config.get("command", ""),
                            args=server_config.get("args", []),
                            cwd=server_config.get("cwd", None),
                            env=server_config.get("env", None),
                            transport=transport,
                        )
                    elif transport == "http":
                        connection = SSEConnection(
                            url=server_config.get("url", ""),
                            transport=transport,
                        )
                    else:
                        continue

                    server_tools = await langchain_load_mcp(
                        session=None,
                        connection=connection,
                        server_name=server_name,
                        tool_name_prefix=True,
                    )
                    tools.extend(server_tools)

                except Exception as e:
                    logger.error(f"加载 MCP 服务器 {server_name} 失败: {e}")

            return tools

        # 检查是否已有事件循环在运行
        try:
            loop = asyncio.get_running_loop()
            # 已有事件循环，在新线程中运行
            import concurrent.futures
            with concurrent.futures.ThreadPoolExecutor() as executor:
                raw_tools = executor.submit(asyncio.run, load_tools()).result()
        except RuntimeError:
            # 没有运行中的事件循环，可以直接使用 asyncio.run
            raw_tools = asyncio.run(load_tools())

        # 包装异步工具为同步
        for t in raw_tools:
            wrapped = _wrap_async_tool_to_sync(t)
            all_tools.append(wrapped)

    except ImportError as e:
        global _mcp_warning_shown
        if not _mcp_warning_shown:
            logger.warning(f"langchain-mcp-adapters 未安装: {e}")
            _mcp_warning_shown = True
    except Exception as e:
        logger.error(f"MCP 工具加载失败: {e}")

    return all_tools


def _wrap_async_tool_to_sync(async_tool):
    """将异步 MCP 工具包装为同步工具"""
    import asyncio

    from langchain_core.tools import Tool

    name = async_tool.name
    description = async_tool.description
    args_schema = async_tool.args_schema

    required_params = []
    param_names = []
    if args_schema and isinstance(args_schema, dict):
        required_params = args_schema.get('required', [])
        param_names = list(args_schema.get('properties', {}).keys())

    def sync_func(tool_input):
        try:
            import json

            if isinstance(tool_input, dict):
                if "__arg1" in tool_input:
                    inner = tool_input["__arg1"]
                    if isinstance(inner, dict):
                        params = inner
                    elif isinstance(inner, str):
                        try:
                            params = json.loads(inner)
                        except json.JSONDecodeError:
                            params = {param_names[0]: inner} if param_names else {"input": inner}
                    else:
                        params = {param_names[0]: str(inner)} if param_names else {"input": str(inner)}
                else:
                    params = tool_input
            elif isinstance(tool_input, str):
                try:
                    params = json.loads(tool_input)
                except json.JSONDecodeError:
                    params = {param_names[0]: tool_input} if param_names else {"input": tool_input}
            else:
                params = {"input": str(tool_input)}

            for req in required_params:
                if req not in params:
                    params[req] = ""

            # 检查是否已有事件循环在运行
            try:
                loop = asyncio.get_running_loop()
                # 已有事件循环，在新线程中运行
                import concurrent.futures
                with concurrent.futures.ThreadPoolExecutor() as executor:
                    result = executor.submit(asyncio.run, async_tool.ainvoke(params)).result()
            except RuntimeError:
                # 没有运行中的事件循环
                result = asyncio.run(async_tool.ainvoke(params))
            return result
        except Exception as e:
            return f"工具调用错误: {str(e)}"

    return Tool(name=name, func=sync_func, description=description)


def reload_tools_config(config_path=None):
    """重新加载工具配置"""
    from .tools.loader import reload_tools
    reload_tools()
