"""Runtime settings, read from the process environment.

MUST stay importable with no environment and no BW client — the OpenAPI schema
dump and the test suite both import `app.main` where neither exists. Nothing here
raises on a missing value; the production guard lives in `main.py`'s lifespan,
which runs only when the server actually starts.
"""

import functools
import os
from pathlib import Path

from app import bw_config

# The development default for the session secret. `main.py` refuses to serve in
# production while this is still the value — a real secret goes in .app.env.
DEV_SESSION_SECRET = "dev-only-change-me"


class Settings:
    def __init__(self) -> None:
        self.app_name = bw_config.APP_NAME
        self.owner = bw_config.OWNER
        self.host = bw_config.HOST

        # Where app state lives. A mounted volume in the container so it
        # survives redeploys (workspace `data/`).
        self.data_dir = Path(os.environ.get("APP_DATA_DIR", "/data"))
        # Vestige of the kit's stdlib store, kept because the STOCK conformance
        # conftest unlinks this path around each test. The real store is the
        # SQLAlchemy database below (managed mode).
        self.accounts_db = str(self.data_dir / "accounts.db")

        # Postgres in prod (compose sidecar, URL from .app.env); a SQLite file in
        # the data dir otherwise, so tests and local runs need no DB container.
        self.database_url = os.environ.get(
            "EASEL_DB_URL", f"sqlite:///{self.data_dir}/app.db")

        # Mockup bundles + comment attachments live under the data dir, never a
        # static mount — served only through the authenticated/token routes.
        self.mockups_dir = self.data_dir / "mockups"
        self.attachments_dir = self.data_dir / "attachments"
        # Hard caps (bytes). A mockup bundle is a handful of HTML/CSS/JS/images.
        self.max_mockup_file_bytes = 15 * 1024 * 1024
        self.max_attachment_bytes = 10 * 1024 * 1024

        self.session_secret = os.environ.get("APP_SESSION_SECRET", DEV_SESSION_SECRET)
        self.env = os.environ.get("APP_ENV", "development")

        # The digest (services/digest.py): one email per person once things
        # have been waiting for them for a QUIET while with nothing new. The
        # window is the one knob most likely to need tuning against real
        # client behaviour (Interaction Standard §7), so it is a setting.
        self.digest_quiet_minutes = int(os.environ.get("EASEL_DIGEST_QUIET_MINUTES", "60"))
        self.digest_poll_seconds = int(os.environ.get("EASEL_DIGEST_POLL_SECONDS", "300"))

        # Pattern B client — bw_auth.py reads these from the environment itself;
        # we mirror them only to know whether BW is configured at all.
        self.bw_client_id = os.environ.get("BW_CLIENT_ID", "")
        self.bw_client_secret = os.environ.get("BW_CLIENT_SECRET", "")
        self.bw_auth = os.environ.get("BW_AUTH", "https://auth.bowden.works")
        self.bw_app_domain = os.environ.get("BW_APP_DOMAIN", f"https://{self.host}")

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

    @property
    def has_bw_client(self) -> bool:
        return bool(self.bw_client_id and self.bw_client_secret)

    @property
    def session_cookie(self) -> str:
        return f"{self.app_name}_session"


@functools.lru_cache
def get_settings() -> Settings:
    return Settings()
