"""FunctionTool - 将普通 Python 函数包装为 Tool"""

import inspect
from typing import Any, Callable, Awaitable

from agentkit.tools.base import Tool


class FunctionTool(Tool):
    """将普通 Python 函数包装为 Tool

    自动从函数签名推断 input_schema。
    """

    def __init__(
        self,
        name: str,
        description: str,
        func: Callable[..., Awaitable[dict]] | Callable[..., dict],
        input_schema: dict[str, Any] | None = None,
        output_schema: dict[str, Any] | None = None,
        version: str = "1.0.0",
        tags: list[str] | None = None,
    ):
        super().__init__(
            name=name,
            description=description,
            input_schema=input_schema or self._infer_schema(func),
            output_schema=output_schema,
            version=version,
            tags=tags,
        )
        self._func = func

    async def execute(self, **kwargs) -> dict:
        result = self._func(**kwargs)
        if inspect.isawaitable(result):
            result = await result
        if not isinstance(result, dict):
            result = {"result": result}
        return result

    @staticmethod
    def _infer_schema(func: Callable) -> dict:
        """从函数签名推断 JSON Schema"""
        sig = inspect.signature(func)
        properties = {}
        required = []

        for param_name, param in sig.parameters.items():
            if param_name in ("self", "cls"):
                continue

            param_type = "string"
            if param.annotation != inspect.Parameter.empty:
                if param.annotation in (int, float):
                    param_type = "number"
                elif param.annotation == bool:
                    param_type = "boolean"
                elif param.annotation in (list, tuple):
                    param_type = "array"
                elif param.annotation == dict:
                    param_type = "object"

            properties[param_name] = {"type": param_type}

            if param.default == inspect.Parameter.empty:
                required.append(param_name)

        schema = {
            "type": "object",
            "properties": properties,
        }
        if required:
            schema["required"] = required
        return schema
