# syntax=docker/dockerfile:1
# =============================================================================
# BFF (NestJS) Dockerfile
# =============================================================================
# Multi-stage build with BuildKit cache mounts for fast rebuilds
# Optimized for minimal image size, security, and fast startup
# =============================================================================

ARG NODE_VERSION=22
ARG PNPM_VERSION=10.25.0

# =============================================================================
# Stage 1: Dependencies (cached layer)
# =============================================================================
FROM node:${NODE_VERSION}-alpine AS deps

ARG PNPM_VERSION

# Install build dependencies in single layer
RUN apk add --no-cache python3 make g++ openssl libc6-compat \
    && corepack enable \
    && corepack prepare pnpm@${PNPM_VERSION} --activate

WORKDIR /app

# Copy manifests first for dependency caching (all workspace packages)
COPY .npmrc pnpm-workspace.yaml package.json pnpm-lock.yaml ./
COPY packages/domain/package.json ./packages/domain/package.json
COPY apps/bff/package.json ./apps/bff/package.json
COPY apps/portal/package.json ./apps/portal/package.json

# Install only the packages needed for the BFF (domain + bff)
ENV HUSKY=0
RUN --mount=type=cache,id=pnpm-bff,target=/root/.local/share/pnpm/store \
    pnpm install --frozen-lockfile --filter @customer-portal/domain... --filter @customer-portal/bff...

# =============================================================================
# Stage 2: Builder
# =============================================================================
FROM deps AS builder

# Copy source files
COPY tsconfig.json tsconfig.base.json tsconfig.node.json ./
COPY packages/domain/ ./packages/domain/
COPY apps/bff/ ./apps/bff/

# Build: domain → Prisma generate → BFF (single RUN for better layer efficiency)
# Clean tsbuildinfo to force fresh emit; checked-in files can skip output otherwise
RUN rm -f apps/bff/tsconfig*.tsbuildinfo \
    && pnpm --filter @customer-portal/domain build \
    && pnpm --filter @customer-portal/bff exec prisma generate \
    && pnpm --filter @customer-portal/bff build

# Create production deployment bundle with pnpm deploy
RUN pnpm deploy --filter @customer-portal/bff --prod /app/deploy \
    && cp -r apps/bff/dist deploy/dist \
    && cp -r apps/bff/prisma deploy/prisma \
    && cp -r packages/domain/dist deploy/node_modules/@customer-portal/domain/dist

# Regenerate Prisma client in the flattened deploy layout so embedded schema path matches production
WORKDIR /app/deploy
RUN pnpm exec prisma generate --schema=prisma/schema.prisma
WORKDIR /app

# =============================================================================
# Stage 3: Production
# =============================================================================
FROM node:${NODE_VERSION}-alpine AS production

ARG PNPM_VERSION

LABEL org.opencontainers.image.title="Customer Portal BFF" \
      org.opencontainers.image.description="NestJS Backend-for-Frontend API" \
      org.opencontainers.image.vendor="Customer Portal"

# Install runtime dependencies only + security hardening
RUN apk add --no-cache dumb-init libc6-compat netcat-openbsd \
    && corepack enable \
    && corepack prepare pnpm@${PNPM_VERSION} --activate \
    && addgroup --system --gid 1001 nodejs \
    && adduser --system --uid 1001 nestjs \
    # Remove apk cache and unnecessary files
    && rm -rf /var/cache/apk/* /tmp/* /root/.npm

WORKDIR /app

# Set Prisma schema path before copying files
ENV PRISMA_SCHEMA_PATH=/app/prisma/schema.prisma

# Copy deploy bundle with correct ownership in single layer
COPY --from=builder --chown=nestjs:nodejs /app/deploy ./

# Copy entrypoint and setup directories
COPY --chown=nestjs:nodejs apps/bff/scripts/docker-entrypoint.sh ./docker-entrypoint.sh
RUN chmod +x docker-entrypoint.sh \
    && mkdir -p secrets logs \
    && chown nestjs:nodejs secrets logs

# Security: Run as non-root user
USER nestjs

# Expose BFF port
EXPOSE 4000

# Environment configuration
ENV NODE_ENV=production \
    PORT=4000 \
    # Node.js production optimizations
    NODE_OPTIONS="--max-old-space-size=512"

# Health check for container orchestration
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD node -e "fetch('http://localhost:4000/health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))"

ENTRYPOINT ["dumb-init", "--", "./docker-entrypoint.sh"]
CMD ["node", "dist/main.js"]
