# ============================================================
# UI Build Stages - Run in parallel with separate caches
# ============================================================
# These stages use registry cache with mode=max, which means:
# - Each stage is cached independently in the registry
# - Only stages with changed dependencies will rebuild
# - Cache mounts persist across builds for faster npm installs
# - Changes to docs/ won't invalidate config_portal or webui caches
# ============================================================

# Build Config Portal UI
FROM node:25.5.0-trixie-slim AS ui-config-portal
WORKDIR /build/config_portal/frontend
COPY config_portal/frontend/package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci
COPY config_portal/frontend ./
RUN npm run build

# Build WebUI
FROM node:25.5.0-trixie-slim AS ui-webui
WORKDIR /build/client/webui/frontend
COPY client/webui/frontend/package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci
COPY client/webui/frontend ./
RUN npm run build

# Build Documentation
FROM node:25.5.0-trixie-slim AS ui-docs
WORKDIR /build/docs
COPY docs/package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci
COPY docs ./
COPY README.md ../README.md
COPY cli/__init__.py ../cli/__init__.py
RUN npm run build

# Stage to extract Node.js binaries for use in Python stages
FROM node:25.5.0-trixie-slim AS node-binaries

# ============================================================
# Python Build Stage
# ============================================================
# This stage uses registry cache with mode=max for optimal caching:
# - uv cache mount (/root/.cache/uv) speeds up package downloads
# - Lock file changes only rebuild dependency installation layer
# - Source code changes only rebuild the wheel build layer
# - Independent from UI build stages - Python changes don't rebuild UI
# ============================================================
FROM python:3.13.11-slim-trixie AS builder

# Copy Node.js 25 from the official node image - Revert to NodeSource when useful (25.5 or 26) version is available
COPY --from=node-binaries /usr/local/bin/node /usr/local/bin/node
COPY --from=node-binaries /usr/local/bin/npm /usr/local/bin/npm
COPY --from=node-binaries /usr/local/bin/npx /usr/local/bin/npx
COPY --from=node-binaries /usr/local/lib/node_modules /usr/local/lib/node_modules

# Install system dependencies and uv
# Add unstable repo with APT pinning to only upgrade libtasn1-6 (CVE-2025-13151 fix)
# Pin libc6=2.41-12+deb13u2 to fix CVE-2026-0861, CVE-2026-0915, CVE-2025-15281 (glibc vulnerabilities)
# Pin dpkg=1.22.22 to fix CVE-2026-2219 (denial of service via zstd-compressed .deb archives)
RUN echo "deb http://deb.debian.org/debian unstable main" > /etc/apt/sources.list.d/unstable.list && \
    printf "Package: *\nPin: release a=unstable\nPin-Priority: 50\n\nPackage: libtasn1-6\nPin: release a=unstable\nPin-Priority: 900\n" > /etc/apt/preferences.d/99pin-libtasn1 && \
    apt-get update && \
    apt-get install -y --no-install-recommends \
    build-essential \
    curl \
    dpkg=1.22.22 \
    ffmpeg=7:7.1.3-0+deb13u1  \
    git \
    libc6=2.41-12+deb13u2 \
    libtasn1-6/unstable \
    libpng16-16t64=1.6.48-1+deb13u4 \
    libsqlite3-0=3.46.1-7+deb13u1 \
    libssl3t64=3.5.5-1~deb13u2 \
    libvpx9=1.15.0-2.1+deb13u1 \
    openssl=3.5.5-1~deb13u2 && \
    curl -LsSf https://astral.sh/uv/install.sh | sh && \
    mv /root/.local/bin/uv /usr/local/bin/uv && \
    rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unstable.list /etc/apt/preferences.d/99pin-libtasn1 && \
    python3 -m venv /opt/venv && \
    uv pip install --system "virtualenv<21" hatch

WORKDIR /app

ENV VIRTUAL_ENV=/opt/venv
ENV UV_LINK_MODE=copy
ENV UV_COMPILE_BYTECODE=1

# Sync dependencies from lock file directly into venv (cached layer)
# This is the expensive step with 188 packages (~8s with cache, ~280MB downloads without)
# Using lock file ensures reproducible builds with exact versions
# --frozen ensures lock file isn't modified, --no-dev skips dev dependencies
RUN --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    uv sync \
        --frozen \
        --no-dev \
        --active \
        --no-install-project

# Copy Python source code and essential files (skip UI source code)
COPY src ./src
COPY cli ./cli
COPY evaluation ./evaluation
COPY templates ./templates
COPY config_portal/__init__.py ./config_portal/__init__.py
COPY config_portal/backend ./config_portal/backend
COPY .github/helper_scripts ./.github/helper_scripts

# Copy pre-built UI static assets from UI build stages
COPY --from=ui-config-portal /build/config_portal/frontend/static ./config_portal/frontend/static
COPY --from=ui-webui /build/client/webui/frontend/static ./client/webui/frontend/static
COPY --from=ui-docs /build/docs/build ./docs/build

COPY LICENSE ./LICENSE
COPY README.md ./README.md
COPY pyproject.toml ./pyproject.toml

# Build the project wheel with cache mount
# Set SAM_SKIP_UI_BUILD to skip npm builds since we already have static assets
RUN --mount=type=cache,target=/root/.cache/uv \
    SAM_SKIP_UI_BUILD=true hatch build -t wheel

# Install only the wheel package (not dependencies, they're already installed)
# This is fast since all deps are already in the venv
RUN --mount=type=cache,target=/root/.cache/uv \
    uv pip install /app/dist/solace_agent_mesh-*.whl

# Runtime stage
FROM python:3.13.11-slim-trixie AS runtime

ENV PYTHONUNBUFFERED=1
ENV PATH="/opt/venv/bin:$PATH"

# Build argument to control LibreOffice installation for binary artifact preview
# LibreOffice is NOT installed by default to keep image size smaller
# To enable binary artifact preview (DOCX/PPTX), set:
#   docker build --build-arg INSTALL_LIBREOFFICE=true -t sam .
# Or via environment variable:
#   INSTALL_LIBREOFFICE=true docker build --build-arg INSTALL_LIBREOFFICE -t sam .
#
# IMPORTANT: LibreOffice is a separate open-source application licensed under MPL-2.0.
# See THIRD_PARTY_LICENSES/LIBREOFFICE.md for full license and attribution details.
# Source code: https://www.libreoffice.org/download/source-code/
ARG INSTALL_LIBREOFFICE

# Copy Node.js 25 from the official node image
COPY --from=node-binaries /usr/local/bin/node /usr/local/bin/node
COPY --from=node-binaries /usr/local/bin/npm /usr/local/bin/npm
COPY --from=node-binaries /usr/local/bin/npx /usr/local/bin/npx
COPY --from=node-binaries /usr/local/lib/node_modules /usr/local/lib/node_modules

# Install minimal runtime dependencies (no uv for licensing compliance, no curl - due to vulnerabilities)
# LibreOffice is optionally installed for document conversion (DOCX/PPTX to PDF for preview)
# Add unstable repo with APT pinning to only upgrade libtasn1-6 (CVE-2025-13151 fix)
# Pin libc6=2.41-12+deb13u2 to fix CVE-2026-0861, CVE-2026-0915, CVE-2025-15281 (glibc vulnerabilities)
# Pin dpkg=1.22.22 to fix CVE-2026-2219 (denial of service via zstd-compressed .deb archives)
RUN echo "deb http://deb.debian.org/debian unstable main" > /etc/apt/sources.list.d/unstable.list && \
    printf "Package: *\nPin: release a=unstable\nPin-Priority: 50\n\nPackage: libtasn1-6\nPin: release a=unstable\nPin-Priority: 900\n" > /etc/apt/preferences.d/99pin-libtasn1 && \
    apt-get update && \
    apt-get install -y --no-install-recommends \
    dpkg=1.22.22 \
    ffmpeg=7:7.1.3-0+deb13u1 \
    git \
    libatomic1 \
    libc6=2.41-12+deb13u2 \
    libtasn1-6/unstable \
    libpng16-16t64=1.6.48-1+deb13u4 \
    libsqlite3-0=3.46.1-7+deb13u1 \
    libssl3t64=3.5.5-1~deb13u2 \
    libvpx9=1.15.0-2.1+deb13u1 \
    openssl=3.5.5-1~deb13u2 && \
    if [ "${INSTALL_LIBREOFFICE}" = "true" ]; then \
        echo "============================================================" && \
        echo "NOTICE: Installing LibreOffice - a separate open-source application" && \
        echo "LibreOffice is licensed under Mozilla Public License 2.0 (MPL-2.0)" && \
        echo "License: https://www.mozilla.org/en-US/MPL/2.0/" && \
        echo "Source:  https://www.libreoffice.org/download/source-code/" && \
        echo "See THIRD_PARTY_LICENSES/LIBREOFFICE.md for full attribution" && \
        echo "============================================================" && \
        apt-get install -y --no-install-recommends \
        libreoffice-writer-nogui \
        libreoffice-impress-nogui \
        libreoffice-calc-nogui; \
    else \
        echo "Skipping LibreOffice installation (set INSTALL_LIBREOFFICE=true to enable binary artifact preview)"; \
    fi && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unstable.list /etc/apt/preferences.d/99pin-libtasn1

# Node 25.5.0 ships with npm 11.8.0; upgrade to pick up security fixes in bundled dependencies
RUN node /usr/local/lib/node_modules/npm/bin/npm-cli.js install -g npm@11.11.1

# Install playwright temporarily just for browser installation (cached layer)
# This is separate from the full venv to keep this layer cached
# We'll use the playwright from the full venv at runtime
RUN --mount=type=cache,target=/root/.cache/pip \
    --mount=type=cache,target=/root/.cache/playwright \
    python3 -m pip install playwright && \
    playwright install-deps chromium && \
    playwright install chromium && \
    python3 -m pip uninstall playwright -y

# Create non-root user and Playwright cache directory
RUN groupadd -r solaceai && useradd --create-home -r -g solaceai solaceai && \
    mkdir -p /var/cache/playwright && \
    chown -R solaceai:solaceai /var/cache/playwright

WORKDIR /app
RUN chown -R solaceai:solaceai /app

# Copy the pre-built virtual environment from builder
# This avoids slow pip install in runtime (UV already did it)
# Copied AFTER Playwright setup so Playwright layers stay cached
COPY --from=builder /opt/venv /opt/venv

COPY preset /preset

USER solaceai
# Required environment variables
ENV CONFIG_PORTAL_HOST=0.0.0.0
ENV FASTAPI_HOST=0.0.0.0
ENV FASTAPI_PORT=8000
ENV NAMESPACE=sam/
ENV SOLACE_DEV_MODE=True

# Set the following environment variables to appropriate values before deploying
ENV SESSION_SECRET_KEY="REPLACE_WITH_SESSION_SECRET_KEY"

LABEL org.opencontainers.image.source=https://github.com/SolaceLabs/solace-agent-mesh

EXPOSE 5002 8000

# CLI entry point
ENTRYPOINT ["solace-agent-mesh"]

# Default command to run the preset agents
CMD ["run", "/preset/agents"]
