# --- Builder Stage ---
# Pinned by digest for reproducible builds; Dependabot keeps the tag comment current.
FROM pytorch/pytorch:2.11.0-cuda12.6-cudnn9-runtime@sha256:3bb77138e105723dd4ed760b82fb63d8310ae3a1afc58f76e0ecf0f776568d33 AS builder

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV DEBIAN_FRONTEND=noninteractive

# Install build dependencies. python3-venv is required because the PyTorch
# base image ships a system Python without ensurepip (it dropped the bundled
# conda environment), so `python -m venv` below cannot bootstrap pip otherwise.
RUN apt-get update && apt-get install -y --no-install-recommends \
    git \
    libpq-dev \
    libssl-dev \
    libffi-dev \
    build-essential \
    python3-venv \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY requirements/ /app/requirements/

# Create a virtual environment that inherits system-site-packages (to use torch/torchaudio)
RUN python -m venv --system-site-packages /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

# Capture the system torch/torchaudio versions as pip constraints.
RUN python -c "import torch; print(f'torch=={torch.__version__}')" > constraints.txt && \
    python -c "import torchaudio; print(f'torchaudio=={torchaudio.__version__}')" >> constraints.txt || true

# Install dependencies using the constraints to force usage of system torch
RUN pip install --no-cache-dir -r requirements/worker.txt -c constraints.txt

# Install pyannote.audio without dependencies to use system torch
RUN pip install --no-cache-dir --no-deps pyannote.audio==4.0.5 -c constraints.txt

# Parakeet ASR (onnx-asr) requires the CUDA build of ONNX Runtime. fastembed
# pulls the CPU-only onnxruntime; replace it with a CUDA-12-compatible
# onnxruntime-gpu build that matches this image's CUDA 12.6 runtime.
RUN pip uninstall -y onnxruntime onnxruntime-gpu && \
    pip install --no-cache-dir onnxruntime-gpu==1.20.2

# Install Triton in the venv so Whisper word-level timestamps use GPU-accelerated
# kernels instead of falling back to slower CPU implementations. The base PyTorch
# image ships Triton as a system package, but the venv may not inherit it correctly.
RUN pip install --no-cache-dir triton

# --- Runtime Stage ---
FROM pytorch/pytorch:2.11.0-cuda12.6-cudnn9-runtime@sha256:3bb77138e105723dd4ed760b82fb63d8310ae3a1afc58f76e0ecf0f776568d33 AS runtime

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV DEBIAN_FRONTEND=noninteractive
ENV PATH="/opt/venv/bin:$PATH"
ENV MALLOC_ARENA_MAX=2
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2

RUN apt-get update && \
    # Patch the base image's OpenSSL against CVE-2026-45447 (PKCS7_verify UAF);
    # the pinned PyTorch base predates the Ubuntu fix (3.0.13-0ubuntu3.11).
    apt-get install -y --no-install-recommends --only-upgrade openssl libssl3t64 && \
    apt-get install -y --no-install-recommends \
    ffmpeg \
    libsndfile1 \
    libpq5 \
    libjemalloc2 \
    && \
    # The worker runs Celery and never invokes uv; remove the base image's uv
    # binaries so their bundled rustls-webpki (GHSA-82j2-j2ch-gfr8) is absent
    # from the published runtime image.
    rm -f /usr/local/bin/uv /usr/local/bin/uvx && \
    rm -rf /var/lib/apt/lists/*

# The PyTorch base ships a system Python with vulnerable pillow/urllib3 in
# /usr/local/lib/.../dist-packages. The venv (system-site-packages) shadows them
# at import time with the patched versions from requirements, but the old files
# remain on disk and are flagged by the image scan. Upgrade the system copies in
# place (as root, before the USER switch) to the same patched versions:
# pillow CVE-2026-40192/42311, urllib3 CVE-2026-44431/44432. Keep these versions
# in step with the pins in requirements/base.txt.
RUN /usr/bin/python3 -m pip install --no-cache-dir --break-system-packages \
    --root-user-action=ignore --upgrade pillow==12.2.0 urllib3==2.7.0

COPY --from=builder /opt/venv /opt/venv

WORKDIR /app

COPY . .

# Create a non-root user and switch to it.
# The Ubuntu 24.04-based PyTorch image ships a default user at UID 1000; remove
# whatever occupies 1000 first so appuser keeps UID 1000 for mounted-volume
# ownership. Create directories for volumes to ensure they are owned by appuser.
RUN if getent passwd 1000 >/dev/null 2>&1; then \
        userdel -r "$(getent passwd 1000 | cut -d: -f1)" 2>/dev/null || true; \
    fi && \
    useradd -m -u 1000 appuser && \
    mkdir -p /home/appuser/.cache/huggingface && \
    mkdir -p /app/data && \
    chown -R appuser:appuser /app /home/appuser

USER appuser

# Entrypoint preloads ML models, then hands off to the CMD
ENTRYPOINT ["backend/worker_entrypoint.sh"]

# Default command: a single worker draining all resource lanes (gpu, cpu, io)
# with embedded Celery Beat (-B), so a standalone `docker run` of this image
# still processes everything and fires periodic jobs (15-minute calendar sync,
# 24-hour temp cleanup, calendar push-channel renewal). The beat schedule DB
# lives on the persistent ./data volume so the cadence survives restarts.
#
# In the Compose deployment this CMD is overridden: work is split across the
# worker-gpu / worker-cpu / worker-io services, and beat (-B) runs on the io
# worker ONLY, so periodic jobs cannot double-schedule.
CMD ["celery", "-A", "backend.celery_app.celery_app", "worker", "-B", "-s", "/app/data/celerybeat-schedule", "-Q", "gpu,cpu,io", "--pool=solo", "--concurrency=1", "--loglevel=info"]
