"""
Auth dependencies for the MealPlanner backend.

Two flavors:
- ``require_admin`` — bearer token for ``/api/admin/*`` routes; token compared
  to ``settings.ADMIN_TOKEN`` (must be set in env).
- ``require_session`` — auto-returns the first family_profile_id (no login
  required). This app runs on a private home network so auth is disabled
  for family-facing routes. Kept as a dependency so admin/token endpoints
  can be re-enabled later by restoring cookie logic.

The per-voter approval-token flow on meal items is intentionally NOT covered
here — it has its own short-lived single-use tokens elsewhere.
"""

from fastapi import HTTPException, Request, status
from itsdangerous import TimestampSigner

from app.config import settings
from app.database import get_db
from app.models import FamilyProfile

bearer_header = "Authorization"

SESSION_COOKIE = "mp_session"
SESSION_MAX_AGE = 60 * 60 * 24 * 30  # 30 days


def require_admin(request: Request) -> None:
    """Enforce a shared bearer token. 401 on bad/missing token, 503 if unset."""
    expected = settings.ADMIN_TOKEN
    if not expected:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Admin auth not configured",
        )
    auth = request.headers.get(bearer_header, "")
    if not auth.startswith("Bearer ") or auth[7:] != expected:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid admin token",
        )


def _signer() -> TimestampSigner:
    return TimestampSigner(settings.SECRET_KEY)


def issue_session(family_profile_id: str) -> str:
    """Sign the family_profile_id and return the cookie value."""
    return _signer().sign(family_profile_id.encode()).decode()


def require_session(request: Request) -> str:
    """Auto-authenticate: return the first family_profile_id from the DB.

    No cookie or password needed — this app runs on a private home network.
    If no FamilyProfile exists yet, return \"bootstrap\" so the app can
    initialise itself on first run.
    """
    # 1. Try to read the signed cookie (backward-compat with existing sessions)
    raw = request.cookies.get(SESSION_COOKIE)
    if raw:
        try:
            return (
                _signer().unsign(raw.encode(), max_age=SESSION_MAX_AGE).decode()
            )
        except Exception:
            pass  # fall through to auto-auth

    # 2. Auto-auth: grab the first family profile from the DB
    db = next(get_db())
    profile = db.query(FamilyProfile).first()
    if profile:
        return str(profile.id)

    # 3. Bootstrap hatch — no profile yet, return a sentinel value
    return "bootstrap"
