"""
LLM Configuration

Configuration dataclasses for LLM providers, supporting
both Claude (primary) and OpenAI (fallback).
"""

from dataclasses import dataclass
from enum import Enum

from sage.llm.base import LLMProvider


class ModelFamily(str, Enum):
    """Model families available."""

    # Anthropic models
    CLAUDE_3_5_SONNET = "claude-3-5-sonnet-20241022"
    CLAUDE_3_5_HAIKU = "claude-3-5-haiku-20241022"
    CLAUDE_3_OPUS = "claude-3-opus-20240229"

    # OpenAI models
    GPT_4O = "gpt-4o"
    GPT_4O_MINI = "gpt-4o-mini"
    GPT_4_TURBO = "gpt-4-turbo"


# Default models for each provider
DEFAULT_MODELS = {
    LLMProvider.ANTHROPIC: ModelFamily.CLAUDE_3_5_SONNET,
    LLMProvider.OPENAI: ModelFamily.GPT_4O,
}


@dataclass
class LLMConfig:
    """
    Configuration for LLM providers.

    Supports configuring both primary (Claude) and fallback (OpenAI)
    providers with appropriate defaults for NCS applications.

    Example:
        config = LLMConfig(
            anthropic_api_key="sk-ant-...",
            openai_api_key="sk-...",  # Optional fallback
            temperature=0.3,  # Low for safety-critical
        )
    """

    # API keys
    anthropic_api_key: str | None = None
    openai_api_key: str | None = None

    # Primary provider settings
    primary_provider: LLMProvider = LLMProvider.ANTHROPIC
    primary_model: str | None = None  # Uses default if not specified

    # Fallback provider settings
    fallback_provider: LLMProvider | None = LLMProvider.OPENAI
    fallback_model: str | None = None

    # Generation parameters
    temperature: float = 0.3  # Low default for safety-critical domain
    max_tokens: int = 4096
    top_p: float = 0.95

    # Safety parameters for NCS
    max_retries: int = 3
    retry_delay: float = 1.0
    timeout_seconds: float = 120.0

    # Caching
    enable_caching: bool = True
    cache_ttl_seconds: int = 3600

    def get_primary_model(self) -> str:
        """Get the primary model name."""
        if self.primary_model:
            return self.primary_model
        return DEFAULT_MODELS[self.primary_provider].value

    def get_fallback_model(self) -> str | None:
        """Get the fallback model name."""
        if not self.fallback_provider:
            return None
        if self.fallback_model:
            return self.fallback_model
        return DEFAULT_MODELS[self.fallback_provider].value

    def validate(self) -> list[str]:
        """
        Validate configuration.

        Returns:
            List of validation errors (empty if valid)
        """
        errors = []

        # Check API key for primary provider
        if self.primary_provider == LLMProvider.ANTHROPIC:
            if not self.anthropic_api_key:
                errors.append("anthropic_api_key required for Anthropic provider")
        elif self.primary_provider == LLMProvider.OPENAI:
            if not self.openai_api_key:
                errors.append("openai_api_key required for OpenAI provider")

        # Check API key for fallback if configured
        if self.fallback_provider == LLMProvider.ANTHROPIC:
            if not self.anthropic_api_key:
                errors.append("anthropic_api_key required for Anthropic fallback")
        elif self.fallback_provider == LLMProvider.OPENAI:
            if not self.openai_api_key:
                errors.append("openai_api_key required for OpenAI fallback")

        # Validate temperature
        if not 0.0 <= self.temperature <= 2.0:
            errors.append("temperature must be between 0.0 and 2.0")

        # Validate max_tokens
        if self.max_tokens < 1:
            errors.append("max_tokens must be positive")

        return errors


@dataclass
class AnthropicConfig:
    """Anthropic-specific configuration."""

    api_key: str
    model: str = ModelFamily.CLAUDE_3_5_SONNET.value
    max_tokens: int = 4096
    temperature: float = 0.3
    top_p: float = 0.95
    timeout: float = 120.0

    # Anthropic-specific
    api_base_url: str = "https://api.anthropic.com"
    anthropic_version: str = "2023-06-01"


@dataclass
class OpenAIConfig:
    """OpenAI-specific configuration."""

    api_key: str
    model: str = ModelFamily.GPT_4O.value
    max_tokens: int = 4096
    temperature: float = 0.3
    top_p: float = 0.95
    timeout: float = 120.0

    # OpenAI-specific
    organization: str | None = None
    api_base_url: str = "https://api.openai.com/v1"
