"""Configuration management for the ReviewIQ pipeline."""

from __future__ import annotations

from typing import Literal

from pydantic import Field, SecretStr, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict


class Config(BaseSettings):
    """Pipeline configuration loaded from environment variables or passed directly."""

    model_config = SettingsConfigDict(
        env_prefix="REVIEWIQ_",
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )

    # Database
    database_url: str = Field(
        default="postgresql://localhost:5432/reviewiq",
        description="PostgreSQL connection string",
    )
    db_pool_min_size: int = Field(default=2, ge=1, le=50)
    db_pool_max_size: int = Field(default=10, ge=1, le=100)

    # LLM Provider
    llm_provider: Literal["openai", "anthropic"] = Field(
        default="openai",
        description="LLM provider to use for classification",
    )
    openai_api_key: SecretStr | None = Field(
        default=None,
        description="OpenAI API key",
    )
    anthropic_api_key: SecretStr | None = Field(
        default=None,
        description="Anthropic API key",
    )

    # Model settings
    llm_model: str = Field(
        default="gpt-4o-mini",
        description="LLM model to use for classification",
    )
    llm_temperature: float = Field(default=0.0, ge=0.0, le=2.0)
    llm_max_retries: int = Field(default=3, ge=1, le=10)
    llm_timeout_seconds: int = Field(default=60, ge=10, le=300)

    # Embedding settings
    embedding_model: str = Field(
        default="all-MiniLM-L6-v2",
        description="Sentence transformer model for embeddings",
    )
    embedding_dimension: int = Field(
        default=384,
        description="Expected embedding dimension",
    )

    # Taxonomy
    taxonomy_version: str = Field(
        default="v5.1",
        description="URT taxonomy version",
    )

    # Classification
    classification_profile: Literal["lite", "core", "standard", "full"] = Field(
        default="standard",
        description="Classification profile to use",
    )
    max_spans_per_review: int = Field(default=10, ge=1, le=20)

    # Processing
    batch_size: int = Field(default=50, ge=1, le=500)
    trust_score_floor: float = Field(default=0.2, ge=0.0, le=1.0)

    # Batched Classification
    classification_batch_size: int = Field(
        default=0,
        ge=0,
        le=200,
        description="Number of reviews per LLM call. 0 = auto-calculate based on context window",
    )
    classification_max_concurrent: int = Field(
        default=0,
        ge=0,
        description="Maximum concurrent batch requests. 0 = unlimited (run all batches in parallel)",
    )
    classification_target_utilization: float = Field(
        default=0.70,
        ge=0.3,
        le=0.85,
        description="Target context window utilization. Optimal: 0.60-0.75. Above 0.85 causes ~23% quality degradation.",
    )
    use_prompt_caching: bool = Field(
        default=True,
        description="Enable prompt caching for cost reduction (OpenAI/Anthropic)",
    )

    # Smart Review Router (cost optimization)
    router_enabled: bool = Field(
        default=False,
        description="Enable smart review routing to skip/route trivial reviews",
    )
    router_skip_enabled: bool = Field(
        default=True,
        description="Allow SKIP tier (no LLM, assign generic code)",
    )
    router_cheap_model_enabled: bool = Field(
        default=True,
        description="Allow CHEAP tier (use Haiku instead of Sonnet)",
    )
    router_cheap_model: str = Field(
        default="claude-3-5-haiku-20241022",
        description="Model to use for CHEAP tier routing",
    )
    router_conservative: bool = Field(
        default=True,
        description="Use conservative routing (fewer false negatives)",
    )

    # Migrations
    migrations_path: str = Field(
        default="",
        description="Path to migrations directory (empty for default)",
    )

    @field_validator("llm_provider")
    @classmethod
    def validate_provider_api_key(cls, v: str) -> str:
        """Validate that provider is supported."""
        if v not in ("openai", "anthropic"):
            raise ValueError(f"Unsupported LLM provider: {v}")
        return v

    def get_llm_api_key(self) -> str:
        """Get the API key for the configured LLM provider."""
        if self.llm_provider == "openai":
            if self.openai_api_key is None:
                raise ValueError("OpenAI API key is required when llm_provider is 'openai'")
            return self.openai_api_key.get_secret_value()
        elif self.llm_provider == "anthropic":
            if self.anthropic_api_key is None:
                raise ValueError("Anthropic API key is required when llm_provider is 'anthropic'")
            return self.anthropic_api_key.get_secret_value()
        else:
            raise ValueError(f"Unsupported LLM provider: {self.llm_provider}")

    @property
    def effective_migrations_path(self) -> str:
        """Get the effective migrations path."""
        if self.migrations_path:
            return self.migrations_path
        # Default to package's migrations directory
        import importlib.resources

        try:
            # Python 3.11+
            return str(importlib.resources.files("reviewiq_pipeline.db") / "migrations")
        except (AttributeError, TypeError):
            # Fallback for older Python
            import os

            return os.path.join(os.path.dirname(__file__), "db", "migrations")


class ClassificationConfig:
    """Configuration specifically for the LLM classification stage."""

    def __init__(self, config: Config):
        self.model = config.llm_model
        self.taxonomy_version = config.taxonomy_version
        self.profile = config.classification_profile
        self.max_spans_per_review = config.max_spans_per_review
        self.temperature = config.llm_temperature
        self.max_retries = config.llm_max_retries
        self.timeout_seconds = config.llm_timeout_seconds

    def to_dict(self) -> dict:
        """Convert to dictionary for contract compatibility."""
        return {
            "model": self.model,
            "taxonomy_version": self.taxonomy_version,
            "profile": self.profile,
            "max_spans_per_review": self.max_spans_per_review,
        }


class EmbeddingConfig:
    """Configuration for the embedding service."""

    def __init__(self, config: Config):
        self.model = config.embedding_model
        self.dimension = config.embedding_dimension

    def to_dict(self) -> dict:
        """Convert to dictionary."""
        return {
            "model": self.model,
            "dimension": self.dimension,
        }


class DatabaseConfig:
    """Configuration for database connections."""

    def __init__(self, config: Config):
        self.url = config.database_url
        self.pool_min_size = config.db_pool_min_size
        self.pool_max_size = config.db_pool_max_size
        self.migrations_path = config.effective_migrations_path

    def to_dict(self) -> dict:
        """Convert to dictionary."""
        return {
            "url": self.url,
            "pool_min_size": self.pool_min_size,
            "pool_max_size": self.pool_max_size,
            "migrations_path": self.migrations_path,
        }
