from __future__ import annotations

import os
from dataclasses import dataclass
from functools import lru_cache
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent


def load_dotenv(path: Path) -> None:
    if not path.is_file():
        return
    for raw in path.read_text(encoding="utf-8").splitlines():
        line = raw.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("'"))


load_dotenv(ROOT / ".env")


def _bool(name: str, default: bool = False) -> bool:
    raw = os.environ.get(name)
    if raw is None:
        return default
    return raw.strip().lower() in {"1", "true", "yes", "on"}


def _int(name: str, default: int) -> int:
    raw = os.environ.get(name)
    if raw is None or not raw.strip():
        return default
    try:
        return int(raw.strip())
    except ValueError as exc:
        raise RuntimeError(f"{name} must be a whole number.") from exc


def _float(name: str, default: float) -> float:
    raw = os.environ.get(name)
    if raw is None or not raw.strip():
        return default
    try:
        return float(raw.strip())
    except ValueError as exc:
        raise RuntimeError(f"{name} must be a number.") from exc


@dataclass(frozen=True)
class Settings:
    root: Path
    host: str
    port: int
    data_dir: Path
    gates_path: Path
    max_duration_seconds: int
    retention_hours: int
    whisper_model: str
    whisper_device: str
    whisper_compute: str
    max_upload_mb: int
    production: bool
    hindi_cer_max: float
    min_free_gb: float
    testing: bool

    @property
    def model_dir(self) -> Path:
        return self.data_dir / "models"

    @property
    def exposed(self) -> bool:
        return self.host not in {"127.0.0.1", "localhost", "::1"}


@lru_cache
def get_settings() -> Settings:
    data_dir = Path(os.environ.get("VAANI_DATA_DIR", str(ROOT / "data"))).expanduser()
    gates = Path(os.environ.get("VAANI_GATES_PATH", str(ROOT / "config" / "launch-gates.json")))
    max_duration = _int("VAANI_MAX_DURATION_SECONDS", 45 * 60)
    if not 30 <= max_duration <= 4 * 60 * 60:
        raise RuntimeError("VAANI_MAX_DURATION_SECONDS must be between 30 and 14400.")
    retention = _int("VAANI_RETENTION_HOURS", 24)
    if not 1 <= retention <= 24 * 30:
        raise RuntimeError("VAANI_RETENTION_HOURS must be between 1 and 720.")
    upload = _int("VAANI_MAX_UPLOAD_MB", 500)
    if not 10 <= upload <= 4000:
        raise RuntimeError("VAANI_MAX_UPLOAD_MB must be between 10 and 4000.")
    cer = _float("VAANI_HINDI_CER_MAX", 0.18)
    if not 0 < cer <= 1:
        raise RuntimeError("VAANI_HINDI_CER_MAX must be greater than 0 and at most 1.")
    free = _float("VAANI_MIN_FREE_GB", 2)
    if free < 0.2:
        raise RuntimeError("VAANI_MIN_FREE_GB must be at least 0.2.")
    port = _int("VAANI_PORT", 8765)
    if not 1 <= port <= 65535:
        raise RuntimeError("VAANI_PORT must be a valid port.")
    model = os.environ.get("VAANI_WHISPER_MODEL", "small").strip() or "small"
    return Settings(
        root=ROOT,
        host=os.environ.get("VAANI_HOST", "127.0.0.1").strip() or "127.0.0.1",
        port=port,
        data_dir=data_dir,
        gates_path=gates,
        max_duration_seconds=max_duration,
        retention_hours=retention,
        whisper_model=model,
        whisper_device=os.environ.get("VAANI_WHISPER_DEVICE", "cpu").strip() or "cpu",
        whisper_compute=os.environ.get("VAANI_WHISPER_COMPUTE", "int8").strip() or "int8",
        max_upload_mb=upload,
        production=_bool("VAANI_PRODUCTION", False),
        hindi_cer_max=cer,
        min_free_gb=free,
        testing=_bool("VAANI_TESTING", False),
    )
