"""Anthropic provider adapter (Claude models).

Handles Anthropic-specific concerns:
- System prompt as separate parameter (not in messages array)
- Content block filtering (skips thinking blocks)
- SDK-native API key resolution (ANTHROPIC_API_KEY env var fallback)
"""

from __future__ import annotations

import logging
from typing import Any

from recollect.exceptions import ExtractionError
from recollect.llm.types import CompletionParams, Message

logger = logging.getLogger(__name__)


class AnthropicProvider:
    """Anthropic API provider for Claude models."""

    def __init__(
        self,
        model: str | None = None,
        api_key: str | None = None,
        base_url: str | None = None,
        defaults: CompletionParams | None = None,
        max_retries: int = 2,
        timeout: float = 60.0,
    ) -> None:
        from recollect.config import config

        self._model = model or str(config.get("extraction.anthropic_model", ""))
        if not self._model:
            raise ExtractionError(
                "Anthropic model not configured. Pass model= or set "
                "ANTHROPIC_MODEL environment variable."
            )

        self._defaults = defaults or CompletionParams()

        effective_base_url = (
            base_url or str(config.get("extraction.anthropic_base_url", "")) or None
        )  # Empty string -> None (SDK default)

        import anthropic

        self._client = anthropic.AsyncAnthropic(
            api_key=api_key,  # SDK falls back to ANTHROPIC_API_KEY env var
            base_url=effective_base_url,
            max_retries=max_retries,
            timeout=timeout,
        )

    @property
    def model_name(self) -> str:
        return self._model

    @staticmethod
    def _build_params(
        model: str,
        messages: list[Message],
        max_tokens: int,
        temperature: float,
    ) -> dict[str, Any]:
        """Build Anthropic API parameters.

        Anthropic requires system prompt as a separate parameter,
        not in the messages array.
        """
        system_parts = [m.content for m in messages if m.role == "system"]
        chat_messages = [
            {"role": m.role, "content": m.content}
            for m in messages
            if m.role != "system"
        ]

        params: dict[str, Any] = {
            "model": model,
            "messages": chat_messages,
            "max_tokens": max_tokens,
            "temperature": temperature,
        }
        if system_parts:
            params["system"] = system_parts[0]
        return params

    @staticmethod
    def _extract_text(content: list[Any]) -> str:
        """Extract text from content blocks, skipping thinking blocks."""
        parts = [
            block.text
            for block in content
            if hasattr(block, "type") and block.type == "text"
        ]
        return "\n".join(parts).strip()

    async def complete(
        self,
        messages: list[Message],
        **kwargs: Any,
    ) -> str:
        import anthropic

        effective = {
            **self._defaults.model_dump(exclude_none=True),
            **kwargs,
        }
        max_tokens = int(effective.pop("max_tokens", 1024))
        temperature = float(effective.pop("temperature", 0.0))

        params = self._build_params(self._model, messages, max_tokens, temperature)
        params.update(effective)  # passthrough extra params

        try:
            response = await self._client.messages.create(**params)
            text = self._extract_text(response.content)
            if not text:
                raise ExtractionError(
                    f"Empty response from Anthropic API ({self._model}). "
                    "All content blocks were non-text (e.g. thinking blocks). "
                    "Try increasing max_tokens."
                )
            return text
        except ExtractionError:
            raise
        except anthropic.APIError as exc:
            logger.exception("Anthropic API error for model %s", self._model)
            raise ExtractionError(
                f"Anthropic API error ({self._model}): {exc}"
            ) from exc
        except Exception as exc:
            logger.exception("Anthropic API call failed for model %s", self._model)
            raise ExtractionError(
                f"Anthropic API call failed ({self._model}): {exc}"
            ) from exc
