import logging
# import re
import json
import functools
from typing import Optional, Tuple
logger = logging.getLogger('sigmund')


class BaseTool:
    """A base class for tools that process an AI reply."""
    
    def __init__(self, sigmund):
        self._sigmund = sigmund
        
    @property
    def tool_spec(self):
        """The tool spec should corresond to the OpenAI specification for
        function tools.
        """
        return {
            "name": self.__class__.__name__,
            "description": self.__doc__,
            "parameters": {
                "type": "object",
                "properties": self.arguments,
                "required": self.required_arguments,
            }
        }
        
    @property
    def name(self):
        return self.__class__.__name__
    
    def bind(self, args: str) -> callable:
        """Returns a callable that corresponds to a tool function called with
        a string of arguments, which should be in JSON format. The callable 
        itself returns a (message: str, result: dict, needs_feedback: bool)
        tuple, where message is an informative text message as generated by
        the tool, result is a dict with name, args, and content keys that
        correspond to the name and arguments of the function and the result of
        the tool call. needs_feedback indicates whether the model should be
        called again to provide feedback based on the tool result.
        """
        def bound_tool_function():
            try:
                message, result, needs_feedback = self(**json.loads(args))
            except Exception as e:
                message = 'Failed to run tool'
                result = f'The following error occurred while trying to run tool:\n\n{e}'
                needs_feedback = True
            result = {'name': self.name,
                      'args': args,
                      'content': result}
            return message, result, needs_feedback
        return bound_tool_function
        
    def __call__(self) -> Tuple[str, Optional[str], bool]:
        """Should be implemented in a tool with additional arguments that
        match tool specification.
        """
        raise NotImplementedError()