#!/bin/bash
#
# Builds the TuneVault self-hosted release zip for the R2 download
# (https://releases.tunevault.app/tunevault-selfhosted-vX.Y.Z.zip).
#
# Uses `git archive` so the artifact contains only committed files — no .env,
# no node_modules, no .git, no .claude worktrees. Dev/CI/cloud-only paths are
# stripped via the `export-ignore` rules in .gitattributes. The archive extracts
# to a top-level `tunevault/` directory (matches the `unzip … && cd tunevault`
# instructions on /download).
#
# Usage:  bash scripts/build-selfhosted-release.sh [version] [git-ref]
#         version defaults to 1.0.0, ref defaults to HEAD.
set -e

VERSION="${1:-1.0.0}"
REF="${2:-HEAD}"
OUT_DIR="dist"
NAME="tunevault-selfhosted-v${VERSION}.zip"

cd "$(git rev-parse --show-toplevel)"
mkdir -p "$OUT_DIR"

echo "Building ${NAME} from ${REF}…"
# `-c core.autocrlf=false` so the archive emits committed blobs verbatim (LF).
# Without it, building on a machine with autocrlf=true (e.g. Windows) would rewrite
# every text file — including .sh and oracle-proxy.py — to CRLF and break them.
git -c core.autocrlf=false archive --format=zip --prefix=tunevault/ -o "${OUT_DIR}/${NAME}" "${REF}"

# ── Ensure shell scripts ship with Unix (LF) line endings ─────────────────────
# `git archive` already emits committed blobs as-is (which are LF), so this is a
# belt-and-suspenders pass against a .sh ever being committed with CRLF. It runs
# only when the needed tools are present and is never fatal — the build still
# produces a valid (LF) zip if normalization is skipped.
ZIP_ABS="$(cd "$OUT_DIR" && pwd)/${NAME}"
if command -v unzip >/dev/null 2>&1 && command -v zip >/dev/null 2>&1; then
  TMP="$(mktemp -d)"
  unzip -q "$ZIP_ABS" -d "$TMP"
  find "$TMP" -name '*.sh' -exec sed -i 's/\r$//' {} +
  # Ensure the entry-point scripts ship executable (git archive already emits the
  # exec bit for mode-100755 blobs; this is belt-and-suspenders if that bit is ever
  # dropped from a commit, so `bash setup.sh` / `./update.sh` never fail on chmod).
  for s in setup.sh update.sh install.sh uninstall.sh; do
    [ -f "$TMP/tunevault/$s" ] && chmod +x "$TMP/tunevault/$s"
  done
  rm -f "$ZIP_ABS"
  ( cd "$TMP" && zip -qr "$ZIP_ABS" . )
  rm -rf "$TMP"
  echo "✓ Normalized .sh line endings to LF + set exec bits (zip/unzip)"
elif python3 -c 'pass' >/dev/null 2>&1; then
  # python3 fallback (gated on actually running, not just command -v — Windows
  # ships a non-functional python3 stub that command -v would falsely match).
  python3 - "$ZIP_ABS" <<'PY'
import sys, zipfile, os
src = sys.argv[1]; tmp = src + '.tmp'
with zipfile.ZipFile(src) as zin, zipfile.ZipFile(tmp, 'w', zipfile.ZIP_DEFLATED) as zout:
    for it in zin.infolist():
        data = zin.read(it.filename)
        if it.filename.endswith('.sh'):
            data = data.replace(b'\r\n', b'\n')
        zout.writestr(it, data)
os.replace(tmp, src)
PY
  echo "✓ Normalized .sh line endings to LF (python3)"
else
  echo "• Skipped .sh LF normalization (no zip+unzip or python3) — git archive already emits LF"
fi

SIZE=$(du -h "${OUT_DIR}/${NAME}" | cut -f1)
COUNT=$(git -c core.autocrlf=false archive --format=tar --prefix=tunevault/ "${REF}" | tar -tf - | grep -vc '/$' || true)

echo "✓ ${OUT_DIR}/${NAME} (${SIZE}, ${COUNT} files)"
echo ""
echo "Upload to R2:"
echo "  aws s3 cp ${OUT_DIR}/${NAME} s3://<bucket>/${NAME} \\"
echo "    --endpoint-url https://<account>.r2.cloudflarestorage.com"
echo "  (or via the Cloudflare dashboard → R2 → releases bucket)"
echo "Served at: https://releases.tunevault.app/${NAME}"
