#!/bin/bash
#
# tools/build-installer — build the x86_64 stock-OS installer bundle (ADR-0017,
# Session C). The installer/image analogue of a per-board .img.xz: a single
# tarball an operator unpacks on a stock Debian/Ubuntu x86_64 base and runs to
# get a Vendora server.
#
# Produces (per-platform artifact tag — ADR-0017 Decision #7):
#   vendora-sbc_<version>_x86_64_installer.tar.gz   (+ .sha256, + .manifest.txt)
#
# Bundle contents:
#   install-on-stock-os.sh            ← packaging/installer/
#   vendora-sbc_<version>_all.deb      ← built here (or --deb PATH)
#   license.env                        ← baked from .env.image if present (0600)
#   VERSION
#   packaging/                         ← lib + configs + keys + apt sources
#
# Runs on the build host (vendora-build). The .deb is Architecture: all, so no
# device + no cross-compile is needed.
#
# Usage:
#   tools/build-installer [--deb PATH] [--env-image PATH] [--dev]
#
#   --deb PATH         use an existing .deb instead of building one
#   --env-image PATH   license keys to bake (default:
#                      image/armbian-build-config/.env.image if present)
#   --dev              build a DEV-labeled variant — filenames get a `_dev` suffix
#                      (vendora-sbc_<v>_x86_64_dev.run) and the manifest tags it
#                      DEV. The staged install-on-stock-os.sh is force-set to
#                      HARDEN=0 (SSH kept, no random root pw). NOTE (2026-08-13):
#                      the *default* installer now also ships HARDEN=0 while the
#                      system is iterating (ADR-0019 amendment), so `--dev` and
#                      default currently produce functionally-equivalent installs
#                      — the difference is cosmetic (filename + manifest label).
#                      Kept as an explicit "development-labeled" build so the flag
#                      keeps working when we re-tighten prod's default HARDEN=1.
# Output dir override:  INSTALLER_OUTPUT_DIR=<path> tools/build-installer

set -euo pipefail

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
OUTPUT_DIR="${INSTALLER_OUTPUT_DIR:-$HOME/armbian-build/output/installer}"

DEB_PATH=""
ENV_IMAGE="$PROJECT_ROOT/image/armbian-build-config/.env.image"
DEV_MODE=0     # --dev flips to 1 → forces HARDEN=0 + adds _dev label.
               # NOTE: default (DEV_MODE=0) currently ALSO produces HARDEN=0
               # via the source default (ADR-0019 amendment 2026-08-13 — SSH
               # kept while the system iterates). Distinction between the two
               # is currently just filename/label; the flag machinery is here
               # for when prod's HARDEN default gets flipped back to 1.

log() { echo "[vendora-build-installer] $*"; }
die() { echo "[vendora-build-installer] ERROR: $*" >&2; exit 1; }

while [ $# -gt 0 ]; do
    case "$1" in
        --deb)        DEB_PATH="${2:-}"; shift 2 ;;
        --env-image)  ENV_IMAGE="${2:-}"; shift 2 ;;
        --dev)        DEV_MODE=1; shift ;;
        -h|--help)    sed -n '2,30p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
        *) die "unknown option: $1" ;;
    esac
done

# Suffix injected into every artifact name (tarball, .run, inner dir, manifest)
# so a dev bundle can NEVER be confused for production. Prod = no suffix.
SUFFIX=""
[ "$DEV_MODE" = 1 ] && SUFFIX="_dev"

command -v dpkg-deb >/dev/null || die "dpkg-deb not found"
command -v rsync    >/dev/null || die "rsync not found"

# ---------------------------------------------------------------------------
# Version (single source of truth — same as the .deb + image).
# ---------------------------------------------------------------------------
VERSION="$(sed -n 's/^SBC_VERSION[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' \
    "$PROJECT_ROOT/services/common/version.py" | head -1)"
[ -n "$VERSION" ] || die "could not read SBC_VERSION from version.py"
log "version: $VERSION"

# ---------------------------------------------------------------------------
# The .deb — build it (Architecture: all, no device) unless one was passed.
# ---------------------------------------------------------------------------
if [ -z "$DEB_PATH" ]; then
    log "building the .deb via tools/build-deb"
    bash "$SCRIPT_DIR/build-deb"
    OUT="${DEB_OUTPUT_DIR:-$HOME/armbian-build/output/deb}"
    # Native (ADR-0021) builds the amd64 .deb on x86 hosts; fall back to the
    # legacy Architecture: all .deb if the operator ran build-deb --no-native.
    for CAND in "$OUT/vendora-sbc_${VERSION}_amd64.deb" "$OUT/vendora-sbc_${VERSION}_all.deb"; do
        [ -f "$CAND" ] && { DEB_PATH="$CAND"; break; }
    done
fi
[ -f "$DEB_PATH" ] || die "deb not found: $DEB_PATH"
log "using .deb: $DEB_PATH"

# ---------------------------------------------------------------------------
# Stage the bundle.
# ---------------------------------------------------------------------------
STAGING="$(mktemp -d -t vendora-installer-XXXXXX)"
trap 'rm -rf "$STAGING"' EXIT
BUNDLE="$STAGING/vendora-sbc_${VERSION}_x86_64${SUFFIX}_installer"
mkdir -p "$BUNDLE"

log "staging bundle at $BUNDLE"

# Installer script (LF + executable).
sed 's/\r$//' "$PROJECT_ROOT/packaging/installer/install-on-stock-os.sh" \
    > "$BUNDLE/install-on-stock-os.sh"
chmod 0755 "$BUNDLE/install-on-stock-os.sh"

# --dev variant: force HARDEN=0 in the staged install script so the SSH-purge +
# random-root-password blocks (both gated on `[ "$HARDEN" -eq 1 ]`) are skipped.
# Uses the `^HARDEN=[01][[:space:]]` anchor so it works regardless of the source
# default — currently HARDEN=0 (ADR-0019 amendment), historically HARDEN=1. The
# source packaging/installer/install-on-stock-os.sh in the tree is untouched —
# dev-mode behavior only exists inside the staged bundle. Fails loud if the
# anchor moved.
if [ "$DEV_MODE" = 1 ]; then
    if ! grep -q '^HARDEN=[01][[:space:]]' "$BUNDLE/install-on-stock-os.sh"; then
        die "--dev: could not find 'HARDEN=[01]' line in the staged install-on-stock-os.sh — has it been renamed? (refusing to produce a dev bundle that silently ships unknown hardening state)"
    fi
    sed -i 's|^HARDEN=[01][[:space:]].*|HARDEN=0  # DEV BUILD — SSH kept for development access (--dev)|' \
        "$BUNDLE/install-on-stock-os.sh"
    # Sanity-check the flip actually took (grep after sed — this is the safety net).
    grep -q '^HARDEN=0[[:space:]]' "$BUNDLE/install-on-stock-os.sh" \
        || die "--dev: HARDEN sed-flip failed — refusing to ship an unlabeled dev bundle"
    log "  DEV MODE: HARDEN forced to 0 in staged installer (SSH will be KEPT)"
fi

# packaging/ — lib + configs + keys + apt sources (drop debian/ + systemd/:
# the .deb already carries the maintainer scripts + the units). Maintainer/
# shell text stays LF (matches the repo .gitattributes).
rsync -a \
    --exclude='debian' \
    --exclude='systemd' \
    --exclude='installer' \
    --exclude='README.md' \
    "$PROJECT_ROOT/packaging/" "$BUNDLE/packaging/"
# Normalize the shell lib + configs to LF (defensive against a CRLF checkout).
find "$BUNDLE/packaging" -type f \( -name '*.sh' -o -name '*.conf' -o -name '*.sources' \) \
    -exec sed -i 's/\r$//' {} +

# The package.
cp "$DEB_PATH" "$BUNDLE/"

# Version marker.
echo "$VERSION" > "$BUNDLE/VERSION"

# License keys — bake from .env.image (like the image), mode 0600. Optional:
# without it the server installs and reports "awaiting activation".
BAKED_LICENSE="no"
if [ -f "$ENV_IMAGE" ]; then
    api_key="$(sed -n 's/^VENDORA_API_KEY=//p' "$ENV_IMAGE" | head -1 | tr -d '\r')"
    signing_key="$(sed -n 's/^LICENSE_SIGNING_KEY=//p' "$ENV_IMAGE" | head -1 | tr -d '\r')"
    if [ -n "$api_key" ] && [ -n "$signing_key" ]; then
        printf 'VENDORA_API_KEY=%s\nLICENSE_SIGNING_KEY=%s\n' "$api_key" "$signing_key" \
            > "$BUNDLE/license.env"
        chmod 0600 "$BUNDLE/license.env"
        BAKED_LICENSE="yes"
        log "baked license.env (mode 0600) from $ENV_IMAGE"
    else
        log "WARN: $ENV_IMAGE present but keys empty — bundle ships without license.env"
    fi
else
    log "no .env.image — bundle ships without license.env (server will await activation)"
fi

# ---------------------------------------------------------------------------
# Tar it up.
# ---------------------------------------------------------------------------
mkdir -p "$OUTPUT_DIR"
TARBALL="$OUTPUT_DIR/vendora-sbc_${VERSION}_x86_64${SUFFIX}_installer.tar.gz"
log "creating $TARBALL"
tar -C "$STAGING" --owner=root --group=root -czf "$TARBALL" \
    "vendora-sbc_${VERSION}_x86_64${SUFFIX}_installer"

sha="$(sha256sum "$TARBALL" | awk '{print $1}')"
echo "$sha  $(basename "$TARBALL")" > "${TARBALL%.tar.gz}.sha256"
size="$(du -h "$TARBALL" | awk '{print $1}')"

# Self-extracting one-command installer (.run): a tiny stub with the bundle
# tarball base64-appended after a marker. The operator copies ONE file and runs
# ONE command — `sudo bash vendora-sbc_<ver>_x86_64.run [--harden]` — which
# unpacks to a temp dir and execs install-on-stock-os.sh, passing flags through.
RUN="$OUTPUT_DIR/vendora-sbc_${VERSION}_x86_64${SUFFIX}.run"
log "creating self-extracting $RUN"
cat > "$RUN" <<'STUB'
#!/bin/bash
# Vendora SBC — self-extracting x86_64 server installer.
#   sudo bash <this-file> [installer options]
# Unpacks the bundle to a temp dir and runs install-on-stock-os.sh. This release
# ALWAYS disables SSH (purges the server + sets a random root password).
set -euo pipefail
[ "$(id -u)" -eq 0 ] || { echo "run as root:  sudo bash $0 $*" >&2; exit 1; }
_tmp="$(mktemp -d)"; trap 'rm -rf "$_tmp"' EXIT
_start="$(awk '/^__VENDORA_INSTALLER_PAYLOAD__$/ {print NR+1; exit}' "$0")"
[ -n "$_start" ] || { echo "ERROR: payload marker missing" >&2; exit 1; }
tail -n +"$_start" "$0" | base64 -d | tar xz -C "$_tmp"
_dir="$(find "$_tmp" -maxdepth 1 -type d -name 'vendora-sbc_*_installer' | head -1)"
[ -n "$_dir" ] || { echo "ERROR: bundle missing from payload" >&2; exit 1; }
exec bash "$_dir/install-on-stock-os.sh" --bundle-dir "$_dir" "$@"
__VENDORA_INSTALLER_PAYLOAD__
STUB
base64 -w0 "$TARBALL" >> "$RUN"
echo >> "$RUN"
chmod 0755 "$RUN"
run_sha="$(sha256sum "$RUN" | awk '{print $1}')"
echo "$run_sha  $(basename "$RUN")" > "${RUN%.run}.run.sha256"
run_size="$(du -h "$RUN" | awk '{print $1}')"

# Confidential manifest if it carries license keys.
MANIFEST="${TARBALL%.tar.gz}.manifest.txt"
{
    echo "Vendora SBC x86_64 installer manifest"
    if [ "$DEV_MODE" = 1 ]; then
        echo ""
        echo "*** DEV-labeled build ***"
        echo "Filename + this manifest carry a _dev label. Currently equivalent to"
        echo "the default production build (SSH also kept per ADR-0019 amendment"
        echo "2026-08-13). The distinction re-emerges when prod's default HARDEN"
        echo "flag flips back to 1."
        echo ""
    fi
    echo "Built:        $(date -u +%Y-%m-%dT%H:%M:%SZ)"
    echo "Version:      $VERSION"
    echo "Variant:      $( [ "$DEV_MODE" = 1 ] && echo "DEV-labeled (SSH kept, --dev flag)" || echo "PRODUCTION (SSH kept — ADR-0019 amendment 2026-08-13; re-tighten by flipping source HARDEN=1)" )"
    echo "Bundle:       $(basename "$TARBALL")"
    echo "SHA-256:      $sha"
    echo "Self-extract: $(basename "$RUN")"
    echo "  SHA-256:    $run_sha"
    echo "Package:      $(basename "$DEB_PATH")"
    echo "License keys: $BAKED_LICENSE (baked into bundle license.env)"
    if [ "$BAKED_LICENSE" = "yes" ]; then
        echo ""
        echo ">> CONFIDENTIAL: this bundle contains license.env. Treat like the image manifest."
    fi
} > "$MANIFEST"
chmod 600 "$MANIFEST"

log ""
log "DONE."
log "  one-file:  $RUN ($run_size)"
log "  bundle:    $TARBALL ($size)"
log "  manifest:  $MANIFEST"
log ""
if [ "$DEV_MODE" = 1 ]; then
    log "DEV-labeled build (SSH kept — same as current prod default per ADR-0019 amendment)."
    log ""
    log "Install on a stock Debian/Ubuntu x86_64 box:"
    log "  sudo bash $(basename "$RUN")"
    log ""
    log "  (or the unpacked bundle:)"
    log "  tar xzf $(basename "$TARBALL") && cd vendora-sbc_${VERSION}_x86_64${SUFFIX}_installer"
    log "  sudo ./install-on-stock-os.sh"
else
    log "Install on a stock Debian/Ubuntu x86_64 box — SIMPLE (one file, one command):"
    log "  sudo bash $(basename "$RUN")              # SSH is currently KEPT (ADR-0019 amendment 2026-08-13)"
    log ""
    log "  (or the unpacked bundle:)"
    log "  tar xzf $(basename "$TARBALL") && cd vendora-sbc_${VERSION}_x86_64${SUFFIX}_installer"
    log "  sudo ./install-on-stock-os.sh             # SSH is currently KEPT (ADR-0019 amendment 2026-08-13)"
fi
