"""LLM provider abstraction — thin adapters for Anthropic and OpenAI-compatible APIs."""

from __future__ import annotations

import logging
from dataclasses import dataclass
from typing import Protocol

log = logging.getLogger(__name__)


@dataclass(frozen=True)
class LLMResponse:
    """Normalized response from any LLM provider."""
    text: str
    input_tokens: int
    output_tokens: int
    truncated: bool


class LLMClient(Protocol):
    """Protocol for LLM API clients."""
    async def complete(
        self,
        model: str,
        prompt: str,
        max_tokens: int,
        temperature: float,
    ) -> LLMResponse:
        ...


class AnthropicClient:
    """Wraps anthropic.AsyncAnthropic with lazy import."""

    def __init__(self, api_key: str | None = None):
        try:
            from anthropic import AsyncAnthropic
        except ImportError:
            raise ImportError(
                "The 'anthropic' package is required for the Anthropic provider. "
                "Install it with: pip install anthropic"
            )
        self._client = AsyncAnthropic(api_key=api_key or None)

    async def complete(
        self,
        model: str,
        prompt: str,
        max_tokens: int,
        temperature: float,
    ) -> LLMResponse:
        response = await self._client.messages.create(
            model=model,
            max_tokens=max_tokens,
            temperature=temperature,
            messages=[{"role": "user", "content": prompt}],
        )
        return LLMResponse(
            text=response.content[0].text,
            input_tokens=response.usage.input_tokens,
            output_tokens=response.usage.output_tokens,
            truncated=response.stop_reason == "max_tokens",
        )


class OpenAIClient:
    """Wraps openai.AsyncOpenAI with lazy import. Accepts base_url for Ollama/vLLM/etc."""

    def __init__(self, api_key: str | None = None, base_url: str | None = None):
        try:
            from openai import AsyncOpenAI
        except ImportError:
            raise ImportError(
                "The 'openai' package is required for the OpenAI provider. "
                "Install it with: pip install openai  (or pip install loom-agents[openai])"
            )
        kwargs = {}
        if api_key:
            kwargs["api_key"] = api_key
        if base_url:
            kwargs["base_url"] = base_url
        self._client = AsyncOpenAI(**kwargs)

    async def complete(
        self,
        model: str,
        prompt: str,
        max_tokens: int,
        temperature: float,
    ) -> LLMResponse:
        response = await self._client.chat.completions.create(
            model=model,
            max_tokens=max_tokens,
            temperature=temperature,
            messages=[{"role": "user", "content": prompt}],
        )
        choice = response.choices[0]
        usage = response.usage
        return LLMResponse(
            text=choice.message.content or "",
            input_tokens=usage.prompt_tokens if usage else 0,
            output_tokens=usage.completion_tokens if usage else 0,
            truncated=choice.finish_reason == "length",
        )


def create_client(config) -> LLMClient:
    """Factory: create an LLM client based on SkillsConfig.

    Args:
        config: SkillsConfig instance with provider, api_key, and base_url fields.

    Returns:
        An LLMClient implementation.

    Raises:
        ValueError: If the provider is not recognized.
        ImportError: If the required SDK is not installed.
    """
    provider = getattr(config, "provider", "anthropic")
    api_key = getattr(config, "api_key", "") or None
    base_url = getattr(config, "base_url", "") or None

    if provider == "anthropic":
        return AnthropicClient(api_key=api_key)
    elif provider == "openai":
        return OpenAIClient(api_key=api_key, base_url=base_url)
    else:
        raise ValueError(
            f"Unknown LLM provider: '{provider}'. "
            f"Supported providers: 'anthropic', 'openai'"
        )
