# Imagem única para os dois processos do módulo: web (Next standalone) e worker.
# Rodar os dois do mesmo artefato garante que web e worker compartilhem
# exatamente o mesmo código e as mesmas dependências em homologação.

# ---------------------------------------------------------------------------
# Base
# ---------------------------------------------------------------------------
FROM node:24-bookworm-slim AS base
ENV NEXT_TELEMETRY_DISABLED=1
WORKDIR /app

# ---------------------------------------------------------------------------
# Dependências de produção. Inclui `tsx`, que o worker e os scripts
# operacionais usam em runtime — por isso `tsx` está em `dependencies`.
# `--ignore-scripts` é seguro aqui: nenhuma dependência de produção depende de
# postinstall, e o binário do esbuild vem do pacote de plataforma.
# ---------------------------------------------------------------------------
FROM base AS deps-prod
COPY package.json package-lock.json ./
RUN npm ci --omit=dev --ignore-scripts && npm cache clean --force

# ---------------------------------------------------------------------------
# Dependências completas e build
# ---------------------------------------------------------------------------
FROM base AS builder
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts
COPY tsconfig.json next.config.ts postcss.config.mjs eslint.config.mjs next-env.d.ts ./
COPY src ./src
COPY migrations ./migrations
COPY scripts ./scripts
# Release do Sentry: o SHA do commit entra no bundle do cliente e no servidor,
# para o stack trace do evento apontar o código certo. Não é segredo.
ARG SENTRY_RELEASE=""
ENV SENTRY_RELEASE=$SENTRY_RELEASE
ENV NEXT_PUBLIC_SENTRY_RELEASE=$SENTRY_RELEASE
# O build não recebe segredo: `collectConfigIssues` é ignorado na fase de build
# e a validação acontece no start do container.
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build

# ---------------------------------------------------------------------------
# Runtime
# ---------------------------------------------------------------------------
FROM base AS runner
ARG SENTRY_RELEASE=""
ENV NODE_ENV=production
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
ENV SENTRY_RELEASE=$SENTRY_RELEASE
ENV ADAPTER_WORKER_HEARTBEAT=/tmp/adaptador-worker-heartbeat

RUN groupadd --system --gid 1001 adaptador \
 && useradd --system --uid 1001 --gid adaptador adaptador

# 1) node_modules de produção primeiro. Traz `tsx` para o worker e os scripts.
COPY --from=deps-prod --chown=adaptador:adaptador /app/node_modules ./node_modules

# 2) Saída autocontida do Next por cima. Onde um pacote existe nas duas árvores,
#    a versão traçada do build é a que vale para o servidor. Conferido: as duas
#    árvores vêm do mesmo lockfile e não divergem em nenhuma versão; a árvore
#    traçada tem 3 pacotes que não ficam no topo da de produção
#    (@emnapi/runtime, isarray, supports-color), e o COPY mescla sem removê-los.
#    O package.json do standalone NÃO é sobrescrito: é o que o server.js espera.
COPY --from=builder --chown=adaptador:adaptador /app/.next/standalone ./
COPY --from=builder --chown=adaptador:adaptador /app/.next/static ./.next/static

# 3) Arquivos lidos em runtime: migrations pelo migrate, src e scripts pelo
#    worker, tsconfig pelos aliases `@/` do tsx.
COPY --chown=adaptador:adaptador migrations ./migrations
COPY --chown=adaptador:adaptador scripts ./scripts
COPY --chown=adaptador:adaptador src ./src
COPY --chown=adaptador:adaptador tsconfig.json ./
COPY --chown=adaptador:adaptador docker ./docker

USER adaptador
EXPOSE 3000

# Liveness não toca dependência externa: distingue processo vivo de dependência
# fora do ar, que é o papel de /api/health/ready. O contêiner do worker troca
# este healthcheck por `worker-health` no compose.
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
  CMD node -e "fetch('http://127.0.0.1:'+(process.env.PORT||3000)+'/api/health/live').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"

ENTRYPOINT ["/app/docker/entrypoint.sh"]
CMD ["web"]
