ARG DHI_PYTHON_VERSION=3.13
ARG REGISTRY=dhi.io/
ARG UV_VERSION=0.12.3

FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv
# Docker Hardened Image base (as hawk-api) — OS packages patched upstream, so
# no apt-get upgrade. Ref: SUPPLY-MIDDLEMAN-1.
FROM ${REGISTRY}python:${DHI_PYTHON_VERSION}-dev AS python
ARG UV_PROJECT_ENVIRONMENT=/opt/python
ENV PATH=${UV_PROJECT_ENVIRONMENT}/bin:$PATH

FROM python AS builder
USER root
COPY --from=uv /uv /uvx /usr/local/bin/
ENV UV_COMPILE_BYTECODE=1
ENV UV_NO_INSTALLER_METADATA=1
ENV UV_LINK_MODE=copy

WORKDIR /source/middleman

# Third-party deps only. hawk is a `../hawk` path dependency; validating the
# lock needs just its pyproject.toml. hawk and middleman themselves are
# installed in the prod stage, so code edits leave this layer untouched.
COPY --from=hawk pyproject.toml /source/hawk/
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync \
        --locked \
        --no-dev \
        --no-install-project \
        --no-install-package hawk

FROM builder AS build-dev
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync \
        --locked \
        --no-install-project \
        --no-install-package hawk

FROM python AS prod
USER root

ARG MIDDLEMAN_USERNAME=middleman
ARG MIDDLEMAN_UID=1000
ARG MIDDLEMAN_GID=999
ARG MIDDLEMAN_HOME=/home/${MIDDLEMAN_USERNAME}/app
ARG CACHE_DIRECTORY=/home/${MIDDLEMAN_USERNAME}/.cache/middleman

# DHI has no passwd tools; install to create the service account, then purge in
# the same layer so the prod image doesn't retain useradd/groupadd.
RUN apt-get update \
    && apt-get install -y --no-install-recommends passwd \
    && groupadd -g ${MIDDLEMAN_GID} ${MIDDLEMAN_USERNAME} \
    && useradd -m -u ${MIDDLEMAN_UID} -g ${MIDDLEMAN_USERNAME} -s /bin/sh ${MIDDLEMAN_USERNAME} \
    && mkdir -p ${MIDDLEMAN_HOME} ${CACHE_DIRECTORY} \
    && chown -R ${MIDDLEMAN_UID}:${MIDDLEMAN_GID} /home/${MIDDLEMAN_USERNAME} ${CACHE_DIRECTORY} \
    && echo '[]' > ${CACHE_DIRECTORY}/models.jsonc \
    && echo '{}' > ${CACHE_DIRECTORY}/models_base_info.jsonc \
    && apt-get purge -y passwd \
    && rm -rf /var/lib/apt/lists/*

ENV CACHE_DIRECTORY=${CACHE_DIRECTORY}
ENV MODELS_BASE_INFO_JSON_PATH=${CACHE_DIRECTORY}/models_base_info.jsonc
ENV MODELS_JSON_PATH=${CACHE_DIRECTORY}/models.jsonc

WORKDIR ${MIDDLEMAN_HOME}
COPY gunicorn.conf.py ./
RUN echo '[]' > models_public.jsonc \
    && echo '{}' > models_base_info_public.jsonc
COPY --chmod=755 docker-entrypoint.sh /usr/local/bin/

# Stable layer: third-party deps. `--link` keeps its digest independent of the
# layers above.
COPY --link --from=builder ${UV_PROJECT_ENVIRONMENT} ${UV_PROJECT_ENVIRONMENT}
# Volatile layer: hawk + middleman (a few MB), built from bind-mounted sources so
# neither they nor uv land in the image. Only the files the build reads are
# mounted, so a tests-only commit leaves this layer cached; src is `rw` because
# setuptools writes *.egg-info into it (discarded). `--reinstall-package` bypasses
# uv's built-wheel cache, whose key ignores .py edits.
RUN --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,from=uv,source=/uv,target=/usr/local/bin/uv \
    --mount=type=bind,from=hawk,source=pyproject.toml,target=/source/hawk/pyproject.toml \
    --mount=type=bind,from=hawk,source=README.md,target=/source/hawk/README.md \
    --mount=type=bind,from=hawk,source=hawk,target=/source/hawk/hawk \
    --mount=type=bind,source=pyproject.toml,target=/source/middleman/pyproject.toml \
    --mount=type=bind,source=uv.lock,target=/source/middleman/uv.lock \
    --mount=type=bind,source=README.md,target=/source/middleman/README.md \
    --mount=type=bind,source=src,target=/source/middleman/src,rw \
    cd /source/middleman \
 && UV_COMPILE_BYTECODE=1 UV_NO_INSTALLER_METADATA=1 UV_LINK_MODE=copy PYTHONDONTWRITEBYTECODE=1 \
    uv sync \
        --locked \
        --no-dev \
        --no-editable \
        --reinstall-package hawk \
        --reinstall-package middleman-server \
 && rm -rf /tmp/uv-*

USER ${MIDDLEMAN_USERNAME}
EXPOSE 3500

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["ddtrace-run", "gunicorn", \
    "middleman.server:app", \
    "--worker-class", \
    "uvicorn.workers.UvicornWorker", \
    "--bind", \
    "0.0.0.0:3500", \
    "--preload", \
    "--config", \
    "/home/middleman/app/gunicorn.conf.py", \
    "--log-level", \
    "info", \
    "--error-logfile", \
    "-"]

FROM prod AS dev
COPY --from=build-dev ${UV_PROJECT_ENVIRONMENT} ${UV_PROJECT_ENVIRONMENT}
COPY --from=uv /uv /usr/local/bin/uv
COPY . .
COPY --from=hawk pyproject.toml uv.lock README.md /home/middleman/hawk/
COPY --from=hawk hawk/ /home/middleman/hawk/hawk/
USER root
RUN uv sync --locked
USER ${MIDDLEMAN_USERNAME}
