# ─────────────────────────────────────────────────────────────────────────────
# Stage 1 — npm install (Tailwind CLI)
# The .NET SDK stage needs node_modules present before running dotnet publish
# because the MSBuild Tailwind target calls `npx @tailwindcss/cli` during build.
#
# We use the official node:24-slim image here.  This means the npm that ships
# with Node 24 (npm 10.x) is used as-is — we deliberately do NOT run
# `npm install -g npm@latest` anywhere.  Running a global npm self-upgrade
# inside a Debian container is a known reliability hazard: npm replaces its
# own running binaries mid-flight, which can cause EBUSY / ENOENT failures
# that corrupt the install.  The bundled npm is current enough.
# ─────────────────────────────────────────────────────────────────────────────
FROM node:24-slim AS npm-install

WORKDIR /npm
COPY Htmx.ApiDemo/package.json .
# npm ci requires package-lock.json; if it doesn't exist yet, run
# `npm install` locally first to generate it, then commit it to the repo.
COPY Htmx.ApiDemo/package-lock.json* ./
# ci is preferred over install in CI/Docker contexts: respects package-lock,
# clean installs, and is faster.
RUN npm ci

# ─────────────────────────────────────────────────────────────────────────────
# Stage 2 — AOT publish
# Uses the full .NET 10 SDK image.  Node/npx must also be present here so the
# Tailwind MSBuild target can run.  We install Node 24 from NodeSource using
# the official setup script and then immediately install nodejs via apt — no
# subsequent `npm install -g npm` step, for the same reason as above.
# ─────────────────────────────────────────────────────────────────────────────
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS publish

# Install Node.js 24 (required by the Tailwind MSBuild target at publish time).
# We download the NodeSource setup script to a file first so we can inspect it
# if needed, then run it.  Using `| bash -` directly is convenient but hides
# the script from audit — the two-step form is safer in CI/CD contexts.
RUN apt-get update && \
    apt-get install -y --no-install-recommends curl ca-certificates && \
    curl -fsSL https://deb.nodesource.com/setup_24.x -o /tmp/nodesource_setup.sh && \
    bash /tmp/nodesource_setup.sh && \
    apt-get install -y --no-install-recommends nodejs && \
    rm /tmp/nodesource_setup.sh && \
    rm -rf /var/lib/apt/lists/*
# Intentionally no `npm install -g npm` — see Stage 1 note above.

WORKDIR /src

# Copy solution and project files first so NuGet restore is cached separately
COPY Htmx.slnx .
COPY Htmx.ApiDemo/Htmx.ApiDemo.csproj          Htmx.ApiDemo/
COPY Htmx.SourceGenerator/Htmx.SourceGenerator.csproj Htmx.SourceGenerator/

RUN dotnet restore Htmx.ApiDemo/Htmx.ApiDemo.csproj

# Bring in the pre-installed node_modules from Stage 1.
# These were installed with `npm ci` on Node 24 — no npm upgrade was performed.
COPY --from=npm-install /npm/node_modules Htmx.ApiDemo/node_modules

# Copy the rest of the source
COPY . .

# AOT publish — output goes to /publish
RUN dotnet publish Htmx.ApiDemo/Htmx.ApiDemo.csproj \
        -c Release \
        --no-restore \
        -o /publish

# ─────────────────────────────────────────────────────────────────────────────
# Stage 3 — Runtime image
# runtime-deps provides the native library dependencies (libc, libssl, libicu)
# that the AOT binary links against at runtime — no .NET runtime needed.
# ─────────────────────────────────────────────────────────────────────────────
FROM mcr.microsoft.com/dotnet/runtime-deps:10.0 AS runtime

# Run as non-root for security hardening (recommended by Cloud Run docs)
RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser

WORKDIR /app

COPY --from=publish /publish .

# Ensure the binary is executable
RUN chmod +x ./Htmx.ApiDemo

# Cloud Run injects PORT (default 8080).
# ASP.NET Core reads ASPNETCORE_HTTP_PORTS, not PORT directly, so we set it.
# The entrypoint script below maps $PORT → ASPNETCORE_HTTP_PORTS at startup.
COPY GCR/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# Transfer ownership so the app can write temp files if needed
RUN chown -R appuser:appgroup /app

USER appuser

EXPOSE 8080

ENTRYPOINT ["/entrypoint.sh"]
