"""Runtime settings for AI MusiMuse.

This module defines the :class:`Settings` class, which loads runtime
configuration from a ``.env`` file and/or environment variables.

Only runtime configuration lives here.  Algorithm parameters belong in
project configuration managed by future tasks.
"""

from __future__ import annotations

from functools import lru_cache
from pathlib import Path

from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    """Runtime configuration for AI MusiMuse.

    Attributes:
        project_name: Human-readable name of the project.
        database_url: SQLAlchemy database URL.  SQLite only.
        log_level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL).
        cache_directory: Path to the disposable cache directory.
        data_directory: Path to the data directory (source audio, database).
        output_directory: Path to the generated output directory.
    """

    project_name: str = "AI MusiMuse"
    database_url: str = "sqlite:///./data/musimuse.db"
    log_level: str = "INFO"
    cache_directory: str = "./cache"
    data_directory: str = "./data"
    output_directory: str = "./output"

    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
    )

    def ensure_directories(self) -> None:
        """Create runtime directories if they do not exist.

        Raises:
            ConfigurationError: If a directory cannot be created.
        """
        from core.exceptions import ConfigurationError

        dirs = (self.cache_directory, self.data_directory, self.output_directory)
        for path_str in dirs:
            try:
                Path(path_str).mkdir(parents=True, exist_ok=True)
            except OSError as exc:
                raise ConfigurationError(
                    f"Failed to create directory '{path_str}': {exc}"
                ) from exc


@lru_cache(maxsize=1)
def get_settings() -> Settings:
    """Return a cached :class:`Settings` instance.

    The settings are loaded once and reused for the lifetime of the
    process.  Call ``get_settings.cache_clear()`` to force a reload.

    Returns:
        A populated :class:`Settings` instance.
    """
    return Settings()
