# Multi-stage build for the RealSense D4xx API server on aarch64 (Jetson)
# and x86_64. The Intel apt repo ships librealsense2 runtime for arm64
# but no pyrealsense2 wheel, so the Python bindings are built from source
# in a dedicated builder stage and copied into the runtime image.

# ---------------------------------------------------------------------------
# Stage 1: build pyrealsense2 (Python bindings) from source
# ---------------------------------------------------------------------------
FROM ubuntu:22.04 AS librealsense-builder
ENV DEBIAN_FRONTEND=noninteractive
ARG RS_VERSION=v2.55.1

RUN apt-get update && apt-get install -y --no-install-recommends \
        git cmake build-essential pkg-config ca-certificates \
        libssl-dev libusb-1.0-0-dev libudev-dev \
        python3 python3-dev python3-pip \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /src
RUN git clone --depth 1 --branch ${RS_VERSION} https://github.com/IntelRealSense/librealsense.git

WORKDIR /src/librealsense/build
RUN cmake .. \
        -DCMAKE_BUILD_TYPE=Release \
        -DBUILD_EXAMPLES=OFF \
        -DBUILD_GRAPHICAL_EXAMPLES=OFF \
        -DBUILD_TOOLS=OFF \
        -DBUILD_UNIT_TESTS=OFF \
        -DBUILD_NETWORK_DEVICE=OFF \
        -DBUILD_PYTHON_BINDINGS=ON \
        -DPYTHON_EXECUTABLE=/usr/bin/python3 \
        -DCMAKE_INSTALL_PREFIX=/opt/install \
    && make -j$(nproc) \
    && make install

# librealsense@v2.55.1 has a buggy install rule that doesn't install the
# main pyrealsense2.so — only pyrsutils.so. We pick the main .so straight
# from the build dir to work around it.
RUN mkdir -p /opt/pyrealsense2 \
    && cp -r /usr/lib/python3/dist-packages/pyrealsense2/. /opt/pyrealsense2/ \
    && cp /src/librealsense/build/Release/pyrealsense2.cpython-310-aarch64-linux-gnu.so /opt/pyrealsense2/ \
    && ls /opt/pyrealsense2/pyrealsense2.cpython-310-aarch64-linux-gnu.so > /dev/null \
    && printf 'from .pyrealsense2 import *\n' > /opt/pyrealsense2/__init__.py \
    && echo "=== /opt/pyrealsense2 contents ===" \
    && ls -la /opt/pyrealsense2

# ---------------------------------------------------------------------------
# Stage 2: build React frontend
# ---------------------------------------------------------------------------
FROM node:20-alpine AS frontend-build
WORKDIR /app
COPY src/frontend/react/package*.json ./
RUN npm ci
COPY src/frontend/react/ .
RUN npm run build

# ---------------------------------------------------------------------------
# Stage 3: runtime image
# ---------------------------------------------------------------------------
FROM ubuntu:22.04 AS runtime
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y --no-install-recommends \
        ca-certificates curl gnupg \
        python3 python3-pip python3-venv \
        libusb-1.0-0 libudev1 \
        libgl1 libglib2.0-0 libsm6 libxext6 libxrender1 \
        usbutils \
    && rm -rf /var/lib/apt/lists/*

# Intel RealSense apt repo for the librealsense2 native runtime (pinned to v2.55.1).
# Intel rotated the signing key in 2025: the legacy librealsense.pgp file on
# their server is the old 2018 key (C8B3A55A...), but the current `jammy`
# Packages index is signed by the new key FB0B24895113F120. We fetch the new
# key from Ubuntu's keyserver and dearmor it into the trusted keyring.
RUN mkdir -p /etc/apt/keyrings \
    && curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xFB0B24895113F120" \
       | gpg --dearmor -o /etc/apt/keyrings/librealsense.gpg \
    && echo "deb [signed-by=/etc/apt/keyrings/librealsense.gpg] https://librealsense.intel.com/Debian/apt-repo jammy main" \
        > /etc/apt/sources.list.d/librealsense.list \
    && apt-get update \
    && apt-get install -y --no-install-recommends \
        librealsense2=2.55.1-0~realsense.3337 \
        librealsense2-udev-rules=2.55.1-0~realsense.3337 \
    && rm -rf /var/lib/apt/lists/*

# Python bindings (built in stage 1). System Python 3.10 looks in
# /usr/lib/python3/dist-packages, so install there.
COPY --from=librealsense-builder /opt/pyrealsense2 /usr/lib/python3/dist-packages/pyrealsense2

WORKDIR /app

# Python dependencies — keep this layer cacheable: install before copying source.
RUN pip3 install --no-cache-dir \
        "fastapi>=0.115" \
        "uvicorn[standard]>=0.34" \
        "pydantic>=2.0" \
        "pydantic-settings>=2.0" \
        "python-dotenv>=1.0" \
        "nats-py>=2.9" \
        "numpy>=1.24,<2" \
        "opencv-python-headless>=4.8"

# Application source
COPY src/backend/ src/backend/
COPY --from=frontend-build /app/dist src/frontend/react/dist/

# Entrypoint
COPY scripts/entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh

# Optional .env (compose can also inject via env_file)
COPY .env* ./

EXPOSE 8878

ENTRYPOINT ["/app/entrypoint.sh"]
