from typing import List, Type

from langchain_core.tools import BaseTool, StructuredTool
from langchain_core.utils.pydantic import get_fields

import langchain_community.tools
from langchain_community.tools import _DEPRECATED_TOOLS
from langchain_community.tools import __all__ as tools_all

_EXCLUDE = {
    BaseTool,
    StructuredTool,
}


def _get_tool_classes(skip_tools_without_default_names: bool) -> List[Type[BaseTool]]:
    results = []
    for tool_class_name in tools_all:
        if tool_class_name in _DEPRECATED_TOOLS:
            continue
        # Resolve the str to the class
        tool_class = getattr(langchain_community.tools, tool_class_name)
        if isinstance(tool_class, type) and issubclass(tool_class, BaseTool):
            if tool_class in _EXCLUDE:
                continue
            default_name = get_fields(tool_class)["name"].default
            if skip_tools_without_default_names and default_name in [
                None,
                "",
            ]:
                continue
            if not isinstance(default_name, str):
                continue

            results.append(tool_class)
    return results


def test_tool_names_unique() -> None:
    """Test that the default names for our core tools are unique."""
    tool_classes = _get_tool_classes(skip_tools_without_default_names=True)
    names = sorted([tool_cls.model_fields["name"].default for tool_cls in tool_classes])
    duplicated_names = [name for name in names if names.count(name) > 1]
    # only one duplicate currently exists
    assert duplicated_names == ["sql_db_query", "sql_db_query"]
