import json
from typing import Any, List

import inspect
from typing import Callable
from swarms.utils.formatter import formatter


def scrape_tool_func_docs(fn: Callable) -> str:
    """
    Scrape the docstrings and parameters of a function decorated with `tool` and return a formatted string.

    Args:
        fn (Callable): The function to scrape.

    Returns:
        str: A string containing the function's name, documentation string, and a list of its parameters. Each parameter is represented as a line containing the parameter's name, default value, and annotation.
    """
    try:
        # If the function is a tool, get the original function
        if hasattr(fn, "func"):
            fn = fn.func

        signature = inspect.signature(fn)
        parameters = []
        for name, param in signature.parameters.items():
            parameters.append(
                f"Name: {name}, Type:"
                f" {param.default if param.default is not param.empty else 'None'},"
                " Annotation:"
                f" {param.annotation if param.annotation is not param.empty else 'None'}"
            )
        parameters_str = "\n".join(parameters)
        return (
            f"Function: {fn.__name__}\nDocstring:"
            f" {inspect.getdoc(fn)}\nParameters:\n{parameters_str}"
        )
    except Exception as error:
        (
            formatter.print_panel(
                f"Error scraping tool function docs {error} try"
                " optimizing your inputs with different"
                " variables and attempt once more."
            ),
        )

        raise error


def tool_find_by_name(tool_name: str, tools: List[Any]):
    """Find the tool by name"""
    for tool in tools:
        if tool.name == tool_name:
            return tool
    return None


def is_str_valid_func_output(
    output: str = None, function_map: callable = None
):
    """
    Check if the output is a valid JSON string, and if the function name in the JSON matches any name in the function map.

    Args:
        output (str): The output to check.
        function_map (dict): A dictionary mapping function names to functions.

    Returns:
        bool: True if the output is valid and the function name matches, False otherwise.
    """
    try:
        # Parse the output as JSON
        data = json.loads(output)

        # Check if the output matches the schema
        if (
            data.get("type") == "function"
            and "function" in data
            and "name" in data["function"]
        ):

            # Check if the function name matches any name in the function map
            function_name = data["function"]["name"]
            if function_name in function_map:
                return True

    except json.JSONDecodeError:
        pass

    return False
