"""pydantic-ai agents — generic LLM infrastructure for NoiseGate."""

from pydantic import BaseModel
from pydantic_ai import Agent

from noisegate.config import get_configured_model
from noisegate.exceptions import LLMError

FALLBACK_MODEL = "anthropic:claude-sonnet-4-6"

_PROVIDER_KEY_MAP = {
    "anthropic": "ANTHROPIC_API_KEY",
    "openai": "OPENAI_API_KEY",
    "google-gla": "GOOGLE_API_KEY",
    "google-vertex": "GOOGLE_API_KEY",
    "mistral": "MISTRAL_API_KEY",
    "ollama": None,
}


def get_default_model() -> str:
    """Return the configured default model, falling back to the built-in default."""
    return get_configured_model() or FALLBACK_MODEL


def _make_llm_error(e: Exception, model: str) -> LLMError:
    """Return an actionable LLMError, upgrading bare auth errors to friendly messages."""
    raw = str(e)
    low = raw.lower()
    if "api_key" in low or "api key" in low or "environment variable" in low or "apikey" in low:
        provider = model.split(":")[0] if ":" in model else "anthropic"
        env_var = _PROVIDER_KEY_MAP.get(provider, f"{provider.upper()}_API_KEY")
        if env_var:
            hint = (
                f"No API key found for provider '{provider}'.\n\n"
                f"  Run [bold]noisegate llm[/bold] to configure an LLM provider,\n"
                f"  or set the environment variable directly: export {env_var}=<your-key>\n"
            )
        else:
            hint = f"LLM error with provider '{provider}': {raw}"
        return LLMError(hint)
    return LLMError(raw)


def run_structured_llm_call[T: BaseModel](
    model: str,
    output_type: type[T],
    system_prompt: str,
    user_message: str,
) -> tuple[T, int, int]:
    """Run an LLM call with structured output.

    Returns (output, prompt_tokens, completion_tokens).
    """
    try:
        agent: Agent[None, T] = Agent(
            model, output_type=output_type, system_prompt=system_prompt
        )
        result = agent.run_sync(user_message)
    except Exception as e:
        raise _make_llm_error(e, model) from e
    usage = result.usage()
    return result.output, usage.request_tokens or 0, usage.response_tokens or 0
