# Production Dockerfile for apps/web — used for self-hosted deployments.
# Build from the monorepo root so pnpm workspace files are included:
#   docker build -f apps/web/Dockerfile \
#     --build-arg NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co \
#     --build-arg NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ... \
#     -t ghcr.io/<owner>/spanlens-web .
#
# Runtime: node:22-alpine serving Next.js standalone on PORT (default 3000).
# Env vars required at runtime (see apps/web/.env.example):
#   NEXT_PUBLIC_SUPABASE_URL   (also needed as build arg — baked into client bundle)
#   NEXT_PUBLIC_SUPABASE_ANON_KEY  (same)
#   SUPABASE_SERVICE_ROLE_KEY  (server-side only, for middleware workspace resolution)
#   API_URL                    (backend server URL, e.g. http://server:3001)

# ── Stage 1: deps ───────────────────────────────────────────────
FROM node:22-alpine AS deps
WORKDIR /repo

RUN corepack enable && corepack prepare pnpm@10.33.0 --activate

# Copy workspace manifests so pnpm can resolve the workspace graph.
# apps/server and packages/sdk manifests are needed because they are
# declared in pnpm-workspace.yaml. Sprint 7 R-20 (PR #277) added two
# real dependencies that web now consumes:
#   - @spanlens/api-types (runtime helper for the error envelope)
#   - `server` workspace devDep (type-only `import type { AppType }`)
# Both manifests must exist before `pnpm install --filter web` so the
# workspace links resolve. The actual source for both is copied in the
# build stage below.
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/web/package.json ./apps/web/
COPY apps/server/package.json ./apps/server/
COPY packages/sdk/package.json ./packages/sdk/
COPY packages/api-types/package.json ./packages/api-types/

# Sprint 7 R-20 (PR #277) made apps/web do a type-only import from
# `server/src/app`, and that server file itself imports from hono,
# supabase-js, sentry, etc. The tsc invocation inside `next build`
# reads server's source to resolve AppType and therefore needs every
# transitive dep of apps/server installed. `--filter web` and even
# `--filter ...web` (which should include workspace transitive deps)
# both proved insufficient in CI — apps/server/node_modules/hono was
# not populated either way. Drop the filter so every workspace package's
# deps install. Image size is unaffected: the runner stage only copies
# the Next standalone bundle, which already strips anything not
# imported at runtime.
RUN pnpm install --frozen-lockfile

# ── Stage 2: build ──────────────────────────────────────────────
FROM node:22-alpine AS builder
WORKDIR /repo

RUN corepack enable && corepack prepare pnpm@10.33.0 --activate

# NEXT_PUBLIC_* vars are statically inlined into the client bundle at build
# time by Next.js. For the pre-built GHCR image we compile in placeholder
# strings that docker-entrypoint.sh replaces at container startup with the
# real values from env. Pass real values here only when building locally
# (docker compose up --build) — the docker-compose.yml does this already.
ARG NEXT_PUBLIC_SUPABASE_URL=__PLACEHOLDER_SUPABASE_URL__
ARG NEXT_PUBLIC_SUPABASE_ANON_KEY=__PLACEHOLDER_SUPABASE_ANON_KEY__
# API_URL default matches the docker-compose service name "server".
ARG API_URL=http://server:3001

ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL
ENV NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY
ENV API_URL=$API_URL
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production

COPY --from=deps /repo/node_modules ./node_modules
COPY --from=deps /repo/apps/web/node_modules ./apps/web/node_modules
# Sprint 7 R-20 (PR #277): apps/web/lib/api-client.ts does a type-only
# `import type { AppType } from 'server/src/app'`. tsc reading that
# server source needs the hono / @sentry/node / supabase-js etc. type
# packages to resolve from apps/server/node_modules. Same reasoning
# for packages/api-types — its dist/ is the runtime entry and tsc
# walks its own node_modules. Without these COPY lines the build
# fails with "Cannot find module 'hono'" inside server/src/app.ts.
COPY --from=deps /repo/apps/server/node_modules ./apps/server/node_modules
COPY --from=deps /repo/packages/api-types/node_modules ./packages/api-types/node_modules

# Copy workspace manifests (needed for pnpm exec)
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/web ./apps/web
# Sprint 7 R-20 (PR #277): apps/web/lib/api-client.ts does
#   `import type { AppType } from 'server/src/app'`
# so the server source files must exist for tsc to resolve AppType when
# next build runs. The import is type-only, so nothing from apps/server
# runs at runtime and no server JS bytes land in the Next bundle.
COPY apps/server ./apps/server
# packages/api-types is a runtime dependency (isApiErrorEnvelope helper
# is called from apps/web/lib/api-client.ts). Its `dist/` must be
# built before next build runs since the package.json `main`/`types`
# fields point into dist/.
COPY packages/api-types ./packages/api-types
COPY packages/sdk/package.json ./packages/sdk/
COPY tsconfig*.json ./

RUN pnpm --filter @spanlens/api-types build
RUN pnpm --filter web build

# ── Stage 3: runner ─────────────────────────────────────────────
FROM node:22-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Next.js standalone server listens on PORT; HOSTNAME=0.0.0.0 required
# inside Docker so the server accepts connections from outside the container.
ENV PORT=3000
ENV HOSTNAME=0.0.0.0

RUN addgroup -g 1001 -S nodejs && adduser -S nextjs -u 1001 -G nodejs

# Standalone output is a self-contained server with traced node_modules.
# The directory structure mirrors the monorepo layout:
#   .next/standalone/server.js           ← entry point (at repo root level)
#   .next/standalone/apps/web/.next/     ← compiled pages
COPY --from=builder --chown=nextjs:nodejs /repo/apps/web/.next/standalone ./
# Static assets are NOT included in standalone and must be copied separately.
COPY --from=builder --chown=nextjs:nodejs /repo/apps/web/.next/static ./apps/web/.next/static
COPY --from=builder --chown=nextjs:nodejs /repo/apps/web/public ./apps/web/public

# pnpm uses symlinks in node_modules that point to the content-addressed store
# at node_modules/.pnpm. The standalone output copies those symlinks but not
# the store itself. Copy the store so the symlinks resolve correctly at runtime.
# (Only packages reachable via --filter web are present in this store.)
COPY --from=builder --chown=nextjs:nodejs /repo/node_modules/.pnpm /node_modules/.pnpm

COPY --chown=nextjs:nodejs apps/web/docker-entrypoint.sh ./
RUN chmod +x docker-entrypoint.sh

USER nextjs
EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \
  CMD wget --quiet --spider http://localhost:3000/ || exit 1

# docker-entrypoint.sh patches placeholder NEXT_PUBLIC_* strings in the
# compiled bundle with the real values from env, then starts the server.
CMD ["sh", "docker-entrypoint.sh"]
