#!/bin/bash
#
# Pre-build all E2E Docker images and package standard modules as .netapps.
#
# Run once before the test suite. Subsequent test runs use the cached
# images and skip the build phase entirely (~5s vs ~3min per test).
#
# Usage:
#   ./e2e/bin/e2e-build          # build netapps + all images
#   ./e2e/bin/e2e-build --save   # build + save to tarball for colima restarts
#

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
E2E_DIR="$(dirname "$SCRIPT_DIR")"
PKG_DIR="$E2E_DIR"
REPO_ROOT="$(cd "$E2E_DIR/../.." && pwd)"
MODULES_DIR="$REPO_ROOT/modules"
NETAPPS_DIR="$E2E_DIR/netapps"

cd "$E2E_DIR"

GREEN='\033[0;32m'
DIM='\033[2m'
BOLD='\033[1m'
NC='\033[0m'

# ── Step 0: Stage simulated celilo.computer + npm registry contents ───────────
#
# Two shared-infra simulators (celilo-website-sim, npm-registry-sim) need
# build-time inputs that don't live in their docker context by default:
#
#   - celilo-website-sim COPYs the static site into the image. The site is
#     built by `bun run build` in modules/celilo-website/site/. We stage
#     the dist into packages/e2e/.celilo-website-cache/ so the COPY in
#     Dockerfile.celilo-website-sim has a relative path it can use.
#
#   - npm-registry-sim COPYs the @celilo/* tarballs install.sh resolves
#     against. We stage these into packages/e2e/.npm-registry-cache/ via
#     scripts/pack-celilo-packages.ts.
#
# Both staging dirs are .gitignored — they're build outputs, not source.

echo -e "${BOLD}Staging simulator inputs...${NC}"
echo ""

# Build the celilo-website static site and stage its dist/.
WEBSITE_SRC="$REPO_ROOT/modules/celilo-website/site"
WEBSITE_CACHE="$E2E_DIR/.celilo-website-cache"

printf "  %-30s " "celilo-website (build)"
BUILD_START=$(date +%s)
( cd "$WEBSITE_SRC" && bun install > /dev/null 2>&1 && bun run build > /dev/null 2>&1 )
BUILD_END=$(date +%s)
echo -e "${GREEN}✔${NC} ${DIM}$((BUILD_END - BUILD_START))s${NC}"

printf "  %-30s " "celilo-website (stage)"
rm -rf "$WEBSITE_CACHE"
mkdir -p "$WEBSITE_CACHE"
cp -R "$WEBSITE_SRC/dist/." "$WEBSITE_CACHE/"
INSTALL_SH_SIZE=$(wc -c < "$WEBSITE_CACHE/install.sh" 2>/dev/null || echo 0)
echo -e "${GREEN}✔${NC} ${DIM}install.sh ${INSTALL_SH_SIZE}B${NC}"

# Pack the @celilo/* workspace packages install.sh's `bun add -g` needs.
printf "  %-30s " "npm-registry (pack)"
BUILD_START=$(date +%s)
bun run "$E2E_DIR/scripts/pack-celilo-packages.ts" > /dev/null 2>&1
BUILD_END=$(date +%s)
TGZ_COUNT=$(find "$E2E_DIR/.npm-registry-cache" -name '*.tgz' 2>/dev/null | wc -l | tr -d ' ')
echo -e "${GREEN}✔${NC} ${DIM}$((BUILD_END - BUILD_START))s, ${TGZ_COUNT} tarball(s)${NC}"

echo ""

# ── Step 1: Package standard modules as .netapp files ─────────────────────────

STANDARD_MODULES=(namecheap greenwave iptables caddy authentik)

echo -e "${BOLD}Packaging standard modules...${NC}"
echo ""

mkdir -p "$NETAPPS_DIR"

for MODULE in "${STANDARD_MODULES[@]}"; do
  SRC="$MODULES_DIR/$MODULE"
  OUT="$NETAPPS_DIR/$MODULE.netapp"

  if [ ! -d "$SRC" ]; then
    echo -e "  ${DIM}skip${NC}  $MODULE  ${DIM}(not found at $SRC)${NC}"
    continue
  fi

  printf "  %-20s " "$MODULE"
  BUILD_START=$(date +%s)

  # Use the wrapper script if available, else bun directly
  if [ -x "$REPO_ROOT/celilo" ]; then
    "$REPO_ROOT/celilo" package "$SRC" --output "$OUT" > /dev/null 2>&1
  else
    bun run "$REPO_ROOT/apps/celilo/src/cli/index.ts" package "$SRC" --output "$OUT" > /dev/null 2>&1
  fi

  BUILD_END=$(date +%s)
  SIZE=$(du -h "$OUT" 2>/dev/null | cut -f1)
  echo -e "${GREEN}✔${NC} ${DIM}$((BUILD_END - BUILD_START))s  ${SIZE}${NC}"
done

echo ""

# ── Step 2: Build Docker images ───────────────────────────────────────────────

echo -e "${BOLD}Building E2E Docker images...${NC}"
echo ""

DOCKERFILES=(docker/Dockerfile.*)
TOTAL=${#DOCKERFILES[@]}
START=$(date +%s)

for ((i=0; i<TOTAL; i++)); do
  FILE="${DOCKERFILES[$i]}"
  NAME=$(basename "$FILE" | sed 's/Dockerfile\.//')
  TAG="celilo-e2e/${NAME}"

  printf "  [%d/%d] %-25s " "$((i+1))" "$TOTAL" "$NAME"

  BUILD_START=$(date +%s)
  docker build -t "$TAG" -f "$FILE" . > /dev/null 2>&1
  BUILD_END=$(date +%s)
  DURATION=$((BUILD_END - BUILD_START))

  echo -e "${GREEN}✔${NC} ${DIM}${DURATION}s${NC}"
done

END=$(date +%s)
TOTAL_TIME=$((END - START))
echo ""
echo -e "${GREEN}All $TOTAL images built in ${TOTAL_TIME}s${NC}"

# ── Step 2b: Pin the vanilla management tag ───────────────────────────────────
#
# Dockerfile.management produces a vanilla image (bun + unzip + bunfig, no
# celilo). The `cele2e build-infra` bake step in step 2c rewrites
# `celilo-e2e/management:latest` to a post-install.sh image, but the install-sh
# regression test (packages/e2e/tests/install-sh.test.ts) still wants the
# untouched starting point. Aliasing it as `:vanilla` here keeps that
# pre-bake state addressable.
docker tag celilo-e2e/management celilo-e2e/management:vanilla
echo ""

# ── Step 2c: Bake celilo into management:latest via install.sh ────────────────
#
# This is the dogfooding step: the management image every test uses gets
# its celilo CLI from running the published install.sh against the
# simulated celilo.computer + npm registry. If install.sh regresses, this
# step fails build-infra loudly with the script's own output.
echo -e "${BOLD}Baking celilo into management:latest via install.sh...${NC}"
BAKE_START=$(date +%s)
bun run "$E2E_DIR/bin/e2e-bake-management"
BAKE_END=$(date +%s)
echo -e "${GREEN}Baked in $((BAKE_END - BAKE_START))s${NC}"
echo ""

# ── Step 3: Optionally save images to tarball ─────────────────────────────────

if [ "$1" = "--save" ]; then
  echo ""
  echo -e "${BOLD}Saving images to tarball...${NC}"
  TARBALL="$E2E_DIR/.docker-cache/celilo-e2e-images.tar"
  mkdir -p "$(dirname "$TARBALL")"

  IMAGES=$(docker images --filter "reference=celilo-e2e/*" --format "{{.Repository}}:{{.Tag}}" | sort)
  docker save $IMAGES -o "$TARBALL"

  SIZE=$(du -h "$TARBALL" | cut -f1)
  echo -e "${GREEN}Saved to $TARBALL ($SIZE)${NC}"
  echo ""
  echo "To restore after colima restart:"
  echo "  ./e2e/bin/e2e-load"
fi
