"""Application settings."""

from functools import lru_cache
from typing import Literal

from pydantic import Field, model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    """Runtime configuration loaded from environment variables."""

    model_config = SettingsConfigDict(
        env_file=".env",
        env_prefix="GNEXUS_CREDS_",
        extra="ignore",
    )

    env: Literal["development", "test", "production"] = "development"
    app_name: str = "gnexus-creds"
    database_url: str = "postgresql+psycopg://gnexus_creds:gnexus_creds@localhost:5432/gnexus_creds"
    master_key: str = Field(default="change-me-to-a-32-byte-url-safe-key", min_length=16)
    session_secret: str = Field(default="change-me", min_length=8)
    session_cookie_name: str = "gnexus_creds_session"
    session_ttl_seconds: int = 60 * 60 * 24 * 14
    auth_base_url: str = Field(default="http://gnexus-auth.local", alias="GNEXUS_AUTH_BASE_URL")
    auth_client_id: str = Field(default="gnexus-creds", alias="GNEXUS_AUTH_CLIENT_ID")
    auth_client_secret: str = Field(default="change-me", alias="GNEXUS_AUTH_CLIENT_SECRET")
    auth_redirect_uri: str = Field(
        default="http://localhost:8000/auth/callback",
        alias="GNEXUS_AUTH_REDIRECT_URI",
    )
    auth_webhook_secret: str = Field(default="change-me", alias="GNEXUS_AUTH_WEBHOOK_SECRET")
    mcp_resource_url: str = "http://localhost:8000/mcp-protocol/"
    rate_limit_window_seconds: int = 60
    rate_limit_max_sensitive_requests: int = 120

    @model_validator(mode="after")
    def validate_production_settings(self) -> "Settings":
        if not self.is_production:
            return self

        defaults = {
            "master_key": "change-me-to-a-32-byte-url-safe-key",
            "session_secret": "change-me",
            "auth_client_id": "gnexus-creds",
            "auth_client_secret": "change-me",
            "auth_webhook_secret": "change-me",
        }
        unsafe = [name for name, value in defaults.items() if getattr(self, name) == value]
        if unsafe:
            raise ValueError(f"Unsafe production defaults: {', '.join(sorted(unsafe))}.")
        if self.database_url.startswith("sqlite"):
            raise ValueError("Production database_url must use PostgreSQL.")
        for name in ("auth_base_url", "auth_redirect_uri", "mcp_resource_url"):
            value = getattr(self, name)
            if not value.startswith("https://"):
                raise ValueError(f"Production {name} must use https://.")
        return self

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


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