# ClippyMe — Multi-platform Dockerfile
#
# CPU / Apple Silicon (default):  docker compose up --build
# NVIDIA GPU:                     docker compose -f docker-compose.yml -f docker-compose.gpu.yml up --build

ARG GPU_RUNTIME=cpu

# ============================================================
# Stage 2a: NVIDIA CUDA runtime (x86_64 only)
# ============================================================
# Ubuntu 24.04 (glibc 2.39) — the auto-editor releases (v29+) are built on
# 24.04-era runners and hard-require GLIBC_2.38; the old 22.04 base (2.35)
# loaded the binary but it died at runtime with "GLIBC_2.38 not found", so
# Smart Cut silently fell back to FFmpeg. CUDA stays on the 12.x line so the
# torch cu12 wheels and the NVIDIA pip stack keep matching.
FROM nvidia/cuda:12.6.3-cudnn-runtime-ubuntu24.04 AS runtime-nvidia

ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Etc/UTC

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    python3 python3-venv python3-dev \
    ffmpeg libgl1 libglib2.0-0 libsm6 libxext6 libxrender1 libcairo2 \
    curl unzip ca-certificates gosu && \
    curl -fsSL https://deno.land/install.sh | sh -s v2.8.3 && \
    mv /root/.deno/bin/deno /usr/local/bin/ && \
    rm -rf /root/.deno && \
    ln -sf /usr/bin/python3 /usr/bin/python && \
    curl -fsSL -o /tmp/get-pip.py https://bootstrap.pypa.io/get-pip.py && python3 /tmp/get-pip.py --break-system-packages && \
    # software-properties-common (used above only for add-apt-repository) pulls
    # Debian's python3-* packages (pyparsing, six, httplib2, gi, apt, …) into
    # the shared /usr/lib/python3/dist-packages. python3.11's pip sees those and
    # fails to REPLACE any it needs ("no RECORD file") — e.g. pyparsing when
    # requirements.lock pins a different version. The app only uses python3.11
    # pip-installed packages, so drop the Debian (python3.12) shared dir.
    rm -rf /usr/lib/python3/dist-packages && \
    rm -rf /var/lib/apt/lists/* && \
    # Install a PINNED auto-editor Nim binary (v30.x track) with sha256
    # verification, so a re-tagged/tampered GitHub asset can't slip in at build
    # time. The optional runtime updater keeps it fresh only when explicitly
    # enabled; bump AE_VERSION + the digests together when updating the pin.
    AE_VERSION=30.5.0 && \
    ARCH=$(uname -m) && \
    case "$ARCH" in \
      x86_64)  AE_ASSET=auto-editor-linux-x86_64;  AE_SHA=673e69b096d740736364f34669e864505294441f5ec9188642b33e24b07cf147 ;; \
      aarch64) AE_ASSET=auto-editor-linux-aarch64; AE_SHA=0c54d2cbc617fd369dae434eb62156557877da47c60fd8b2018b65b481166a4e ;; \
      *) echo "Unsupported arch $ARCH for auto-editor binary"; exit 1 ;; \
    esac && \
    curl -fsSL -o /usr/local/bin/auto-editor \
      "https://github.com/WyattBlue/auto-editor/releases/download/${AE_VERSION}/$AE_ASSET" && \
    echo "$AE_SHA  /usr/local/bin/auto-editor" | sha256sum -c - && \
    chmod +x /usr/local/bin/auto-editor && \
    (/usr/local/bin/auto-editor --version || echo "auto-editor version check failed (non-fatal)")

ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility

# ============================================================
# Stage 2b: CPU runtime (multi-arch: amd64, arm64, Apple Silicon)
# ============================================================
# Ubuntu 24.04 (glibc 2.39) instead of the old python:3.11-slim (Debian
# bookworm, glibc 2.36) — auto-editor needs GLIBC_2.38 (see runtime-nvidia).
# python 3.11 is kept (via deadsnakes) so the pinned CV/ML wheels (torch,
# mediapipe 0.10.14, …) are unchanged; the pip bootstrap mirrors runtime-nvidia.
FROM ubuntu:24.04 AS runtime-cpu

ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Etc/UTC

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    python3 python3-venv python3-dev \
    ffmpeg libgl1 libglib2.0-0 libsm6 libxext6 libxrender1 libcairo2 \
    curl unzip ca-certificates gosu && \
    curl -fsSL https://deno.land/install.sh | sh -s v2.8.3 && \
    mv /root/.deno/bin/deno /usr/local/bin/ && \
    rm -rf /root/.deno && \
    ln -sf /usr/bin/python3 /usr/bin/python && \
    curl -fsSL -o /tmp/get-pip.py https://bootstrap.pypa.io/get-pip.py && python3 /tmp/get-pip.py --break-system-packages && \
    # software-properties-common (used above only for add-apt-repository) pulls
    # Debian's python3-* packages (pyparsing, six, httplib2, gi, apt, …) into
    # the shared /usr/lib/python3/dist-packages. python3.11's pip sees those and
    # fails to REPLACE any it needs ("no RECORD file") — e.g. pyparsing when
    # requirements.lock pins a different version. The app only uses python3.11
    # pip-installed packages, so drop the Debian (python3.12) shared dir.
    rm -rf /usr/lib/python3/dist-packages && \
    rm -rf /var/lib/apt/lists/* && \
    # Install a PINNED auto-editor Nim binary (v30.x track) with sha256
    # verification, so a re-tagged/tampered GitHub asset can't slip in at build
    # time. The optional runtime updater keeps it fresh only when explicitly
    # enabled; bump AE_VERSION + the digests together when updating the pin.
    AE_VERSION=30.5.0 && \
    ARCH=$(uname -m) && \
    case "$ARCH" in \
      x86_64)  AE_ASSET=auto-editor-linux-x86_64;  AE_SHA=673e69b096d740736364f34669e864505294441f5ec9188642b33e24b07cf147 ;; \
      aarch64) AE_ASSET=auto-editor-linux-aarch64; AE_SHA=0c54d2cbc617fd369dae434eb62156557877da47c60fd8b2018b65b481166a4e ;; \
      *) echo "Unsupported arch $ARCH for auto-editor binary"; exit 1 ;; \
    esac && \
    curl -fsSL -o /usr/local/bin/auto-editor \
      "https://github.com/WyattBlue/auto-editor/releases/download/${AE_VERSION}/$AE_ASSET" && \
    echo "$AE_SHA  /usr/local/bin/auto-editor" | sha256sum -c - && \
    chmod +x /usr/local/bin/auto-editor && \
    (/usr/local/bin/auto-editor --version || echo "auto-editor version check failed (non-fatal)")

# ============================================================
# Stage 3: Final image
# ============================================================
FROM runtime-${GPU_RUNTIME} AS final

WORKDIR /app
ENV PYTHONUNBUFFERED=1
# /app/data/bin is the writable location where auto_editor_updater.py drops
# fresh auto-editor binaries at runtime. Prepend it so it shadows the
# system-wide install in /usr/local/bin when a newer version is available.
ENV PATH=/app/data/bin:$PATH

# Install Python deps. CUDA pip wheels (nvidia-cublas-cu12, cudnn) are only
# needed on the GPU path — skipping them on CPU saves ~500 MB per image.
#
# Speaker diarization on the Whisper path is OPT-IN via ENABLE_WHISPER_DIARIZE.
# pyannote.audio pulls ~500 MB of deps (pytorch-lightning, speechbrain,
# torchaudio extras) and requires accepting the pyannote/speaker-diarization-3.1
# license on HuggingFace, so we keep it out of the default image.
# Build with:   docker compose build --build-arg ENABLE_WHISPER_DIARIZE=1
ARG GPU_RUNTIME
ARG ENABLE_WHISPER_DIARIZE=0
# Install from the fully-pinned core lock plus the explicitly pinned auxiliary
# CLI/rendering tools. requirements.txt is copied for reference/diagnostics.
COPY requirements.lock requirements.txt requirements-runtime-tools.txt ./
# BuildKit cache mount: pip's download cache lives in the mount (shared across
# rebuilds) and is NOT baked into the image layer.
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install --break-system-packages --upgrade pip && \
    pip install --break-system-packages -r requirements.lock -r requirements-runtime-tools.txt && \
    if [ "$GPU_RUNTIME" = "nvidia" ]; then \
        pip install --break-system-packages nvidia-cublas-cu12 && \
        SITE=$(python -c "import site; print(site.getsitepackages()[0])") && \
        echo "$SITE/nvidia/cublas/lib" > /etc/ld.so.conf.d/nvidia-pip.conf && \
        echo "$SITE/nvidia/cudnn/lib" >> /etc/ld.so.conf.d/nvidia-pip.conf && \
        ldconfig 2>/dev/null || true; \
    fi && \
    if [ "$ENABLE_WHISPER_DIARIZE" = "1" ]; then \
        pip install --break-system-packages 'pyannote.audio>=3.1'; \
    fi

# NOTE: do NOT `pip install --upgrade yt-dlp` here — that would un-pin yt-dlp
# from requirements.lock and pull whatever the latest unreviewed release is at
# build time. The reviewed floor is yt-dlp>=2026.6.9,<2027; update it by
# regenerating the lock.

# Create non-root user
RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser && \
    mkdir -p /app/uploads /app/output /app/data /app/data/bin /tmp/Ultralytics && \
    chown -R appuser:appuser /app /tmp/Ultralytics

USER appuser

# Pre-download YOLO model
RUN python -c "from ultralytics import YOLO; YOLO('yolov8n.pt')"

COPY --chown=appuser:appuser . .

# Install the clippyme package itself (src-layout) so that
# `python -m clippyme.pipeline.main` and `uvicorn clippyme.api.app:app` resolve.
USER root
RUN pip install --break-system-packages --no-cache-dir -e .

# Entrypoint normalizes ownership of the (bind-mountable) data/ dir as root,
# then drops to appuser via gosu before launching the server. Copied to a
# path OUTSIDE /app so the `.:/app` bind mount can't shadow it.
COPY --chmod=0755 docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]

EXPOSE 8000

HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:8000/ || exit 1

CMD ["uvicorn", "clippyme.api.app:app", "--host", "0.0.0.0", "--port", "8000"]
