#!/usr/bin/env bash
# publish-golden-image.sh
#
# Build the banger golden-image bundle, upload it to R2, and patch
# internal/imagecat/catalog.json with the resulting URL + sha256 +
# size. Mirrors publish-kernel.sh for kernelcat.
#
# Usage:
#   scripts/publish-golden-image.sh [--name <n>] [--kernel-ref <k>] \
#     [--distro <d>] [--arch <a>] [--description "..."] \
#     [--size <spec>] [--platform <p>] [--skip-upload]
#
# Environment overrides:
#   RCLONE_REMOTE   rclone remote to upload through (default: banger-images)
#   RCLONE_BUCKET   R2 bucket name                  (default: banger-images)
#   BASE_URL        public URL prefix for the bucket (default: https://images.thaloco.com)

set -euo pipefail

log() { printf '[publish-golden-image] %s\n' "$*" >&2; }
die() { log "$*"; exit 1; }

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
CATALOG_FILE="$REPO_ROOT/internal/imagecat/catalog.json"

RCLONE_REMOTE="${RCLONE_REMOTE:-banger-images}"
RCLONE_BUCKET="${RCLONE_BUCKET:-banger-images}"
BASE_URL="${BASE_URL:-https://images.thaloco.com}"

NAME="debian-bookworm"
KERNEL_REF="generic-6.12"
DISTRO="debian"
ARCH="x86_64"
DESCRIPTION=""
SIZE=""
PLATFORM="linux/amd64"
SKIP_UPLOAD=0

while [[ $# -gt 0 ]]; do
  case "$1" in
    --name) NAME="${2:-}"; shift 2;;
    --kernel-ref) KERNEL_REF="${2:-}"; shift 2;;
    --distro) DISTRO="${2:-}"; shift 2;;
    --arch) ARCH="${2:-}"; shift 2;;
    -d|--description) DESCRIPTION="${2:-}"; shift 2;;
    --size) SIZE="${2:-}"; shift 2;;
    --platform) PLATFORM="${2:-}"; shift 2;;
    --skip-upload) SKIP_UPLOAD=1; shift;;
    -h|--help)
      sed -n '2,/^set -euo/p' "$0" | sed 's/^# \?//' | sed '$d'
      exit 0
      ;;
    *) die "unknown option: $1";;
  esac
done

for tool in jq sha256sum stat; do
  command -v "$tool" >/dev/null 2>&1 || die "missing required tool: $tool"
done
[[ -f "$CATALOG_FILE" ]] || die "catalog file not found: $CATALOG_FILE"
if [[ "$SKIP_UPLOAD" -ne 1 ]]; then
  for tool in rclone curl; do
    command -v "$tool" >/dev/null 2>&1 || die "missing required tool: $tool"
  done
fi

STAGE="$(mktemp -d)"
trap 'rm -rf "$STAGE"' EXIT
# Build to a temp name; the content-addressed final name is chosen
# after sha256 is computed.
BUILD_OUT="$STAGE/build.tar.zst"

log "building bundle via make-golden-bundle.sh"
SIZE_FLAG=()
[[ -n "$SIZE" ]] && SIZE_FLAG=(--size "$SIZE")
"$SCRIPT_DIR/make-golden-bundle.sh" \
  --name "$NAME" \
  --kernel-ref "$KERNEL_REF" \
  --distro "$DISTRO" \
  --arch "$ARCH" \
  --description "$DESCRIPTION" \
  --platform "$PLATFORM" \
  "${SIZE_FLAG[@]}" \
  --out "$BUILD_OUT"

SHA256="$(sha256sum "$BUILD_OUT" | awk '{print $1}')"
SIZE_BYTES="$(stat -c '%s' "$BUILD_OUT")"
HUMAN="$(numfmt --to=iec --suffix=B "$SIZE_BYTES" 2>/dev/null || echo "${SIZE_BYTES}B")"

# Content-addressed filename: every rebuild lives at a unique URL, so
# stale CDN caches can never serve the wrong bytes for the URL the
# catalog points at. First 12 hex chars of sha256 is plenty of
# collision margin for this workload.
SHA_PREFIX="${SHA256:0:12}"
TARBALL_NAME="${NAME}-${ARCH}-${SHA_PREFIX}.tar.zst"
OUT="$STAGE/$TARBALL_NAME"
mv "$BUILD_OUT" "$OUT"

log "bundle ready: $TARBALL_NAME ($HUMAN, sha256 $SHA256)"

if [[ "$SKIP_UPLOAD" -eq 1 ]]; then
  KEEP="$REPO_ROOT/dist/$TARBALL_NAME"
  mkdir -p "$(dirname "$KEEP")"
  cp -f "$OUT" "$KEEP"
  log "--skip-upload set; catalog not patched"
  log "bundle kept at: $KEEP"
  exit 0
fi

log "uploading to $RCLONE_REMOTE:$RCLONE_BUCKET/$TARBALL_NAME"
# --s3-no-check-bucket skips the HeadBucket preflight; --no-check-dest
# skips the HeadObject preflight. Both fail with 403 on R2 tokens that
# only have PutObject + GetObject but not Head* — a common scoped-token
# setup.
rclone copyto \
  --s3-no-check-bucket \
  --no-check-dest \
  "$OUT" "$RCLONE_REMOTE:$RCLONE_BUCKET/$TARBALL_NAME"

URL="$BASE_URL/$TARBALL_NAME"
log "verifying $URL is reachable"
HEAD_STATUS="$(curl -fsSI -o /dev/null -w '%{http_code}' "$URL" || true)"
if [[ "$HEAD_STATUS" != "200" ]]; then
  die "uploaded tarball is not publicly reachable at $URL (HTTP $HEAD_STATUS); check bucket public-access config"
fi

log "patching $CATALOG_FILE"
NEW_ENTRY="$(jq -n \
  --arg name "$NAME" \
  --arg distro "$DISTRO" \
  --arg arch "$ARCH" \
  --arg kref "$KERNEL_REF" \
  --arg url "$URL" \
  --arg sha "$SHA256" \
  --argjson size "$SIZE_BYTES" \
  --arg desc "$DESCRIPTION" \
  '{
    name: $name,
    distro: $distro,
    arch: $arch,
    kernel_ref: $kref,
    tarball_url: $url,
    tarball_sha256: $sha,
    size_bytes: $size,
    description: $desc
  } | with_entries(select(.value != null and .value != ""))')"

CATALOG_TMP="$(mktemp)"
jq --arg name "$NAME" --argjson new "$NEW_ENTRY" '
  .version = (.version // 1)
  | .entries = (((.entries // []) | map(select(.name != $name))) + [$new])
  | .entries |= sort_by(.name)
' "$CATALOG_FILE" > "$CATALOG_TMP"
mv "$CATALOG_TMP" "$CATALOG_FILE"

log "done"
log "next steps:"
log "  git diff -- $CATALOG_FILE"
log "  git add $CATALOG_FILE && git commit -m 'imagecat: publish $NAME'"
log "  make build   # rebuild banger so the new catalog is embedded"
