# -------------------------------------------------------
# Panguard API - Production Image
#
# Multi-stage build:
#   Stage 1: pnpm workspace build
#   Stage 2: Standalone bundle with npm (no pnpm symlinks)
#
# Build:  docker build -t panguard-api .
# Run:    docker run -p 3000:3000 -v pg-data:/data panguard-api
# -------------------------------------------------------

# Stage 1: Build everything with pnpm workspace
FROM node:22-slim AS builder

# Build tools for native modules (better-sqlite3) + curl/ca-certs for the
# Litestream download below.
RUN apt-get update && \
    apt-get install -y --no-install-recommends python3 make g++ git curl ca-certificates && \
    rm -rf /var/lib/apt/lists/*

# ---- Litestream binary ----
# Pinned to v0.3.13 because:
#   * The litestream.yml config schema in this repo is v0.3.x format.
#   * v0.5.x is a major rewrite with a breaking config change (`replicas` ->
#     `replica`, removal of `retention`/`snapshot-interval`/`validation-interval`).
#   * Upgrading requires rewriting litestream.yml AND retesting failover.
# Docker buildx provides TARGETARCH automatically (amd64 / arm64).
ARG TARGETARCH=amd64
ARG LITESTREAM_VERSION=v0.3.13
ARG LITESTREAM_SHA256_AMD64=eb75a3de5cab03875cdae9f5f539e6aedadd66607003d9b1e7a9077948818ba0
ARG LITESTREAM_SHA256_ARM64=9585f5a508516bd66af2b2376bab4de256a5ef8e2b73ec760559e679628f2d59
RUN set -eu; \
    case "${TARGETARCH}" in \
      amd64) LS_SHA="${LITESTREAM_SHA256_AMD64}";; \
      arm64) LS_SHA="${LITESTREAM_SHA256_ARM64}";; \
      *) echo "Unsupported TARGETARCH=${TARGETARCH} for Litestream"; exit 1;; \
    esac; \
    curl -fsSL -o /tmp/litestream.tar.gz \
      "https://github.com/benbjohnson/litestream/releases/download/${LITESTREAM_VERSION}/litestream-${LITESTREAM_VERSION}-linux-${TARGETARCH}.tar.gz"; \
    echo "${LS_SHA}  /tmp/litestream.tar.gz" | sha256sum -c -; \
    tar -xzf /tmp/litestream.tar.gz -C /usr/local/bin litestream; \
    rm /tmp/litestream.tar.gz; \
    chmod +x /usr/local/bin/litestream; \
    /usr/local/bin/litestream version

ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
ENV CI=true
RUN corepack enable

WORKDIR /build

# Copy workspace config + all package.json files for dependency resolution
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.json .npmrc ./
COPY packages/core/package.json packages/core/
COPY packages/scan-core/package.json packages/scan-core/
COPY packages/panguard/package.json packages/panguard/
COPY packages/panguard-guard/package.json packages/panguard-guard/
COPY packages/panguard-scan/package.json packages/panguard-scan/
COPY packages/panguard-chat/package.json packages/panguard-chat/
COPY packages/panguard-report/package.json packages/panguard-report/
COPY packages/panguard-trap/package.json packages/panguard-trap/
COPY packages/panguard-web/package.json packages/panguard-web/
COPY packages/panguard-mcp/package.json packages/panguard-mcp/
COPY packages/panguard-skill-auditor/package.json packages/panguard-skill-auditor/
COPY packages/threat-cloud/package.json packages/threat-cloud/
COPY packages/atr/package.json packages/atr/
COPY security-hardening/package.json security-hardening/

# Install all dependencies (including dev for TypeScript compilation)
RUN pnpm install --frozen-lockfile --prod=false

# Copy source code (website excluded by .dockerignore)
COPY packages/core/ packages/core/
COPY packages/scan-core/ packages/scan-core/
COPY packages/panguard/ packages/panguard/
COPY packages/panguard-guard/ packages/panguard-guard/
COPY packages/panguard-scan/ packages/panguard-scan/
COPY packages/panguard-chat/ packages/panguard-chat/
COPY packages/panguard-report/ packages/panguard-report/
COPY packages/panguard-trap/ packages/panguard-trap/
COPY packages/panguard-web/ packages/panguard-web/
COPY packages/panguard-mcp/ packages/panguard-mcp/
COPY packages/panguard-skill-auditor/ packages/panguard-skill-auditor/
COPY packages/threat-cloud/ packages/threat-cloud/
COPY packages/atr/ packages/atr/
COPY security-hardening/ security-hardening/
COPY config/ config/
COPY packages/admin/ packages/admin/

# Download community rules at build time (gitignored, not in repo)
COPY scripts/update-sigma-rules.sh scripts/update-sigma-rules.sh
COPY scripts/update-yara-rules.sh scripts/update-yara-rules.sh
RUN bash scripts/update-sigma-rules.sh || echo "WARNING: Sigma community rules download failed"
RUN bash scripts/update-yara-rules.sh || echo "WARNING: YARA community rules download failed"

# Build all backend packages (skip website)
RUN pnpm --filter '!@panguard-ai/website' -r run build

# ---- Create standalone bundle (no pnpm symlinks) ----
# Cache buster: change this value to force Railway to rebuild from here
ARG CACHE_BUST=2026-04-16-v3
RUN mkdir -p /standalone

# Step 1: Copy main CLI entry point
RUN cp -r packages/panguard/dist /standalone/dist

# Step 2: Install external deps with npm (no workspace: references)
# Using echo instead of printf to avoid shell escaping issues across platforms
# Also strip any workspace: references from copied package.json files
RUN echo '{"name":"panguard-api","version":"0.1.0","private":true,"type":"module","dependencies":{"commander":"12.1.0","better-sqlite3":"11.10.0","i18next":"24.2.3","js-yaml":"4.1.1","zod":"3.25.76","pdfkit":"0.15.2","ws":"8.19.0"},"optionalDependencies":{"ssh2":"1.17.0"}}' > /standalone/package.json && \
    cat /standalone/package.json && \
    cd /standalone && npm install --omit=dev

# Step 3: Copy workspace packages into node_modules AFTER npm install
# Strip workspace:* references from package.json (npm doesn't understand pnpm workspace protocol)
RUN mkdir -p /standalone/node_modules/@panguard-ai && \
    for pkg in core scan-core panguard-guard panguard-scan panguard-chat panguard-report panguard-trap panguard-web panguard-mcp panguard-skill-auditor; do \
      mkdir -p /standalone/node_modules/@panguard-ai/$pkg && \
      cp -r packages/$pkg/dist /standalone/node_modules/@panguard-ai/$pkg/dist && \
      sed 's/"workspace:\*"/"*"/g' packages/$pkg/package.json > /standalone/node_modules/@panguard-ai/$pkg/package.json; \
    done && \
    mkdir -p /standalone/node_modules/@panguard-ai/security-hardening && \
    cp -r security-hardening/dist /standalone/node_modules/@panguard-ai/security-hardening/dist && \
    sed 's/"workspace:\*"/"*"/g' security-hardening/package.json > /standalone/node_modules/@panguard-ai/security-hardening/package.json && \
    mkdir -p /standalone/node_modules/@panguard-ai/threat-cloud && \
    cp -r packages/threat-cloud/dist /standalone/node_modules/@panguard-ai/threat-cloud/dist && \
    sed 's/"workspace:\*"/"*"/g' packages/threat-cloud/package.json > /standalone/node_modules/@panguard-ai/threat-cloud/package.json && \
    mkdir -p /standalone/node_modules/@panguard-ai/atr && \
    cp -r packages/atr/dist /standalone/node_modules/@panguard-ai/atr/dist && \
    sed 's/"workspace:\*"/"*"/g' packages/atr/package.json > /standalone/node_modules/@panguard-ai/atr/package.json && \
    mkdir -p /standalone/node_modules/agent-threat-rules && \
    cp -rL node_modules/agent-threat-rules/dist /standalone/node_modules/agent-threat-rules/dist && \
    cp -L node_modules/agent-threat-rules/package.json /standalone/node_modules/agent-threat-rules/ && \
    cp -rL node_modules/agent-threat-rules/rules /standalone/node_modules/agent-threat-rules/rules

# Verify entry point exists
RUN ls -la /standalone/dist/cli/index.js

# -------------------------------------------------------
# Stage 2: Production
FROM node:22-slim

# tini: proper PID 1 init (signal handling, zombie reaping)
# curl: healthcheck probe
RUN apt-get update && \
    apt-get install -y --no-install-recommends tini curl && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copy standalone bundle (flat node_modules, no pnpm symlinks)
COPY --from=builder /standalone .

# Copy config directory (YARA rules etc., at monorepo root)
COPY --from=builder /build/config ./config

# Copy admin dashboard static files (served by panguard serve at /admin)
COPY --from=builder /build/packages/admin ./packages/admin

# Persistent data directory
RUN mkdir -p /data

# Litestream — binary, config, and wrapper entrypoint.
# The entrypoint restores from S3 on cold start (if no local DB) then
# replicates continuously while wrapping the TC server.
COPY --from=builder /usr/local/bin/litestream /usr/local/bin/litestream
COPY litestream.yml /etc/litestream.yml
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh

# Run as non-root user
RUN groupadd --system --gid 1001 panguard && \
    useradd --system --uid 1001 --gid 1001 panguard && \
    chown -R panguard:panguard /app /data
USER panguard

ENV NODE_ENV=production
ENV PANGUARD_DATA_DIR=/data

EXPOSE 3000

# No Dockerfile HEALTHCHECK - let Railway manage it after container starts
# tini is PID 1 -> docker-entrypoint.sh -> litestream replicate -exec "node ..."
# On SIGTERM, tini forwards to litestream, which flushes WAL before exiting child.
ENTRYPOINT ["tini", "--", "/docker-entrypoint.sh"]
