"""Abstract base class for LLM providers."""

from abc import ABC, abstractmethod
from collections.abc import AsyncGenerator
from typing import Any

from kguru.utils import extract_json


class BaseLLM(ABC):
    """
    Abstract base class for LLM providers.

    Provides a consistent API for different LLM services with async support.
    """

    def __init__(
        self,
        model: str,
        api_key: str,
        api_base: str | None = None,
        **additional_kwargs: Any,
    ) -> None:
        """
        Initialize the LLM provider.

        Args:
            model: Model identifier
            api_key: API key for authentication
            api_base: Base URL for API calls
            **additional_kwargs: Additional provider-specific arguments
        """
        self.model = model
        self.api_key = api_key
        self.api_base = api_base
        self._client: Any = None
        self._aclient: Any = None
        self._additional_kwargs = additional_kwargs

    @property
    @abstractmethod
    def client(self) -> Any:
        """Get synchronous client instance."""
        pass

    @property
    @abstractmethod
    def aclient(self) -> Any:
        """Get async client instance."""
        pass

    @abstractmethod
    async def reason(self, **kwargs: Any) -> str:
        """
        Generate a text response.

        Args:
            **kwargs: Provider-specific arguments (messages, temperature, etc.)

        Returns:
            Generated text response
        """
        pass

    @abstractmethod
    async def stream(self, **kwargs: Any) -> AsyncGenerator[str, None]:
        """
        Stream text response chunks.

        Args:
            **kwargs: Provider-specific arguments (messages, temperature, etc.)

        Yields:
            Text chunks as they are generated
        """
        pass

    async def reason_structure(self, **kwargs: Any) -> dict[str, Any]:
        """
        Generate a structured JSON response.

        Default implementation uses reason() and extracts JSON.
        Subclasses can override for provider-specific structured output.

        Args:
            **kwargs: Provider-specific arguments (messages, temperature, etc.)

        Returns:
            Parsed JSON response as dictionary
        """
        text = await self.reason(**kwargs)
        return extract_json(text)

    def validate_configuration(self) -> None:
        """
        Validate the configuration of the LLM provider.

        Subclasses can override to implement provider-specific validation.
        """
        pass
