"""Configuration lue dans l'environnement (jamais de secret dans le code ni dans Git)."""
from __future__ import annotations

import os
from dataclasses import dataclass
from functools import lru_cache
from pathlib import Path

ENVIRONMENTS = {"development", "test", "demo", "production"}
AV_MODES = {"required", "optional", "disabled"}


def _load_env_file(path: str) -> None:
    """Charge un fichier KEY=VALUE (utile en développement ; systemd le fait en production)."""
    p = Path(path).expanduser()
    if not p.is_file():
        return
    for line in p.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#") or "=" not in line:
            continue
        key, value = line.split("=", 1)
        os.environ.setdefault(key.strip(), value.strip().strip('"').strip("'"))


def _bool(name: str, default: bool) -> bool:
    raw = os.environ.get(name)
    if raw is None or raw == "":
        return default
    return raw.strip().lower() in {"1", "true", "yes", "oui", "on"}


@dataclass(frozen=True)
class Config:
    env: str
    secret_key: str
    database_url: str
    database_owner_url: str
    storage_dir: Path
    public_origin: str
    cookie_secure: bool
    av_mode: str
    clamav_socket: str | None
    tesseract_bin: str
    worker_poll_seconds: float

    @property
    def is_production(self) -> bool:
        return self.env == "production"

    @property
    def is_demo(self) -> bool:
        return self.env == "demo"

    @property
    def cookie_name(self) -> str:
        # Le préfixe __Host- impose Secure, Path=/ et l'absence de Domain.
        return "__Host-edcf_sid" if self.cookie_secure else "edcf_sid"

    @property
    def imports_dir(self) -> Path:
        return self.storage_dir / "imports"

    @property
    def branding_dir(self) -> Path:
        return self.storage_dir / "branding"


class ConfigError(RuntimeError):
    pass


@lru_cache(maxsize=1)
def get_config() -> Config:
    if os.environ.get("EDCF_ENV_FILE"):
        _load_env_file(os.environ["EDCF_ENV_FILE"])
    env = os.environ.get("EDCF_ENV", "development").strip().lower()
    if env not in ENVIRONMENTS:
        raise ConfigError(f"EDCF_ENV invalide : {env!r}")
    secret = os.environ.get("EDCF_SECRET_KEY", "")
    if len(secret) < 32:
        raise ConfigError("EDCF_SECRET_KEY doit contenir au moins 32 caractères aléatoires.")
    db_url = os.environ.get("EDCF_DATABASE_URL", "")
    if not db_url:
        raise ConfigError("EDCF_DATABASE_URL est obligatoire.")
    av_mode = os.environ.get("EDCF_AV_MODE", "required").strip().lower()
    if av_mode not in AV_MODES:
        raise ConfigError(f"EDCF_AV_MODE invalide : {av_mode!r}")
    if env == "production" and av_mode != "required":
        # Autorisé mais tracé au démarrage : la décision appartient aux référents sécurité.
        pass
    return Config(
        env=env,
        secret_key=secret,
        database_url=db_url,
        database_owner_url=os.environ.get("EDCF_DATABASE_OWNER_URL", db_url),
        storage_dir=Path(os.environ.get("EDCF_STORAGE_DIR", "./var")).resolve(),
        public_origin=os.environ.get("EDCF_PUBLIC_ORIGIN", "http://localhost:5173").rstrip("/"),
        cookie_secure=_bool("EDCF_COOKIE_SECURE", env in {"production", "demo"}),
        av_mode=av_mode,
        clamav_socket=os.environ.get("EDCF_CLAMAV_SOCKET") or None,
        tesseract_bin=os.environ.get("EDCF_TESSERACT_BIN", "tesseract"),
        worker_poll_seconds=float(os.environ.get("EDCF_WORKER_POLL_SECONDS", "1.5")),
    )
