"""Centralized application configuration.

All settings are loaded from environment variables (or a .env file)
once at startup. Provider-specific defaults (model names, base URLs)
are resolved by the provider adapters, not here.
"""

import logging.config
from collections.abc import Sequence
from enum import StrEnum
from functools import cache
from pathlib import Path
from typing import Annotated
from typing import Any
from typing import Literal

from pydantic import BaseModel
from pydantic import Field
from pydantic import SecretStr
from pydantic_settings import BaseSettings
from pydantic_settings import SettingsConfigDict

logger = logging.getLogger(__name__)


class Provider(StrEnum):
    OPENROUTER = "openrouter"


class SqliteSettings(BaseModel):
    driver: Literal["sqlite"] = "sqlite"
    path: str = "app.db"


class PostgresSettings(BaseModel):
    driver: Literal["postgres"] = "postgres"
    host: str
    port: int = 5432
    database: str
    user: str
    password: SecretStr


DatabaseSettings = Annotated[
    SqliteSettings | PostgresSettings,
    Field(discriminator="driver"),
]


class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
        env_nested_delimiter="__",
        cli_implicit_flags=True,
        cli_kebab_case=True,
    )

    # --- NiceGUI Server ---
    host: str = "0.0.0.0"
    port: int = 8000
    log_level: Literal["critical", "error", "warning", "info", "debug", "trace"] = "info"
    reload: bool = False

    # --- AI provider ---
    provider: Provider = Provider.OPENROUTER
    openrouter_api_key: str
    provider_model: str | None = None
    openrouter_http_referer: str | None = None
    openrouter_app_title: str | None = None

    # --- runtime environment ---
    environment: Literal["development", "test", "production"] = "development"

    # --- persistence ---
    database: DatabaseSettings = Field(default_factory=SqliteSettings)
    bootstrap_schema_on_startup: bool = False
    sqlite_check_same_thread: bool = False

    # --- filesystem paths ---
    upload_dir: Path = Path("./uploads")
    prompt_dir: Path = Path("./prompts")

    # --- worker reliability ---
    worker_max_retries: int = 0
    worker_retry_backoff_seconds: float = 0.0
    worker_provider_timeout_seconds: float = Field(default=20.0, gt=0.0, le=20.0)
    worker_min_transcription_chars: int = Field(default=0, ge=0)
    worker_min_transcription_lines: int = Field(default=0, ge=0)
    worker_fail_on_finish_reason_length: bool = False

    @property
    def should_bootstrap_schema(self) -> bool:
        """Return whether startup should auto-create schema for this environment."""
        if "bootstrap_schema_on_startup" in self.model_fields_set:
            return self.bootstrap_schema_on_startup
        return self.environment in {"development", "test"}


@cache
def get_settings(**kwargs: Any) -> Settings:
    """Load cached settings without reading process CLI arguments."""
    return Settings(_cli_parse_args=False, **kwargs)  # pyright: ignore[reportCallIssue]


def parse_cli_settings(args: Sequence[str] | None = None) -> Settings:
    """Load settings with CLI arguments at the executable boundary."""
    cli_args = True if args is None else list(args)
    return Settings(_cli_parse_args=cli_args)  # pyright: ignore[reportCallIssue]


LOGGING_CONFIG: dict[str, Any] = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "standard": {
            "format": "%(asctime)s %(levelname)-8s | %(message)s",
            "datefmt": "%Y-%m-%d %H:%M:%S",
        }
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "standard",
            "stream": "ext://sys.stdout",
        }
    },
    "root": {
        "level": "INFO",
        "handlers": ["console"],
    },
    "loggers": {
        "transcription": {
            "level": "DEBUG",
            "handlers": ["console"],
            "propagate": False,
        }
    },
}


def configure_logging(settings: Settings | None = None) -> None:
    """Configure root logging once at startup."""
    cfg = LOGGING_CONFIG.copy()
    active_settings = settings or get_settings()
    cfg["loggers"]["transcription"]["level"] = active_settings.log_level.upper()
    logging.config.dictConfig(cfg)
    logger.debug("Logging configured")
