# syntax=docker/dockerfile:1

# Define build-time arguments
ARG NODE_VERSION=24
ARG PACKAGE_MANAGER

# Build here and pull down all the devDependencies
FROM node:${NODE_VERSION} AS builder
ARG PACKAGE_MANAGER
ARG NODE_OPTIONS="--max_old_space_size=8192"
# Run pnpm/yarn/npm non-interactively (no TTY in Docker builds).
# Without this, pnpm aborts on prompts like confirmModulesPurge.
ENV CI=true
WORKDIR /app

# Copy dependency-related files first for better layer caching.
# package.json guarantees at least one match; wildcards skip absent files.
COPY package.json yarn.lock* pnpm-lock.yaml* pnpm-workspace.yaml* package-lock.json* .yarnrc.yml* .npmrc* ./

RUN <<EOF
  set -e
  if [ -z "${PACKAGE_MANAGER}" ]; then
    echo "ERROR: PACKAGE_MANAGER build arg is required. Pass --build-arg PACKAGE_MANAGER=yarn|pnpm|npm" >&2
    exit 1
  fi
  case "${PACKAGE_MANAGER}" in
    yarn)
      npm install -g corepack
      corepack enable && corepack prepare
      yarn install
      ;;
    pnpm)
      npm install -g corepack
      corepack enable && corepack prepare
      pnpm install --frozen-lockfile
      ;;
    npm)
      npm ci
      ;;
    *)
      echo "Unsupported package manager: ${PACKAGE_MANAGER}" && exit 1
      ;;
  esac
EOF

# Now copy the rest of the source and build
COPY . .
RUN <<EOF
  set -e
  # Detect any custom build script in package.json
  if node -e "process.exit(require('./package.json').scripts?.build ? 0 : 1)"; then
    BUILD_CMD="build"
  else
    # Default to xy build if no build script is defined
    BUILD_CMD="xy build"
  fi

  case "${PACKAGE_MANAGER}" in
    yarn) yarn ${BUILD_CMD} ;;
    pnpm) pnpm ${BUILD_CMD} ;;
    npm) npm run ${BUILD_CMD} ;;
  esac
EOF

# Just install the production dependencies here
FROM node:${NODE_VERSION} AS dependencies
ARG PACKAGE_MANAGER
ENV CI=true
WORKDIR /app

# Copy only dependency-related files — install layer is cached until these change
COPY package.json yarn.lock* pnpm-lock.yaml* pnpm-workspace.yaml* package-lock.json* .yarnrc.yml* .npmrc* ./

# Install only production dependencies to keep the final image lean.
# devDependencies are excluded — they were only needed in the builder stage.
RUN <<EOF
  set -e
  case "${PACKAGE_MANAGER}" in
    yarn)
      npm install -g corepack
      corepack enable && corepack prepare
      yarn workspaces focus --production
      ;;
    pnpm)
      npm install -g corepack
      corepack enable && corepack prepare
      pnpm install --prod --frozen-lockfile
      ;;
    npm)
      npm ci --omit=dev
      ;;
    *)
      echo "Unsupported package manager: ${PACKAGE_MANAGER}" && exit 1
      ;;
  esac
EOF

# Copy over the compiled output & production dependencies
# into puppeteer container
FROM node:${NODE_VERSION} AS server
WORKDIR /app
ENV PORT="80"
ENV SDK_META_SERVER_DIR="./node_modules/@xylabs/meta-server"
# Tell Puppeteer to skip installing Chrome. We'll be using the installed package.
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium

# Start the meta-server pointed to the static app
CMD ["node", "/app/node_modules/@xylabs/meta-server/dist/node/bin/start-meta.mjs"]

# Install Chromium and required fonts/libraries for Puppeteer
# https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#running-on-alpine
RUN apt-get update && apt-get install -y --no-install-recommends \
  ca-certificates \
  chromium \
  fonts-freefont-ttf \
  fonts-ipafont-gothic \
  fonts-kacst \
  fonts-thai-tlwg \
  fonts-wqy-zenhei \
  libfreetype6 \
  libharfbuzz0b \
  libnss3 \
  libxss1 \
  && rm -rf /var/lib/apt/lists/*

# Copy only what the runtime needs — no source code, lock files, PM config, or credentials
COPY --from=dependencies /app/node_modules ./node_modules
COPY --from=dependencies /app/package.json ./package.json

# Use Node to read in the package.json and determine the Node output dist dir
RUN SDK_META_SERVER_DIST_DIR_RELATIVE=$(node -p "path.dirname(require('${SDK_META_SERVER_DIR}/package').exports['.'].default)") \
  && SDK_META_SERVER_DIST_DIR=$(node -p "path.join('${SDK_META_SERVER_DIR}', '${SDK_META_SERVER_DIST_DIR_RELATIVE}')") \
  # create the expected destination directory
  && mkdir -p ${SDK_META_SERVER_DIST_DIR_RELATIVE} \
  # Copy over the node build files
  && cp -r ${SDK_META_SERVER_DIST_DIR}/. ${SDK_META_SERVER_DIST_DIR_RELATIVE}/

# Copy over the compiled static app
ARG BUILD_OUTPUT_DIR=build
COPY --from=builder /app/${BUILD_OUTPUT_DIR} ./bin/build

WORKDIR /app/bin
