from __future__ import annotations

import os
from dataclasses import dataclass
from functools import lru_cache


@dataclass(frozen=True)
class Settings:
    host: str = "0.0.0.0"
    port: int = 8095
    token: str = "change-this-token"
    engine: str = "pillow"
    device: str = "cpu"
    max_upload_mb: int = 20
    max_input_width: int = 4096
    max_input_height: int = 4096
    max_output_width: int = 8192
    max_output_height: int = 8192
    tmp_dir: str = "/app/storage/tmp"
    output_dir: str = "/app/storage/output"
    result_ttl_minutes: int = 60
    model_dir: str = "/app/app/models"
    default_model: str = "realesrgan-x4plus"
    realesrgan_bin: str = "/app/bin/realesrgan-ncnn-vulkan"
    realesrgan_model_dir: str = "/app/models"
    realesrgan_default_model: str = "realesrgan-x4plus"
    realesrgan_anime_model: str = "realesrgan-x4plus-anime"
    realesrgan_gpu_id: int = -1
    realesrgan_tile: int = 0
    realesrgan_tta: bool = False
    realesrgan_verbose: bool = False
    realesrgan_timeout_seconds: int = 900
    realesrgan_preprocess_max_pixels: int = 16_777_216
    realesrgan_output_ext: str = "webp"
    realesrgan_allow_model_fallback: bool = True


def _env_int(name: str, default: int) -> int:
    try:
        return int(os.getenv(name, str(default)).strip())
    except ValueError:
        return default


def _env_bool(name: str, default: bool) -> bool:
    value = os.getenv(name)

    if value is None:
        return default

    normalized = value.strip().lower()

    if normalized in {"1", "true", "yes", "on"}:
        return True

    if normalized in {"0", "false", "no", "off"}:
        return False

    return default


@lru_cache(maxsize=1)
def get_settings() -> Settings:
    legacy_model_dir = os.getenv("WORKER_MODEL_DIR", "/app/app/models").strip() or "/app/app/models"
    legacy_default_model = os.getenv("WORKER_DEFAULT_MODEL", "realesrgan-x4plus").strip() or "realesrgan-x4plus"
    realesrgan_model_dir = os.getenv(
        "WORKER_REALESRGAN_MODEL_DIR",
        legacy_model_dir if legacy_model_dir != "/app/app/models" else "/app/models",
    ).strip() or (legacy_model_dir if legacy_model_dir != "/app/app/models" else "/app/models")

    return Settings(
        host=os.getenv("WORKER_HOST", "0.0.0.0").strip() or "0.0.0.0",
        port=_env_int("WORKER_PORT", 8095),
        token=os.getenv("WORKER_TOKEN", "change-this-token").strip(),
        engine=os.getenv("WORKER_ENGINE", "pillow").strip().lower() or "pillow",
        device=os.getenv("WORKER_DEVICE", "cpu").strip().lower() or "cpu",
        max_upload_mb=max(1, _env_int("WORKER_MAX_UPLOAD_MB", 20)),
        max_input_width=max(1, _env_int("WORKER_MAX_INPUT_WIDTH", 4096)),
        max_input_height=max(1, _env_int("WORKER_MAX_INPUT_HEIGHT", 4096)),
        max_output_width=max(1, _env_int("WORKER_MAX_OUTPUT_WIDTH", 8192)),
        max_output_height=max(1, _env_int("WORKER_MAX_OUTPUT_HEIGHT", 8192)),
        tmp_dir=os.getenv("WORKER_TMP_DIR", "/app/storage/tmp").strip() or "/app/storage/tmp",
        output_dir=os.getenv("WORKER_OUTPUT_DIR", "/app/storage/output").strip() or "/app/storage/output",
        result_ttl_minutes=max(1, _env_int("WORKER_RESULT_TTL_MINUTES", 60)),
        model_dir=legacy_model_dir,
        default_model=legacy_default_model,
        realesrgan_bin=os.getenv("WORKER_REALESRGAN_BIN", "/app/bin/realesrgan-ncnn-vulkan").strip() or "/app/bin/realesrgan-ncnn-vulkan",
        realesrgan_model_dir=realesrgan_model_dir,
        realesrgan_default_model=os.getenv("WORKER_REALESRGAN_DEFAULT_MODEL", legacy_default_model).strip() or legacy_default_model,
        realesrgan_anime_model=os.getenv("WORKER_REALESRGAN_ANIME_MODEL", "realesrgan-x4plus-anime").strip() or "realesrgan-x4plus-anime",
        realesrgan_gpu_id=_env_int("WORKER_REALESRGAN_GPU_ID", -1),
        realesrgan_tile=max(0, _env_int("WORKER_REALESRGAN_TILE", 0)),
        realesrgan_tta=_env_bool("WORKER_REALESRGAN_TTA", False),
        realesrgan_verbose=_env_bool("WORKER_REALESRGAN_VERBOSE", False),
        realesrgan_timeout_seconds=max(1, _env_int("WORKER_REALESRGAN_TIMEOUT_SECONDS", 900)),
        realesrgan_preprocess_max_pixels=max(1, _env_int("WORKER_REALESRGAN_PREPROCESS_MAX_PIXELS", 16_777_216)),
        realesrgan_output_ext=os.getenv("WORKER_REALESRGAN_OUTPUT_EXT", "webp").strip().lower() or "webp",
        realesrgan_allow_model_fallback=_env_bool("WORKER_REALESRGAN_ALLOW_MODEL_FALLBACK", True),
    )