"""Tools API Router

聚合两套工具体系的元数据：
1. 注册层 (app/tools/) - YAML manifest 定义
2. Agent 层 (app/agents/tools/) - @tool 装饰器定义
"""

import re
import importlib

from fastapi import APIRouter, Depends

from app.routers.auth import get_current_user
from app.models.user import User
from app.schemas.tools import (
    ToolsResponse,
    ToolCategory,
    ToolSubgroup,
    ToolInfo,
    ToolCommand,
    ToolStats,
    ToolSummary,
)

router = APIRouter(prefix="/api/tools", tags=["Tools"])

# ============================================================
# 辅助函数
# ============================================================


def _parse_command_from_docstring(docstring: str) -> dict:
    """从函数的 docstring 解析参数信息"""
    params = {"type": "object", "properties": {}, "required": []}
    if not docstring:
        return params

    # 简单解析 Args: 段落
    args_match = re.search(
        r"Args:\s*(.*?)(?=\n\s*(?:Returns?|Raises?)|$", docstring, re.DOTALL | re.IGNORECASE
    )
    if args_match:
        args_section = args_match.group(1)
        # 匹配形如 "arg_name (type): description" 的行
        for line in args_section.strip().split("\n"):
            line = line.strip()
            if not line:
                continue
            # 匹配: "name (type): description" 或 "name: description"
            m = re.match(r"(\w+)\s*(?:\(\s*(\w+)\s*\))?\s*:", line)
            if m:
                param_name = m.group(1)
                params["properties"][param_name] = {"type": "string", "description": line}
                params["required"].append(param_name)

    return params


def _build_agent_tools() -> list[ToolInfo]:
    """扫描 app/agents/tools/ 目录，内省 @tool 装饰器"""
    tools: list[ToolInfo] = []

    # 分类映射：文件名 -> (分类名, 子分类名)
    category_map = {
        "search": ("Agent层", "知识检索"),
        "schedule": ("Agent层", "日程管理"),
        "task": ("Agent层", "任务管理"),
        "forum": ("Agent层", "论坛功能"),
        "time_reasoning": ("Agent层", "时间推理"),
        "builtins/file_tools": ("Agent层", "文件工具"),
        "builtins/system_tools": ("Agent层", "系统命令"),
        "builtins/dev_tools": ("Agent层", "开发工具"),
        "builtins/collaboration_tools": ("Agent层", "协作工具"),
    }

    # 工具名称 -> 中文显示名
    display_names = {
        "search_knowledge": "知识库搜索",
        "get_knowledge_graph_context": "知识图谱查询",
        "build_knowledge_graph": "构建知识图谱",
        "hybrid_search": "混合搜索",
        "web_search": "联网搜索",
        "get_schedule_day": "获取日程",
        "create_todo": "创建待办",
        "create_schedule_task": "创建日程任务",
        "create_reminder": "创建提醒",
        "create_goal": "创建目标",
        "get_tasks": "获取任务列表",
        "create_task": "创建任务",
        "update_task_status": "更新任务状态",
        "get_forum_posts": "获取论坛帖子",
        "create_forum_post": "发布论坛帖子",
        "scan_forum_for_instructions": "扫描论坛指令",
        "resolve_time_expression": "解析时间表达式",
        "glob": "文件路径匹配",
        "grep": "文件内容搜索",
        "read_file": "读取文件",
        "write_file": "写入文件",
        "bash": "Bash命令",
        "powershell": "PowerShell命令",
        "git": "Git操作",
        "lsp_tools": "LSP代码导航",
        "team_agent": "团队Agent通信",
        "task_broadcast": "任务广播",
    }

    # 工具描述
    descriptions = {
        "search_knowledge": "搜索用户的私人知识库，返回最相关的文档片段",
        "get_knowledge_graph_context": "获取用户知识图谱的上下文信息",
        "build_knowledge_graph": "从文档构建/更新知识图谱",
        "hybrid_search": "混合搜索，结合向量语义检索和关键词匹配",
        "web_search": "通过 SearxNG 搜索外部网页信息",
        "get_schedule_day": "获取指定日期的 todo/task/reminder/goal 聚合信息",
        "create_todo": "创建指定日期的待办",
        "create_schedule_task": "创建任务，支持优先级和截止日期",
        "create_reminder": "创建提醒，支持自然语言时间",
        "create_goal": "创建指定日期的目标",
        "get_tasks": "获取用户当前的任务列表",
        "create_task": "创建新任务",
        "update_task_status": "更新任务状态",
        "get_forum_posts": "获取论坛帖子列表",
        "create_forum_post": "在论坛发布新帖子",
        "scan_forum_for_instructions": "扫描论坛中的指令类帖子",
        "resolve_time_expression": "解析中文自然语言时间表达",
        "glob": "使用 glob 模式查找文件路径",
        "grep": "在文件中搜索匹配的文本行",
        "read_file": "读取文件内容",
        "write_file": "写入文件内容",
        "bash": "执行 Bash 命令",
        "powershell": "执行 PowerShell 命令",
        "git": "执行 Git 命令",
        "lsp_tools": "LSP 代码导航和查找引用",
        "team_agent": "向团队 Agent 发送消息或请求协作",
        "task_broadcast": "向多个 Agent 广播任务",
    }

    # 需要扫描的模块
    modules_to_scan = [
        ("app.agents.tools.search", "search"),
        ("app.agents.tools.schedule", "schedule"),
        ("app.agents.tools.task", "task"),
        ("app.agents.tools.forum", "forum"),
        ("app.agents.tools.time_reasoning", "time_reasoning"),
        ("app.agents.tools.builtins.file_tools", "builtins/file_tools"),
        ("app.agents.tools.builtins.system_tools", "builtins/system_tools"),
        ("app.agents.tools.builtins.dev_tools", "builtins/dev_tools"),
        ("app.agents.tools.builtins.collaboration_tools", "builtins/collaboration_tools"),
    ]

    for module_name, category_key in modules_to_scan:
        try:
            mod = importlib.import_module(module_name)
        except ImportError:
            continue

        # 扫描模块中所有 @tool 装饰的函数
        for attr_name in dir(mod):
            if attr_name.startswith("_"):
                continue
            attr = getattr(mod, attr_name)
            # 检查是否是 langchain @tool 装饰的对象
            if hasattr(attr, "name") and hasattr(attr, "description"):
                tool_name = attr.name
                tool_desc = attr.description or ""
                # 清理 docstring 中的参数说明用于显示
                display_desc = re.sub(r"\s*Args:\s*.*", "", tool_desc, flags=re.DOTALL).strip()
                display_desc = re.sub(
                    r"\s*Returns?:\s*.*", "", display_desc, flags=re.DOTALL
                ).strip()

                # 获取 category 和 subcategory
                cat_info = category_map.get(category_key, ("Agent层", category_key))
                category, subcategory = cat_info[0], cat_info[1]

                # 获取参数 schema
                params_schema = getattr(attr, "args_schema", None)
                parameters = {}
                if params_schema:
                    try:
                        if hasattr(params_schema, "model_json_schema"):
                            parameters = params_schema.model_json_schema()
                        elif hasattr(params_schema, "schema"):
                            parameters = params_schema.schema()
                    except Exception:
                        pass

                tool_info = ToolInfo(
                    name=tool_name,
                    display_name=display_names.get(tool_name, tool_name),
                    description=descriptions.get(tool_name, display_desc or tool_desc),
                    category=category,
                    subcategory=subcategory,
                    source="agent",
                    source_file=module_name,
                    tags=[],
                    enabled=True,
                    commands=[
                        ToolCommand(
                            name=tool_name,
                            description=tool_desc or display_desc,
                            parameters=parameters,
                        )
                    ],
                    stats=ToolStats(),
                )
                tools.append(tool_info)

    return tools


def _build_manifest_tools() -> list[ToolInfo]:
    """从 YAML manifest 构建工具信息"""
    tools: list[ToolInfo] = []

    # manifest 文件 -> 分类映射
    manifest_map = {
        "file_operator": (
            "注册层",
            "文件操作",
            [
                ToolCommand(name="read_file", description="读取指定路径的文件内容"),
                ToolCommand(name="write_file", description="将内容写入文件"),
                ToolCommand(name="list_directory", description="列出目录内容"),
                ToolCommand(name="search_files", description="递归搜索匹配模式的文件"),
            ],
        ),
        "task_manager": (
            "注册层",
            "任务管理",
            [
                ToolCommand(name="create_task", description="创建新任务"),
                ToolCommand(name="list_tasks", description="列出任务"),
                ToolCommand(name="get_task", description="获取任务详情"),
                ToolCommand(name="complete_task", description="标记任务完成"),
                ToolCommand(name="fail_task", description="标记任务失败"),
            ],
        ),
        "web_fetch": (
            "注册层",
            "网页抓取",
            [
                ToolCommand(name="fetch", description="抓取网页内容"),
                ToolCommand(name="screenshot", description="截取网页截图"),
            ],
        ),
        "web_search": (
            "注册层",
            "联网搜索",
            [
                ToolCommand(name="search", description="执行语义级搜索"),
                ToolCommand(name="deep_search", description="深度搜索，带摘要生成"),
            ],
        ),
    }

    manifest_descriptions = {
        "file_operator": "强大的文件系统操作工具，支持读写、搜索、下载等功能",
        "task_manager": "任务创建、查询、更新和状态管理",
        "web_fetch": "网页内容抓取工具，支持 HTML 解析、截图等功能",
        "web_search": "语义级并发搜索引擎，支持多源搜索和结果聚合",
    }

    for tool_name, (category, subcategory, commands) in manifest_map.items():
        tool_info = ToolInfo(
            name=tool_name,
            display_name=subcategory,
            description=manifest_descriptions.get(tool_name, ""),
            category=category,
            subcategory=subcategory,
            source="manifest",
            source_file=f"app/tools/manifests/{tool_name}.yaml",
            tags=[],
            enabled=True,
            commands=commands,
            stats=ToolStats(),
        )
        tools.append(tool_info)

    return tools


# ============================================================
# 路由
# ============================================================


@router.get("", response_model=ToolsResponse)
async def list_tools(
    current_user: User = Depends(get_current_user),
):
    """获取所有内置工具列表（只读）"""
    # 构建工具列表
    manifest_tools = _build_manifest_tools()
    agent_tools = _build_agent_tools()

    all_tools = manifest_tools + agent_tools

    # 按 category 和 subcategory 分组
    category_map: dict[str, dict[str, list[ToolInfo]]] = {
        "注册层": {},
        "Agent层": {},
    }

    for tool in all_tools:
        cat = tool.category
        subcat = tool.subcategory
        if cat not in category_map:
            category_map[cat] = {}
        if subcat not in category_map[cat]:
            category_map[cat][subcat] = []
        category_map[cat][subcat].append(tool)

    # 构建响应
    categories = []
    for cat_name, subgroups_dict in category_map.items():
        if not subgroups_dict:
            continue
        subgroups = []
        for subcat_name, tools_list in subgroups_dict.items():
            subgroups.append(
                ToolSubgroup(
                    name=subcat_name,
                    display_name=subcat_name,
                    tools=tools_list,
                )
            )
        categories.append(
            ToolCategory(
                name=cat_name,
                display_name=cat_name,
                subgroups=subgroups,
            )
        )

    # 计算摘要
    total_commands = sum(len(t.commands) for t in all_tools)
    active_commands = sum(len(t.commands) for t in all_tools if t.enabled)

    summary = ToolSummary(
        total_commands=total_commands,
        active_commands=active_commands,
        total_tools=len(all_tools),
        manifest_tools=len(manifest_tools),
        agent_tools=len(agent_tools),
    )

    return ToolsResponse(categories=categories, summary=summary)
