"""
tools/base.py — BaseTool abstract class.

All tools inherit from this. The tool registry discovers them and builds
the schema list sent to the AI provider on every agent call.
"""
from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import dataclass


@dataclass
class ToolResult:
    """Normalised return value from every tool execution."""
    success: bool
    data: dict | list | str | None = None
    error: str | None = None

    def to_dict(self) -> dict:
        if self.success:
            return {"success": True, "data": self.data}
        result: dict = {"success": False, "error": self.error}
        if self.data is not None:
            result["data"] = self.data
        return result


class BaseTool(ABC):
    """
    Abstract base for all aide tools.

    Subclasses must set class-level attributes:
        name            — used in tool schema and audit log
        description     — what the AI sees
        input_schema    — JSON Schema for parameters (Anthropic-native format)

    Optional overrides:
        requires_confirmation       — default False
        allowed_in_scheduled_tasks  — default True
    """

    name: str
    description: str
    input_schema: dict

    requires_confirmation: bool = False
    allowed_in_scheduled_tasks: bool = True

    @abstractmethod
    async def execute(self, **kwargs) -> ToolResult:
        """
        Run the tool. Never raises — always returns a ToolResult.
        The dispatcher catches any unexpected exceptions as a safety net.
        """

    def get_schema(self) -> dict:
        """Return the tool schema in aide-internal / Anthropic-native format."""
        return {
            "name": self.name,
            "description": self.description,
            "input_schema": self.input_schema,
        }

    async def should_confirm(self, **kwargs) -> bool:
        """
        Return True if this specific call requires confirmation.
        Override in subclasses for per-call logic (e.g. domain allow-lists).
        Default: return self.requires_confirmation.
        """
        return self.requires_confirmation

    def confirmation_description(self, **kwargs) -> str:
        """
        Human-readable description of the action shown to the user
        when confirmation is required. Override for better messages.
        """
        args_str = ", ".join(f"{k}={v!r}" for k, v in kwargs.items())
        return f"{self.name}({args_str})"
