# syntax=docker/dockerfile:1.7
#
# Backend container — multi-stage Python 3.12 image.
#
# Stage 1 (builder) installs pyswisseph (needs a C toolchain) + WeasyPrint
# system libs + the editable backend. Stage 2 (runtime) carries only the
# resolved venv + the app source + ephemeris data, so the published image
# stays small and unprivileged.
#
# AGPL-3.0 §13 rebuild target: cloning this repo at the commit recorded by
# `/api/v1/source` and running `docker build -t astro-backend backend/`
# from the repo root reproduces the deployment binary exactly. No private
# build steps. No secret-baked layers.
#
# Vendored dependencies that the build expects to see:
#   * `backend/vendor/pyjhora/`  — PyJHora source (git submodule, AGPL-3.0)
#                                   pinned to `fd935ba` per `_vendored_dependencies()`
#   * `backend/data/kp/KP_SL_Divisions.csv`  — KP 249 sub-lord normative table (MIT)
#
# Both must exist on the build context. The runtime startup module asserts
# their presence at import time (refuses to serve if either is missing).
#
# ---------------------------------------------------------------------------

ARG PYTHON_VERSION=3.12-slim-bookworm

# ---- Stage 1: builder -----------------------------------------------------
FROM python:${PYTHON_VERSION} AS builder

ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
    PIP_NO_CACHE_DIR=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1

# Tooling needed to build pyswisseph from source if no wheel is available
# for the slim base, plus WeasyPrint system libraries.
RUN apt-get update && apt-get install -y --no-install-recommends \
        build-essential \
        gcc \
        libpango-1.0-0 \
        libpangoft2-1.0-0 \
        libharfbuzz0b \
        libcairo2 \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /build

# Copy only the dependency manifest first so dependency resolution caches.
COPY pyproject.toml ./

# Editable install so the `app` package resolves once we copy sources next.
# Uses an isolated venv at /opt/venv to keep a clean, copyable artifact.
RUN python -m venv /opt/venv \
    && /opt/venv/bin/pip install --upgrade pip \
    && /opt/venv/bin/pip install -e .

# Now copy the rest of the build context. The vendored PyJHora tree at
# `vendor/pyjhora/src/jhora/` contains the ephemeris data the runtime needs.
COPY app  ./app
COPY data ./data
COPY vendor ./vendor

# Sanity-fail the build if PyJHora / ephemeris data is missing — the
# runtime would otherwise fail at first request with a confusing trace.
RUN test -d vendor/pyjhora/src/jhora || (echo "PyJHora vendor missing" >&2 && exit 1) \
    && test "$(ls vendor/pyjhora/src/jhora/data/ephe/*.se1 2>/dev/null | wc -l)" -ge 3 \
        || (echo "Ephemeris .se1 files missing in vendor tree" >&2 && exit 1) \
    && test -f data/kp/KP_SL_Divisions.csv \
        || (echo "KP_SL_Divisions.csv missing under data/kp/" >&2 && exit 1)

# ---- Stage 2: runtime -----------------------------------------------------
FROM python:${PYTHON_VERSION} AS runtime

ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PATH="/opt/venv/bin:${PATH}" \
    PYTHONPATH="/app:/app/vendor/pyjhora/src"

# Runtime-only system libs (no compilers in the final image).
RUN apt-get update && apt-get install -y --no-install-recommends \
        libpango-1.0-0 \
        libpangoft2-1.0-0 \
        libharfbuzz0b \
        libcairo2 \
        ca-certificates \
        tzdata \
    && rm -rf /var/lib/apt/lists/*

# Copy the resolved venv and the app source from the builder.
COPY --from=builder /opt/venv /opt/venv
WORKDIR /app
COPY --from=builder /build/app    /app/app
COPY --from=builder /build/data   /app/data
COPY --from=builder /build/vendor /app/vendor
COPY pyproject.toml /app/pyproject.toml

# Drop privileges. Most importantly this stops a runaway WeasyPrint or LLM
# request from being able to write outside /tmp.
RUN useradd --system --uid 10001 --home-dir /app astro \
    && chown -R astro:astro /app
USER astro

EXPOSE 8000

# Readiness probe hits /api/v1/readyz so the orchestrator restarts the
# container when REQUIRED dependencies (supabase, ephemeris, redis) are
# unhealthy. Process-only liveness lives at /healthz; using readyz here
# is correct for Cloud Run / k8s where dependency-failure should shed
# traffic. start-period is generous to absorb cold-start probe latency.
# /api/v1/source remains the AGPL-13 canary — a healthy container should
# also serve a non-UNCONFIGURED `git_remote` once `ASTRO_SOURCE_REPO_URL`
# is set in the env.
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
    CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/v1/readyz', timeout=4)" || exit 1

# Production-grade ASGI runner. `--proxy-headers` so we honour
# X-Forwarded-For when behind Cloudflare / Nginx; `--forwarded-allow-ips=*`
# trusts the immediate proxy (override at orchestration layer if needed).
CMD ["uvicorn", "app.main:app", \
     "--host", "0.0.0.0", \
     "--port", "8000", \
     "--proxy-headers", \
     "--forwarded-allow-ips", "*"]
