# syntax=docker/dockerfile:1.7
#
# Image Docker pour le frontend DigitalKin Hub (React + Vite SPA).
# Bundle Magicbox — copié de l'image production Vercel.
#
# Stratégie : multi-stage
#   1. deps    : install pnpm + dépendances (cache friendly)
#   2. build   : tsc -b && vite build → dist/
#   3. runtime : nginx non-privilégié qui sert /dist en statique
#
# Les variables VITE_* sont inlinées dans le bundle au build time.
# Magicbox les passe via `docker build --build-arg VITE_API_URL=...` depuis
# le bloc managed de `<profile>/env/horizon.env` (cf. cli/compose.py
# `generate_horizon_compose`).
# Pour les variables runtime (changer sans rebuild) il faut une autre approche
# (script entrypoint qui réécrit le bundle ou injecte /env-config.js) —
# pas le cas ici puisqu'on reste sur le même modèle que Vercel.

# ─────────────────────────────────────────────────────────────
# Stage 1 — deps : install des dépendances via pnpm
# ─────────────────────────────────────────────────────────────
FROM node:24-alpine AS deps

ENV PNPM_HOME=/pnpm
ENV PATH="$PNPM_HOME:$PATH"
# Skip husky : .git n'est pas dans le contexte, et le hook prepare lancerait husky
ENV HUSKY=0
# Pin pnpm à la branche 10 (cohérent avec le format pnpm.onlyBuiltDependencies
# du package.json — pnpm 11 ne le lit plus). À supprimer si tu migres tout en
# ajoutant `"packageManager": "pnpm@10.x.x"` dans package.json.
RUN corepack enable && corepack prepare pnpm@10 --activate

WORKDIR /app

# Copy uniquement les manifestes pour maximiser le cache de cette étape.
# .npmrc est crucial : il déclare `public-hoist-pattern[]=rxjs` (et autres) pour
# que les deps transitives utilisées en direct soient hoistées au top-level.
COPY package.json pnpm-lock.yaml .npmrc ./

# pnpm 10+ erreure sur les builds ignorés (postinstall scripts non-approuvés via
# onlyBuiltDependencies). On désactive ce strict mode pour le build Docker —
# les builds critiques (esbuild, oxide, sentry-cli…) sont déjà approuvés dans
# package.json `pnpm.onlyBuiltDependencies`, les autres deviennent juste des warnings.
ENV npm_config_strict_dep_builds=false

# Mount cache du store pnpm pour accélérer les rebuilds (BuildKit)
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
    pnpm config set strict-dep-builds false && \
    pnpm install --frozen-lockfile

# ─────────────────────────────────────────────────────────────
# Stage 2 — build : compile l'app (tsc + vite build)
# ─────────────────────────────────────────────────────────────
FROM node:24-alpine AS build

ENV PNPM_HOME=/pnpm
ENV PATH="$PNPM_HOME:$PATH"
ENV HUSKY=0
# Plus de heap pour Vite/tsc sur les gros bundles
ENV NODE_OPTIONS=--max-old-space-size=4096
# Même version de pnpm qu'au stage deps
RUN corepack enable && corepack prepare pnpm@10 --activate

WORKDIR /app

# ── Variables VITE_* (inlinées dans le bundle au build) ──
# Toutes optionnelles : si non passées, Vite mettra `undefined` côté code.
ARG VITE_API_URL
ARG VITE_CLERK_PUBLISHABLE_KEY
ARG VITE_POSTHOG_HOST
ARG VITE_POSTHOG_KEY
ARG VITE_SENTRY_DSN
ARG VITE_INCIDENT_IO_WIDGET_URL
ARG VITE_VERCEL_ENV=production
ARG VITE_REACT_QUERY_DEVTOOLS=false
ARG VITE_SCAN=false
ARG VITE_LOG_I=false
# ── Upload sourcemaps Sentry (optionnel) ──
ARG SENTRY_ORG
ARG SENTRY_PROJECT
ARG SENTRY_AUTH_TOKEN

ENV VITE_API_URL=$VITE_API_URL \
    VITE_CLERK_PUBLISHABLE_KEY=$VITE_CLERK_PUBLISHABLE_KEY \
    VITE_POSTHOG_HOST=$VITE_POSTHOG_HOST \
    VITE_POSTHOG_KEY=$VITE_POSTHOG_KEY \
    VITE_SENTRY_DSN=$VITE_SENTRY_DSN \
    VITE_INCIDENT_IO_WIDGET_URL=$VITE_INCIDENT_IO_WIDGET_URL \
    VITE_VERCEL_ENV=$VITE_VERCEL_ENV \
    VITE_REACT_QUERY_DEVTOOLS=$VITE_REACT_QUERY_DEVTOOLS \
    VITE_SCAN=$VITE_SCAN \
    VITE_LOG_I=$VITE_LOG_I \
    SENTRY_ORG=$SENTRY_ORG \
    SENTRY_PROJECT=$SENTRY_PROJECT \
    SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN

# Récup les node_modules du stage deps (pas de réinstall)
COPY --from=deps /app/node_modules ./node_modules
# Puis le code applicatif
COPY . .

RUN pnpm run build

# ─────────────────────────────────────────────────────────────
# Stage 3 — runtime : nginx non-privilégié qui sert le statique
# ─────────────────────────────────────────────────────────────
# nginx-unprivileged tourne déjà en uid 101 (nginx) sur port 8080,
# sans bidouille de permissions/PID — le bon défaut pour Kubernetes.
FROM nginxinc/nginx-unprivileged:1.27-alpine AS runtime

# Installer dumb-init + curl (healthcheck) → besoin root le temps du apk add
USER root
RUN apk add --no-cache dumb-init curl
USER nginx

# Conf nginx custom Magicbox (reproduit vercel.json : SPA fallback, sécurité,
# proxy PostHog). Le fichier est apporté par le contexte nommé `magicbox-bundle`
# (cf. `additional_contexts` du compose override généré par `dk prepare`) — il
# vit à `services/horizon/Dockerfile/nginx.conf` côté Magicbox et reste
# indépendant du clone Horizon (qui peut, ou non, en avoir un à la racine).
COPY --from=magicbox-bundle --chown=nginx:nginx nginx.conf /etc/nginx/conf.d/default.conf

# Bundle statique
COPY --from=build --chown=nginx:nginx /app/dist /usr/share/nginx/html

EXPOSE 8080

# Healthcheck Docker (Kubernetes utilisera plutôt liveness/readiness probes sur /healthz)
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD curl -fsS http://127.0.0.1:8080/healthz || exit 1

# dumb-init = PID 1 propre (forward signaux, reap zombies)
ENTRYPOINT ["dumb-init", "--"]
CMD ["nginx", "-g", "daemon off;"]
