# One image, two roles (US08-02).
#
# The application is not self-contained Python: it shells out to `exiftool` for every
# EXIF checkpoint and to `immich-go` for every upload, and it serves the static
# frontend from `frontend/`. All three are installed here at pinned versions, because
# an image whose external tools drift is an image whose metadata checkpoints and
# upload reports drift with them (concept §15, "External integration risks").
#
# Everything is pinned:
#   * the base image by tag *and* digest, so a moved tag cannot change the runtime;
#   * exiftool by its Debian package version, verified against `exiftool -ver`;
#   * immich-go by release version and per-architecture SHA-256 of the release asset.
# The verified versions become image labels and /etc/photo-pipeline/versions.json,
# which `python -m photo_pipeline diagnostics` reports — so a running container can
# prove what it contains instead of being trusted about it.
#
# The project is installed editable on purpose: `photo_pipeline.db` resolves
# `alembic.ini` and `migrations/`, and the API resolves `frontend/`, relative to the
# repository root. An editable install keeps that one layout instead of scattering the
# same files across site-packages and a source tree.

ARG PYTHON_IMAGE=python:3.12.14-slim-trixie@sha256:2c941e860699f878900b0edc2403613c234d4b32eda3cc9fa7036991a2a63c4a

# ── the uploader, fetched and verified outside the final layer ────────────────
FROM ${PYTHON_IMAGE} AS uploader

ARG IMMICH_GO_VERSION=0.32.0
ARG IMMICH_GO_SHA256_AMD64=6e2ad86bafdadb9466d6515de7cb882726c0aea1a21d51164dff361d7d480a97
ARG IMMICH_GO_SHA256_ARM64=2c35d9284baae407ef9540bdac5f488971b0bdc7be758a4d7c05ab270af09fdb

COPY docker/fetch-immich-go.py /tmp/fetch-immich-go.py
RUN python /tmp/fetch-immich-go.py \
        --version "${IMMICH_GO_VERSION}" \
        --sha256-amd64 "${IMMICH_GO_SHA256_AMD64}" \
        --sha256-arm64 "${IMMICH_GO_SHA256_ARM64}" \
        --into /usr/local/bin \
    && /usr/local/bin/immich-go version

# ── the application ──────────────────────────────────────────────────────────
FROM ${PYTHON_IMAGE} AS runtime

ARG EXIFTOOL_VERSION=13.25+dfsg-1
ARG IMMICH_GO_VERSION=0.32.0
# The library is mounted from the host, so the container's identity must match the
# ownership that library already has: everything this application renames, writes
# EXIF into, or archives has to stay owned by the host user afterwards.
ARG UID=1000
ARG GID=1000

LABEL org.opencontainers.image.title="photo_pipeline" \
      org.opencontainers.image.source="https://github.com/domverse/photoanalyzer" \
      io.photoanalyzer.exiftool.version="${EXIFTOOL_VERSION}" \
      io.photoanalyzer.immich-go.version="${IMMICH_GO_VERSION}"

ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PATH=/opt/venv/bin:$PATH \
    PHOTO_PIPELINE_DATA_DIR=/data

RUN set -eu; \
    apt-get update; \
    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
        "libimage-exiftool-perl=${EXIFTOOL_VERSION}"; \
    rm -rf /var/lib/apt/lists/*

COPY --from=uploader /usr/local/bin/immich-go /usr/local/bin/immich-go

WORKDIR /app
COPY pyproject.toml alembic.ini README.md ./
COPY photo_pipeline ./photo_pipeline
COPY migrations ./migrations
COPY frontend ./frontend
COPY docker/entrypoint.sh docker/healthcheck.sh /usr/local/bin/

# Runtime dependencies only: the `test` extra (pytest, playwright) and the `vision`
# extra stay out, and pip's build isolation leaves no build tooling behind.
RUN set -eu; \
    python -m venv /opt/venv; \
    /opt/venv/bin/pip install --no-cache-dir -e .

# What is installed must be what was pinned, or the labels and the version record
# would be a claim rather than a fact.
RUN set -eu; \
    mkdir -p /etc/photo-pipeline; \
    exiftool_version="$(exiftool -ver)"; \
    immich_go_version="$(immich-go version | head -n 1 | tr -d '\r')"; \
    expected_exiftool="$(printf '%s' "${EXIFTOOL_VERSION}" | cut -d+ -f1 | cut -d- -f1)"; \
    [ "${exiftool_version}" = "${expected_exiftool}" ] \
      || { echo "exiftool ${exiftool_version} is not the pinned ${expected_exiftool}" >&2; exit 1; }; \
    case "${immich_go_version}" in \
      *"${IMMICH_GO_VERSION}"*) ;; \
      *) echo "immich-go '${immich_go_version}' is not pinned ${IMMICH_GO_VERSION}" >&2; exit 1 ;; \
    esac; \
    printf '{\n  "exiftool": "%s",\n  "immich-go": "%s"\n}\n' \
        "${exiftool_version}" "${IMMICH_GO_VERSION}" > /etc/photo-pipeline/versions.json

# Non-root, with the host library's ownership. /data is the persistent volume; the
# photo library itself is mounted by the deployment (US08-03), never baked in.
RUN set -eu; \
    groupadd --gid "${GID}" --non-unique app; \
    useradd --uid "${UID}" --gid "${GID}" --non-unique --no-create-home --home-dir /app app; \
    mkdir -p /data; \
    chown "${UID}:${GID}" /data
USER ${UID}:${GID}

EXPOSE 8000

# Readiness, not liveness: an unmigrated or misconfigured database answers
# /api/v1/health/ready with 503, and a container that cannot serve must not be
# reported healthy. The worker role has no endpoint, so its check is a no-op here.
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
    CMD ["/usr/local/bin/healthcheck.sh"]

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["serve"]
