"""
Base provider adapter interface.

Follows the same Protocol + ABC pattern as
apps/kv-eviction-optimizer/kv_evict/policies/base.py.

Each adapter translates between the unified OpenAI-compatible format
and a specific provider's native HTTP API.
"""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Any, AsyncIterator, Dict, Protocol, Tuple, runtime_checkable

from proxy.schemas import (
    ChatCompletionChunk,
    ChatCompletionRequest,
    ChatCompletionResponse,
    TokenPricing,
)


@runtime_checkable
class ProviderAdapter(Protocol):
    """Protocol defining the interface for provider adapters.

    Any class with matching methods will satisfy this protocol (duck typing).

    Example:
        >>> class MyAdapter:
        ...     @property
        ...     def name(self) -> str:
        ...         return "my_provider"
        ...     @property
        ...     def base_url(self) -> str:
        ...         return "https://api.myprovider.com"
        ...     # ... other methods ...
        >>> isinstance(MyAdapter(), ProviderAdapter)
        True
    """

    @property
    def name(self) -> str:
        """Human-readable provider name for logging and display."""
        ...

    @property
    def base_url(self) -> str:
        """Base URL for the provider's API."""
        ...

    def translate_request(
        self,
        request: ChatCompletionRequest,
        api_key: str,
    ) -> Tuple[str, Dict[str, str], Dict[str, Any]]:
        """Translate unified request to provider-native format.

        Args:
            request: Unified chat completion request.
            api_key: User's API key for the provider.

        Returns:
            Tuple of (url, headers, body_dict) for the provider's API.
        """
        ...

    def translate_response(
        self,
        status_code: int,
        headers: Dict[str, str],
        body: Dict[str, Any],
    ) -> ChatCompletionResponse:
        """Translate provider-native response to unified format.

        Args:
            status_code: HTTP status code from provider.
            headers: Response headers from provider.
            body: Parsed JSON response body from provider.

        Returns:
            Unified ChatCompletionResponse.
        """
        ...

    def parse_stream_chunk(
        self,
        raw_line: str,
    ) -> ChatCompletionChunk | None:
        """Parse a single SSE line from the provider's stream.

        Args:
            raw_line: A single line from the SSE stream (after 'data: ' prefix).

        Returns:
            Parsed chunk, or None if the line is not a data event (e.g., keep-alive).
        """
        ...

    def get_pricing(self, model: str) -> TokenPricing:
        """Get per-token pricing for the given model.

        Args:
            model: Model identifier (e.g., "gpt-4o", "claude-sonnet-4-20250514").

        Returns:
            TokenPricing with costs per 1K tokens.
        """
        ...


class BaseProviderAdapter(ABC):
    """Abstract base class for provider adapters.

    Provides common functionality. Prefer inheriting from this class
    for custom adapters.
    """

    def __init__(self, base_url: str):
        self._base_url = base_url.rstrip("/")

    @property
    @abstractmethod
    def name(self) -> str: ...

    @property
    def base_url(self) -> str:
        return self._base_url

    @abstractmethod
    def translate_request(
        self,
        request: ChatCompletionRequest,
        api_key: str,
    ) -> Tuple[str, Dict[str, str], Dict[str, Any]]: ...

    @abstractmethod
    def translate_response(
        self,
        status_code: int,
        headers: Dict[str, str],
        body: Dict[str, Any],
    ) -> ChatCompletionResponse: ...

    @abstractmethod
    def parse_stream_chunk(
        self,
        raw_line: str,
    ) -> ChatCompletionChunk | None: ...

    @abstractmethod
    def get_pricing(self, model: str) -> TokenPricing: ...
