# syntax=docker/dockerfile:1
# Multi-stage build for the scopa stack (kaya backend + Sycamore/WASM
# frontend). The Docker build context is the REPOSITORY ROOT (see
# docker-compose.yml) so this single image assembles both parts:
#
#   web-builder  rust + trunk -> compiles web/ into web/dist
#   builder      alpine python -> python venv with the backend + deps
#   runtime      alpine python + the venv + the compiled frontend
#
# apk and pip both use BuildKit cache mounts (type=cache): the package
# caches persist in the builder's cache across builds instead of being
# re-downloaded, and never land in the image layers.

# --- Web builder -------------------------------------------------------------
FROM rust:1-slim AS web-builder

ARG TRUNK_VERSION=0.21.14
# The build environment blocks plain HTTP: force the apt mirrors to HTTPS.
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    sed -i 's|http://deb.debian.org|https://deb.debian.org|g' /etc/apt/sources.list.d/debian.sources \
 && apt-get update \
 && apt-get install -y --no-install-recommends curl ca-certificates \
 && curl -fsSL "https://github.com/trunk-rs/trunk/releases/download/v${TRUNK_VERSION}/trunk-x86_64-unknown-linux-gnu.tar.gz" \
      | tar -xz -C /usr/local/bin \
 && rustup target add wasm32-unknown-unknown

WORKDIR /web

# Card images are committed in the repository (CC0 woodcut napoletane deck);
# web/fetch-cards.sh can regenerate them.
COPY web/Cargo.toml web/Cargo.lock web/index.html web/style.css web/Trunk.toml ./
COPY web/assets ./assets
COPY web/src ./src

RUN --mount=type=cache,target=/usr/local/cargo/registry \
    --mount=type=cache,target=/web/target \
    trunk build --release

# --- Python builder ----------------------------------------------------------
FROM alpine:3.24 AS builder

RUN --mount=type=cache,target=/var/cache/apk \
    apk add python3 py3-pip build-base python3-dev

WORKDIR /build

COPY server/pyproject.toml server/README.md server/requirements.txt ./
COPY server/src/ ./src/
# aerich migration files are a release artifact: the db-migrate compose
# service runs `aerich upgrade` from this image before the app starts.
COPY server/migrations/ ./migrations/

RUN --mount=type=cache,target=/root/.cache/pip \
    python3 -m venv /opt/venv \
 && /opt/venv/bin/pip install --upgrade pip \
 && /opt/venv/bin/pip install -r requirements.txt .

# --- Runtime ---------------------------------------------------------------
FROM alpine:3.24

RUN --mount=type=cache,target=/var/cache/apk \
    apk add python3 ca-certificates tzdata \
 && addgroup -S app && adduser -S -G app app

COPY --from=builder /opt/venv /opt/venv
COPY --from=builder /build/migrations /app/migrations
# aerich reads [tool.aerich] from pyproject.toml (its default config file);
# the db-migrate compose service runs `aerich upgrade` with working_dir=/app.
COPY --from=builder /build/pyproject.toml /app/pyproject.toml
# The compiled single-page application, served by the backend itself.
COPY --from=web-builder /web/dist /app/web/dist

ENV PATH="/opt/venv/bin:$PATH" \
    PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    GRANIAN_HOST=0.0.0.0 \
    GRANIAN_PORT=8080 \
    GRANIAN_INTERFACE=rsgi \
    STATIC_DIR=/app/web/dist

USER app

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
  CMD wget -q -O- http://127.0.0.1:8080/api/health || exit 1

CMD ["granian", "scopa.app:app"]
