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

FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv
FROM amazon/aws-cli:${AWS_CLI_VERSION} AS aws-cli
FROM ${REGISTRY}python:${DHI_PYTHON_VERSION}-dev AS python

# aws-cli as a complete /usr/local tree. The directories COPY creates get a
# fixed mtime, so the layer digest below is the same on every build (a plain
# COPY records build time on them and re-pushes 62 MB per deploy).
FROM aws-cli AS aws-cli-tree
COPY --from=aws-cli /usr/local/aws-cli/v2/current /out/usr/local
RUN touch -h -t 202001010000.00 /out /out/usr /out/usr/local

FROM python AS base
USER root
ARG UV_PROJECT_ENVIRONMENT=/opt/python
ENV PATH=${UV_PROJECT_ENVIRONMENT}/bin:$PATH
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1

FROM base AS builder
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/relay

# Third-party deps only. hawk is a `../hawk` path dependency; validating the
# lock needs just its pyproject.toml. hawk and relay themselves are installed
# in the prod stage, so code edits leave this layer untouched. Build with:
#   docker build --build-context hawk=../hawk relay/
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 base AS prod
# EKS kubeconfig exec plugin runs `aws eks get-token` at runtime (mirrors hawk/Dockerfile).
COPY --link --from=aws-cli-tree /out/ /

WORKDIR /home/nonroot/app
COPY gunicorn.conf.py ./

# 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 + relay (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/relay/pyproject.toml \
    --mount=type=bind,source=uv.lock,target=/source/relay/uv.lock \
    --mount=type=bind,source=README.md,target=/source/relay/README.md \
    --mount=type=bind,source=src,target=/source/relay/src,rw \
    cd /source/relay \
 && UV_COMPILE_BYTECODE=1 UV_NO_INSTALLER_METADATA=1 UV_LINK_MODE=copy \
    uv sync \
        --locked \
        --no-dev \
        --no-editable \
        --reinstall-package hawk \
        --reinstall-package hawk-relay \
 && rm -rf /tmp/uv-*

USER nonroot
EXPOSE 8080

CMD ["gunicorn", \
    "relay.server:app", \
    "--worker-class", \
    "uvicorn.workers.UvicornWorker", \
    "--bind", \
    "0.0.0.0:8080", \
    "--preload", \
    "--config", \
    "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
USER root
COPY . .
COPY --from=hawk pyproject.toml uv.lock README.md /home/nonroot/hawk/
COPY --from=hawk hawk/ /home/nonroot/hawk/hawk/
RUN uv sync --locked
USER nonroot
