"""Abstract LLM adapter interface.

Adapters encapsulate provider-specific request/response handling for:
- tool definitions formats
- tool call extraction
- tool result insertion
- final text extraction
"""

from __future__ import annotations

import abc
from dataclasses import dataclass
from typing import Any


@dataclass(slots=True)
class ToolCall:
    """Normalized tool call representation."""

    id: str
    name: str
    arguments: dict[str, Any]


@dataclass(slots=True)
class ToolResult:
    """Normalized tool result representation."""

    tool_call_id: str
    name: str
    content: str
    is_error: bool = False


class BaseLLMAdapter(abc.ABC):
    """Base interface for LLM adapters."""

    @abc.abstractmethod
    async def chat(
        self,
        messages: list[dict[str, Any]],
        tools: list[dict[str, Any]],
        system: str | None = None,
        **kwargs: Any,
    ) -> Any:
        """Call the LLM and return the raw provider response."""

    @abc.abstractmethod
    def extract_tool_calls(self, response: Any) -> list[ToolCall]:
        """Extract tool calls into normalized `ToolCall` objects."""

    @abc.abstractmethod
    def extract_text(self, response: Any) -> str:
        """Extract final assistant text from a provider response."""

    @abc.abstractmethod
    def is_done(self, response: Any) -> bool:
        """True if the LLM produced the final answer and no tool calls are pending."""

    @abc.abstractmethod
    def append_tool_results(
        self,
        messages: list[dict[str, Any]],
        response: Any,
        tool_results: list[ToolResult],
    ) -> list[dict[str, Any]]:
        """Append assistant tool-call turn(s) and the tool result turns."""

    @abc.abstractmethod
    def count_tokens(self, messages: list[dict[str, Any]], system: str) -> int:
        """Estimate token usage for history trimming."""

    @property
    @abc.abstractmethod
    def provider_name(self) -> str:
        """Provider identifier used by registry.for_llm()."""

    @property
    @abc.abstractmethod
    def supports_parallel_tool_calls(self) -> bool:
        """Whether the provider supports multiple tool calls in one response."""

    @property
    @abc.abstractmethod
    def supports_system_prompt(self) -> bool:
        """Whether the provider accepts system prompt as a separate parameter."""

