"""
本地回调工具注册。

通过 Gateway CallbackTool 机制，将本地 Python 函数暴露为 Agent 可调用的工具。
"""

from __future__ import annotations

import threading
from dataclasses import dataclass, field
from typing import Any, Callable


@dataclass
class LocalTool:
    """本地回调工具描述符。

    用法::

        def my_tool(args: dict) -> str:
            return f"结果: {args['input']}"

        tool = LocalTool(
            name="my_tool",
            description="执行自定义操作",
            parameters={
                "type": "object",
                "properties": {
                    "input": {"type": "string", "description": "输入内容"}
                },
                "required": ["input"]
            },
            callback=my_tool,
        )
    """

    name: str
    """工具名称，Agent 调用时使用此名称。"""

    description: str
    """工具功能描述，帮助 LLM 决策何时调用。"""

    parameters: dict[str, Any]
    """JSON Schema 格式的参数定义。"""

    callback: Callable[[dict[str, Any]], str]
    """本地执行函数：接收 args dict，返回结果字符串。"""

    timeout: float = 30.0
    """工具执行超时时间（秒），默认 30 秒。"""

    def execute(self, args: dict[str, Any]) -> str:
        """执行本地回调，带超时控制。"""
        result: list[str] = []
        error: list[Exception] = []

        def _run() -> None:
            try:
                result.append(str(self.callback(args)))
            except Exception as exc:
                error.append(exc)

        thread = threading.Thread(target=_run, daemon=True)
        thread.start()
        thread.join(timeout=self.timeout)

        if thread.is_alive():
            return f"[tool_timeout] 工具 {self.name!r} 执行超时（{self.timeout}s）"
        if error:
            return f"[tool_error] {error[0]}"
        return result[0] if result else ""

    def to_registration_payload(self, callback_url: str) -> dict[str, Any]:
        """生成注册到 Gateway 的请求体。"""
        return {
            "name": self.name,
            "description": self.description,
            "parameters": self.parameters,
            "callbackUrl": callback_url,
        }
