from __future__ import annotations

import typing
import traceback

from langbot_plugin.api.definition.components.manifest import ComponentManifest
from langbot_plugin.api.entities.events import pipeline_query

from .. import loader
import langbot_plugin.api.entities.builtin.resource.tool as resource_tool


# @loader.loader_class('plugin-tool-loader')
class PluginToolLoader(loader.ToolLoader):
    """插件工具加载器。

    本加载器中不存储工具信息，仅负责从插件系统中获取工具信息。
    """

    async def get_tools(self, bound_plugins: list[str] | None = None) -> list[resource_tool.LLMTool]:
        # 从插件系统获取工具（内容函数）
        all_functions: list[resource_tool.LLMTool] = []

        for tool in await self.ap.plugin_connector.list_tools(bound_plugins):
            tool_obj = resource_tool.LLMTool(
                name=tool.metadata.name,
                human_desc=tool.metadata.description.en_US,
                description=tool.spec['llm_prompt'],
                parameters=tool.spec['parameters'],
                func=lambda parameters: {},
            )
            all_functions.append(tool_obj)

        return all_functions

    async def get_tool_catalog(self, bound_plugins: list[str] | None = None) -> list[dict[str, typing.Any]]:
        catalog: list[dict[str, typing.Any]] = []

        for tool in await self.ap.plugin_connector.list_tools(bound_plugins):
            catalog.append(
                {
                    'name': tool.metadata.name,
                    'description': tool.spec['llm_prompt'],
                    'human_desc': tool.metadata.description.en_US,
                    'parameters': tool.spec['parameters'],
                    'source': 'plugin',
                    'source_name': tool.owner,
                    'source_id': tool.owner,
                }
            )

        return catalog

    async def has_tool(self, name: str) -> bool:
        """检查工具是否存在"""
        for tool in await self.ap.plugin_connector.list_tools():
            if tool.metadata.name == name:
                return True
        return False

    async def get_tool(self, name: str) -> ComponentManifest | None:
        for tool in await self.ap.plugin_connector.list_tools():
            if tool.metadata.name == name:
                return tool
        return None

    async def invoke_tool(self, name: str, parameters: dict, query: pipeline_query.Query) -> typing.Any:
        try:
            return await self.ap.plugin_connector.call_tool(
                name,
                parameters,
                session=query.session,
                query_id=query.query_id,
                query_uuid=query.query_uuid,
            )
        except Exception as e:
            self.ap.logger.error(f'执行函数 {name} 时发生错误: {e}')
            traceback.print_exc()
            return f'error occurred when executing function {name}: {e}'

    async def shutdown(self):
        """关闭工具"""
        pass
