# syntax=docker/dockerfile:1.7

# ---- Stage 1: builder ---------------------------------------------------------
# Resolves and installs runtime dependencies into a project-local .venv using uv.
FROM python:3.12-slim@sha256:46cb7cc2877e60fbd5e21a9ae6115c30ace7a077b9f8772da879e4590c18c2e3 AS builder

# Pull the uv binary from the upstream image — faster and more reliable than pip-installing it.
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    UV_LINK_MODE=copy \
    UV_COMPILE_BYTECODE=0 \
    UV_PYTHON_DOWNLOADS=never

WORKDIR /app

# Layer 1: lockfile + project metadata only, so dependency install caches
# independently of source changes. README.md is a project-metadata input for
# hatchling (pyproject.toml has `readme = "README.md"`), so it must exist
# when `uv sync` validates the package — even on the deps-only pass.
COPY pyproject.toml uv.lock README.md ./

# Install runtime dependencies only (no dev extras) into ./.venv.
# --frozen asserts the lockfile is authoritative — CI/builds never silently drift.
# --no-install-project skips installing the project itself; we copy src/ after.
RUN uv sync --frozen --no-dev --no-install-project

# Layer 2: application source + migrations. Changes here don't bust the deps
# layer above. alembic.ini and alembic/ must be present in the runtime image so
# `alembic upgrade head` can run at container start; we copy them here in the
# builder stage so a single COPY --from=builder pulls them into runtime.
COPY src/ ./src/
COPY alembic.ini ./alembic.ini
COPY alembic/ ./alembic/

# Install the project itself (editable-free) into the same venv.
RUN uv sync --frozen --no-dev

# Strip bytecode caches that may have been produced — keeps the copied venv lean.
RUN find /app/.venv -type d -name "__pycache__" -prune -exec rm -rf {} + \
    && find /app/.venv -type f -name "*.pyc" -delete


# ---- Stage 2: runtime ---------------------------------------------------------
# Minimal final image: just Python + the pre-built venv + src. No uv, no build tools.
FROM python:3.12-slim@sha256:46cb7cc2877e60fbd5e21a9ae6115c30ace7a077b9f8772da879e4590c18c2e3 AS runtime

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PATH="/app/.venv/bin:$PATH" \
    AGENTDROP_DATA_DIR=/data

# Non-root user. Fixed UID/GID so bind-mounted ./data has predictable ownership
# for users who pre-create the host directory.
RUN groupadd --system --gid 1000 appuser \
    && useradd --system --uid 1000 --gid appuser --home-dir /app --shell /usr/sbin/nologin appuser \
    && mkdir -p /app /data \
    && chown -R appuser:appuser /app /data

WORKDIR /app

# Copy the fully-resolved venv and application source from the builder.
COPY --from=builder --chown=appuser:appuser /app/.venv /app/.venv
COPY --from=builder --chown=appuser:appuser /app/src /app/src

# Migrations — alembic.ini + migration scripts. The entrypoint runs
# `alembic upgrade head` before starting uvicorn so fresh deploys have tables.
COPY --from=builder --chown=appuser:appuser /app/alembic.ini /app/alembic.ini
COPY --from=builder --chown=appuser:appuser /app/alembic /app/alembic

# Entrypoint script: runs migrations, then execs uvicorn so SIGTERM reaches it.
COPY --chown=appuser:appuser scripts/entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh

# Bundle the VAPID keypair generator so end users can run it without a
# source checkout: `docker run --rm --entrypoint python <image> /app/scripts/gen_vapid_keys.py`.
# See docs/QUICKSTART.md for the one-liner. The script's only deps
# (cryptography, py_vapid) are already installed via pywebpush.
COPY --chown=appuser:appuser scripts/gen_vapid_keys.py /app/scripts/gen_vapid_keys.py

USER appuser

VOLUME ["/data"]
EXPOSE 8080

# Basic liveness probe. Uses python's stdlib so we don't drag in curl/wget.
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD python -c "import urllib.request,sys; \
sys.exit(0 if urllib.request.urlopen('http://localhost:8080/health', timeout=3).status == 200 else 1)"

CMD ["/app/entrypoint.sh"]
