"""工具迁移和向后兼容层 - Phase 6.1

将现有 @tool 装饰的工具迁移到 ToolRegistry，同时保持向后兼容。
"""

from functools import wraps
from typing import Any, Callable

from app.agents.tools.manifest import (
    PermissionClass,
    SideEffectScope,
    ToolCategory,
    ToolManifest,
)
from app.agents.tools.registry import get_tool_registry


# 现有工具的类别映射
_TOOL_CATEGORY_MAP: dict[str, tuple[ToolCategory, PermissionClass, SideEffectScope]] = {
    # 知识检索 - 只读
    "search_knowledge": (ToolCategory.READ, PermissionClass.READ, SideEffectScope.NONE),
    "get_knowledge_graph_context": (ToolCategory.READ, PermissionClass.READ, SideEffectScope.NONE),
    "hybrid_search": (ToolCategory.READ, PermissionClass.READ, SideEffectScope.NONE),
    "web_search": (ToolCategory.NETWORK, PermissionClass.EXTERNAL, SideEffectScope.NETWORK),
    # 知识构建 - 写入
    "build_knowledge_graph": (
        ToolCategory.WRITE,
        PermissionClass.WRITE,
        SideEffectScope.LOCAL_STATE,
    ),
    # 任务工具
    "get_tasks": (ToolCategory.READ, PermissionClass.READ, SideEffectScope.NONE),
    "create_task": (ToolCategory.WRITE, PermissionClass.WRITE, SideEffectScope.LOCAL_STATE),
    "update_task_status": (ToolCategory.WRITE, PermissionClass.WRITE, SideEffectScope.LOCAL_STATE),
    # 日程工具
    "get_schedule_day": (ToolCategory.READ, PermissionClass.READ, SideEffectScope.NONE),
    "create_todo": (ToolCategory.WRITE, PermissionClass.WRITE, SideEffectScope.LOCAL_STATE),
    "create_schedule_task": (
        ToolCategory.WRITE,
        PermissionClass.WRITE,
        SideEffectScope.LOCAL_STATE,
    ),
    "create_reminder": (ToolCategory.WRITE, PermissionClass.WRITE, SideEffectScope.LOCAL_STATE),
    "create_goal": (ToolCategory.WRITE, PermissionClass.WRITE, SideEffectScope.LOCAL_STATE),
    "resolve_time_expression": (ToolCategory.READ, PermissionClass.READ, SideEffectScope.NONE),
    # 论坛工具
    "get_forum_posts": (ToolCategory.READ, PermissionClass.READ, SideEffectScope.NONE),
    "create_forum_post": (ToolCategory.WRITE, PermissionClass.WRITE, SideEffectScope.LOCAL_STATE),
    "scan_forum_for_instructions": (ToolCategory.READ, PermissionClass.READ, SideEffectScope.NONE),
}


def get_tool_category(name: str) -> tuple[ToolCategory, PermissionClass, SideEffectScope]:
    """获取工具的类别信息"""
    return _TOOL_CATEGORY_MAP.get(
        name,
        (ToolCategory.EXTERNAL, PermissionClass.EXTERNAL, SideEffectScope.NETWORK),
    )


def infer_tags_from_docstring(docstring: str | None) -> list[str]:
    """从 docstring 推断工具标签"""
    if not docstring:
        return []
    tags = []
    doc_lower = docstring.lower()
    if "搜索" in docstring or "查询" in docstring or "search" in doc_lower:
        tags.append("search")
    if "创建" in docstring or "新建" in docstring or "create" in doc_lower:
        tags.append("create")
    if "获取" in docstring or "读取" in docstring or "get" in doc_lower:
        tags.append("read")
    if "更新" in docstring or "修改" in docstring or "update" in doc_lower:
        tags.append("update")
    return tags


def migrate_tool(tool_func: Callable) -> Callable:
    """将现有 @tool 装饰的函数迁移到 ToolRegistry

    Args:
        tool_func: LangChain @tool 装饰的函数

    Returns:
        原函数（已注册到 registry）
    """
    registry = get_tool_registry()

    # 如果已经注册，跳过
    if registry.get(tool_func.name):
        return tool_func

    # 获取类别信息
    category, permission, side_effect = get_tool_category(tool_func.name)

    # 从 docstring 提取 description
    description = tool_func.description if hasattr(tool_func, "description") else ""

    # 推断 tags
    tags = infer_tags_from_docstring(description)
    tags.append("migrated")

    # 创建 manifest
    manifest = ToolManifest(
        name=tool_func.name,
        description=description,
        category=category,
        parameters={},  # LangChain @tool 动态处理参数
        return_schema={},
        permission_class=permission,
        side_effect_scope=side_effect,
        requires_confirmation=side_effect != SideEffectScope.NONE,
        is_streaming=False,
        tags=tags,
    )

    # 注册到 registry
    registry.register(manifest, tool_func)

    return tool_func


def migrate_all_tools() -> int:
    """迁移所有现有工具到 ToolRegistry

    Returns:
        迁移的工具数量
    """
    from app.agents.tools import (
        ALL_TOOLS,
        KNOWLEDGE_GRAPH_TOOLS,
        KNOWLEDGE_RETRIEVAL_TOOLS,
        SCHEDULE_READ_TOOLS,
        SCHEDULE_WRITE_TOOLS,
        TASK_TOOLS,
        FORUM_TOOLS,
    )

    all_tools = (
        KNOWLEDGE_RETRIEVAL_TOOLS
        + KNOWLEDGE_GRAPH_TOOLS
        + TASK_TOOLS
        + SCHEDULE_READ_TOOLS
        + SCHEDULE_WRITE_TOOLS
        + FORUM_TOOLS
    )

    count = 0
    for tool in all_tools:
        try:
            migrate_tool(tool)
            count += 1
        except Exception as e:
            print(f"Failed to migrate tool {getattr(tool, 'name', 'unknown')}: {e}")

    return count


class BackwardCompatTool:
    """向后兼容工具包装器

    确保现有代码通过 registry.get_executor() 仍能正常调用工具。
    """

    def __init__(self, name: str):
        self.name = name
        self._registry = get_tool_registry()

    def __call__(self, *args, **kwargs) -> Any:
        executor = self._registry.get_executor(self.name)
        if executor is None:
            raise ValueError(f"Tool not found in registry: {self.name}")
        return executor(*args, **kwargs)

    def invoke(self, tool_input: dict[str, Any]) -> Any:
        """LangChain 风格的 invoke 调用"""
        executor = self._registry.get_executor(self.name)
        if executor is None:
            raise ValueError(f"Tool not found in registry: {self.name}")

        # 处理位置参数
        if isinstance(tool_input, dict):
            return executor(**tool_input)
        return executor(tool_input)


def create_compat_layer() -> dict[str, BackwardCompatTool]:
    """创建向后兼容层

    返回一个字典，允许通过名称访问兼容的工具包装器。
    """
    registry = get_tool_registry()
    tools = registry.list_all()

    return {tool.name: BackwardCompatTool(tool.name) for tool in tools}


# 自动迁移装饰器
def auto_migrate(func: Callable) -> Callable:
    """自动迁移装饰器

    用于装饰新的 @tool 函数，自动注册到 registry。
    """

    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)

    # 迁移到 registry
    migrate_tool(wrapper)

    return wrapper


# 便捷函数：获取兼容的工具执行器
def get_tool_executor(name: str) -> Callable | None:
    """获取工具执行器（兼容层）

    优先从 registry 获取，fallback 到直接导入。
    """
    registry = get_tool_registry()
    executor = registry.get_executor(name)

    if executor is not None:
        return executor

    # Fallback: 直接从模块导入（仅用于迁移期间）
    try:
        from app.agents.tools import (
            TASK_TOOLS,
            SCHEDULE_READ_TOOLS,
            SCHEDULE_WRITE_TOOLS,
            FORUM_TOOLS,
            KNOWLEDGE_RETRIEVAL_TOOLS,
        )

        all_tools = (
            KNOWLEDGE_RETRIEVAL_TOOLS
            + TASK_TOOLS
            + SCHEDULE_READ_TOOLS
            + SCHEDULE_WRITE_TOOLS
            + FORUM_TOOLS
        )

        for tool in all_tools:
            if hasattr(tool, "name") and tool.name == name:
                return tool
    except ImportError:
        pass

    return None
