"""Server configuration from environment variables."""

from pathlib import Path
from typing import Any
from urllib.parse import urlparse

from pydantic_settings import BaseSettings

# Secret keys we will actively refuse. These cover the default template value
# and dev-only literals that have appeared in scripts or documentation.
_FORBIDDEN_SECRETS: frozenset[str] = frozenset(
    {
        "change-me-in-production",
        "test-secret-key-minimum-32-chars",
        "dev-secret-key-not-for-production",
    }
)


class Settings(BaseSettings):
    """Application settings loaded from environment variables."""

    data_dir: Path = Path("/data")
    database_url: str = ""

    secret_key: str = "change-me-in-production"

    access_token_expire_minutes: int = 15
    refresh_token_expire_days: int = 30

    jwt_issuer: str = "notify-bridge"
    jwt_audience: str = "notify-bridge-api"

    host: str = "0.0.0.0"
    port: int = 8420
    debug: bool = False

    # Comma-separated list of trusted proxy IPs uvicorn will honor for
    # X-Forwarded-For / X-Forwarded-Proto. Use "*" ONLY when you trust the
    # network (never directly on the internet). Default matches uvicorn.
    forwarded_allow_ips: str = "127.0.0.1"

    # How long to wait for in-flight requests / scheduler jobs before force
    # killing on SIGTERM.
    graceful_shutdown_seconds: int = 60

    anthropic_api_key: str = ""
    ai_model: str = "claude-sonnet-4-20250514"
    ai_max_tokens: int = 1024

    telegram_webhook_secret: str = ""

    cors_allowed_origins: str = "http://localhost:5175"
    """Comma-separated allowed origins for CORS (e.g. 'http://localhost:5173,https://myapp.com')."""

    static_dir: str = ""
    """Path to frontend static files. Set to serve SvelteKit build via FastAPI (e.g. /app/static in Docker)."""

    # --- Logging ---
    log_level: str = "INFO"
    """Root log level for the app loggers (``DEBUG``/``INFO``/``WARNING``/``ERROR``)."""

    log_format: str = "text"
    """Log output format: ``text`` (human-readable) or ``json`` (one object per line)."""

    log_levels: str = ""
    """Comma-separated per-module overrides, e.g. ``notify_bridge_core.notifications.telegram.client=DEBUG,sqlalchemy.engine=INFO``."""

    # --- Retention ---
    event_log_retention_days: int = 30
    """Days of event_log history to retain. 0 disables the retention job."""

    pre_migrate_snapshot_keep: int = 5
    """Number of pre-migration DB snapshots to keep in ``data_dir/backups/``.
    0 disables snapshotting entirely. Each snapshot is produced at boot
    before migrations run using SQLite's ``VACUUM INTO`` (atomic, consistent).
    """

    metrics_enabled: bool = True
    """Expose the Prometheus ``/api/metrics`` endpoint. Disable on hardened
    deployments where the API port is exposed beyond the trust boundary —
    metrics are unauthenticated and can leak operational information about
    queue depth, dispatch rates, and provider failures.
    """

    model_config = {"env_prefix": "NOTIFY_BRIDGE_"}

    def model_post_init(self, __context: Any) -> None:
        if self.secret_key in _FORBIDDEN_SECRETS:
            raise ValueError(
                "SECURITY: Refusing to start with a known/default secret_key. "
                "Set NOTIFY_BRIDGE_SECRET_KEY to a random value (>=32 bytes) "
                "before starting the server."
            )
        if len(self.secret_key) < 32:
            raise ValueError(
                "SECURITY: NOTIFY_BRIDGE_SECRET_KEY must be at least 32 characters."
            )
        origins = [o.strip() for o in self.cors_allowed_origins.split(",") if o.strip()]
        if "*" in origins:
            raise ValueError(
                "SECURITY: wildcard '*' is not allowed in CORS origins when credentials are enabled."
            )
        for origin in origins:
            parsed = urlparse(origin)
            if parsed.scheme not in {"http", "https"} or not parsed.netloc:
                raise ValueError(
                    f"CORS origin {origin!r} is invalid — must include scheme (http/https) and host."
                )
        if self.access_token_expire_minutes <= 0:
            raise ValueError("access_token_expire_minutes must be > 0")
        if self.refresh_token_expire_days <= 0:
            raise ValueError("refresh_token_expire_days must be > 0")
        if not (1 <= self.port <= 65535):
            raise ValueError("port must be in range 1..65535")
        if self.event_log_retention_days < 0:
            raise ValueError("event_log_retention_days must be >= 0")
        if self.pre_migrate_snapshot_keep < 0:
            raise ValueError("pre_migrate_snapshot_keep must be >= 0")

    @property
    def effective_database_url(self) -> str:
        if self.database_url:
            return self.database_url
        db_path = self.data_dir / "notify_bridge.db"
        return f"sqlite+aiosqlite:///{db_path}"


settings = Settings()
