from __future__ import annotations

import os
import secrets
from dataclasses import dataclass
from pathlib import Path


def load_dotenv(path: str = ".env") -> None:
    env_path = Path(path)
    if not env_path.exists():
        return
    for raw_line in env_path.read_text().splitlines():
        line = raw_line.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("'"))


def _bool(name: str, default: bool = False) -> bool:
    value = os.environ.get(name)
    if value is None:
        return default
    return value.lower() in {"1", "true", "yes", "on"}


def _csv(name: str) -> set[str]:
    return {
        item.strip().lower()
        for item in os.environ.get(name, "").split(",")
        if item.strip()
    }


#: A "home" deployment serves the public landing page and nothing else: no database, no session,
#: no OIDC. Everything that needs an identity lives on the "full" deployment at auth_base_url.
ROLES = {"full", "home"}


@dataclass(frozen=True)
class Config:
    role: str
    auth_base_url: str
    base_url: str
    host: str
    port: int
    secret: str
    cookie_secure: bool
    database_url: str
    trusted_domains: set[str]
    default_ipa_group: str
    app_admin_emails: set[str]
    admin_groups: set[str]
    oidc_issuer: str
    oidc_client_id: str
    oidc_client_secret: str
    oidc_scopes: str
    smtp_host: str
    smtp_port: int
    smtp_username: str
    smtp_password: str
    smtp_from: str
    smtp_starttls: bool
    smtp_ssl: bool
    ipa_mode: str
    ipa_principal: str
    ipa_keytab: str
    ipa_default_shell: str
    ipa_home_root: str
    authentik_sync_enabled: bool
    authentik_sync_container: str
    authentik_ldap_source_slugs: tuple[str, ...]


def get_config() -> Config:
    load_dotenv()
    role = os.environ.get("APP_ROLE", "full").strip().lower()
    if role not in ROLES:
        raise SystemExit(f"APP_ROLE must be one of {sorted(ROLES)}, got {role!r}")
    base_url = os.environ.get("APP_BASE_URL", "http://127.0.0.1:8080").rstrip("/")
    database_url = os.environ.get("DATABASE_URL", "")
    if role != "home" and not database_url:
        raise SystemExit("DATABASE_URL is required unless APP_ROLE=home")
    # Where the pages this deployment does not serve actually live -- the "full" deployment that
    # owns registration, profile and admin. A "full" deployment serves them itself, so its own
    # base URL is the right answer. This is NOT the identity provider: OIDC_ISSUER points at
    # Authentik, which lives on a different host.
    auth_base_url = os.environ.get("AUTH_BASE_URL", base_url).rstrip("/")
    oidc_issuer = os.environ.get("OIDC_ISSUER", "").rstrip("/")
    if role != "home" and not oidc_issuer:
        raise SystemExit("OIDC_ISSUER is required unless APP_ROLE=home")
    return Config(
        role=role,
        auth_base_url=auth_base_url,
        base_url=base_url,
        host=os.environ.get("APP_HOST", "127.0.0.1"),
        port=int(os.environ.get("APP_PORT", "8080")),
        secret=os.environ.get("APP_SECRET", secrets.token_hex(32)),
        cookie_secure=_bool("COOKIE_SECURE", False),
        database_url=database_url,
        trusted_domains=_csv("TRUSTED_EMAIL_DOMAINS"),
        default_ipa_group=os.environ.get("DEFAULT_IPA_GROUP", "sticknife_users"),
        app_admin_emails=_csv("APP_ADMIN_EMAILS"),
        admin_groups=_csv("APP_ADMIN_GROUPS") or {"sticknife_admins"},
        oidc_issuer=oidc_issuer,
        oidc_client_id=os.environ.get("OIDC_CLIENT_ID", ""),
        oidc_client_secret=os.environ.get("OIDC_CLIENT_SECRET", ""),
        oidc_scopes=os.environ.get("OIDC_SCOPES", "openid profile email groups"),
        smtp_host=os.environ.get("SMTP_HOST", "mail.sticknife.com"),
        smtp_port=int(os.environ.get("SMTP_PORT", "587")),
        smtp_username=os.environ.get("SMTP_USERNAME", ""),
        smtp_password=os.environ.get("SMTP_PASSWORD", ""),
        smtp_from=os.environ.get("SMTP_FROM", "accounts@sticknife.com"),
        smtp_starttls=_bool("SMTP_STARTTLS", True),
        smtp_ssl=_bool("SMTP_SSL", False),
        ipa_mode=os.environ.get("STICKNIFE_IPA_PROVISION_MODE", "dry-run"),
        ipa_principal=os.environ.get("IPA_PRINCIPAL", ""),
        ipa_keytab=os.environ.get("IPA_KEYTAB", ""),
        ipa_default_shell=os.environ.get("IPA_DEFAULT_SHELL", "/bin/bash"),
        ipa_home_root=os.environ.get("IPA_HOME_ROOT", "/home"),
        authentik_sync_enabled=_bool("AUTHENTIK_SYNC_ENABLED", False),
        authentik_sync_container=os.environ.get("AUTHENTIK_SYNC_CONTAINER", "authentik-worker-1"),
        authentik_ldap_source_slugs=tuple(sorted(_csv("AUTHENTIK_LDAP_SOURCE_SLUGS"))),
    )

