import os
from dataclasses import dataclass
from functools import lru_cache
from typing import Optional


@dataclass(frozen=True)
class Settings:
    """
    Immutable runtime settings loaded from environment variables.

    These values control storage, logging, output paths, and LLM configuration.
    """

    db_path: str
    db_url: Optional[str]
    sink: str
    log_level: str
    output_path: Optional[str]
    output_format: str
    summary_path: Optional[str]
    changes_path: Optional[str]
    llm_provider: str
    openai_api_key: Optional[str]
    openai_model: str
    llm_retries: int
    llm_backoff_seconds: float
    llm_request_delay_seconds: float
    max_results: int


@lru_cache(maxsize=1)
def get_settings() -> Settings:
    """
    Resolve settings from environment variables with sane defaults.

    The result is cached to avoid repeated environment lookups.
    """

    db_path = os.getenv("SYNTHNEURA_DB_PATH", "trials.db")
    db_url = os.getenv("SYNTHNEURA_DB_URL")
    sink = os.getenv("SYNTHNEURA_SINK", "sqlite")
    log_level = os.getenv("SYNTHNEURA_LOG_LEVEL", "INFO")
    output_path = os.getenv("SYNTHNEURA_OUTPUT_PATH")
    output_format = os.getenv("SYNTHNEURA_OUTPUT_FORMAT", "json")
    summary_path = os.getenv("SYNTHNEURA_SUMMARY_PATH")
    changes_path = os.getenv("SYNTHNEURA_CHANGES_PATH")
    llm_provider = os.getenv("SYNTHNEURA_LLM_PROVIDER", "openai")
    openai_api_key = os.getenv("SYNTHNEURA_OPENAI_API_KEY")
    openai_model = os.getenv("SYNTHNEURA_OPENAI_MODEL", "gpt-4o-mini")
    llm_retries_raw = os.getenv("SYNTHNEURA_LLM_RETRIES", "3")
    llm_backoff_raw = os.getenv("SYNTHNEURA_LLM_BACKOFF_SECONDS", "1.0")
    llm_request_delay_raw = os.getenv("SYNTHNEURA_LLM_REQUEST_DELAY_SECONDS", "0.0")
    max_results_raw = os.getenv("SYNTHNEURA_MAX_RESULTS", "10")

    try:
        max_results = int(max_results_raw)
    except ValueError:
        max_results = 10
    try:
        llm_retries = int(llm_retries_raw)
    except ValueError:
        llm_retries = 3
    try:
        llm_backoff_seconds = float(llm_backoff_raw)
    except ValueError:
        llm_backoff_seconds = 1.0
    try:
        llm_request_delay_seconds = float(llm_request_delay_raw)
    except ValueError:
        llm_request_delay_seconds = 0.0

    return Settings(
        db_path=db_path,
        db_url=db_url,
        sink=sink,
        log_level=log_level,
        output_path=output_path,
        output_format=output_format,
        summary_path=summary_path,
        changes_path=changes_path,
        llm_provider=llm_provider,
        openai_api_key=openai_api_key,
        openai_model=openai_model,
        llm_retries=llm_retries,
        llm_backoff_seconds=llm_backoff_seconds,
        llm_request_delay_seconds=llm_request_delay_seconds,
        max_results=max_results,
    )
