#!/bin/sh
# vm-up.sh — start the long-lived Mountaineer builder VM.
#
# First run: generates a NoCloud cloud-init seed (hostname, ssh keys,
# build-deps packages, runcmd), boots the cloud qcow2 with the seed
# attached, polls until sshd is reachable. Subsequent runs: boots without
# the seed (cloud-init has already run).
#
# Usage:
#   tools/qemu/vm-up.sh                # idempotent — provision if needed, then start
#   tools/qemu/vm-up.sh --reprovision  # wipe state and re-run cloud-init from scratch
#   tools/qemu/vm-up.sh --stop         # graceful shutdown via qemu monitor
#
# Apple Silicon caveat: x86_64 guests run via TCG. First boot (cloud-init
# installing the build deps) is the slowest part — expect 5-10 minutes.

. "$(dirname "$0")/common.sh"
ensure_dirs

CLOUD_IMG="$IMG_DIR/alpine-cloud.qcow2"
BUILDER_DISK="$DISK_DIR/builder.qcow2"
SEED_ISO="$DISK_DIR/builder-seed.iso"
KEYS_DIR="$VMS/keys"
BUILDER_KEY="$KEYS_DIR/builder_ed25519"
LOGS_DIR="$VMS/logs"
SOCKETS_DIR="$VMS/sockets"
PROVISIONED_MARKER="$VMS/.builder-provisioned"
PIDFILE="$VMS/builder.pid"

mkdir -p "$LOGS_DIR" "$SOCKETS_DIR"

mode=auto
case "${1:-}" in
    --reprovision) mode=reprovision ;;
    --stop)        mode=stop ;;
    "")            mode=auto ;;
    *) echo "unknown flag: $1" >&2; exit 2 ;;
esac

# --- stop --------------------------------------------------------------
if [ "$mode" = stop ]; then
    if [ -S "$SOCKETS_DIR/builder-mon.sock" ]; then
        printf 'system_powerdown\n' | nc -U "$SOCKETS_DIR/builder-mon.sock" >/dev/null 2>&1 || true
        echo "==> sent powerdown; VM will exit gracefully"
    elif [ -f "$PIDFILE" ]; then
        kill "$(cat "$PIDFILE")" 2>/dev/null || true
        echo "==> sent SIGTERM to qemu (no monitor socket found)"
    else
        echo "==> no running builder VM detected"
    fi
    exit 0
fi

# --- preconditions ------------------------------------------------------
if [ ! -f "$CLOUD_IMG" ]; then
    cat >&2 <<EOF
error: cloud image not found at $CLOUD_IMG

Download with:
    curl -fL -o $CLOUD_IMG \\
        $ALPINE_CLOUD_URL
    qemu-img resize $CLOUD_IMG +30G
EOF
    exit 1
fi

if [ ! -f "$BUILDER_KEY" ] || [ ! -f "$BUILDER_KEY.pub" ]; then
    echo "==> generating builder SSH key at $BUILDER_KEY"
    mkdir -p "$KEYS_DIR"
    ssh-keygen -t ed25519 -N '' -C 'mountaineer-builder' -f "$BUILDER_KEY"
fi

# --- reprovision: clear state -------------------------------------------
if [ "$mode" = reprovision ]; then
    echo "==> reprovisioning: wiping builder state"
    rm -f "$BUILDER_DISK" "$SEED_ISO" "$PROVISIONED_MARKER" "$NVRAM_DIR/builder_VARS.fd"
fi

# --- builder disk: copy-on-write from the cloud image -------------------
if [ ! -f "$BUILDER_DISK" ]; then
    echo "==> creating builder disk as overlay on $CLOUD_IMG"
    qemu-img create -f qcow2 -b "$CLOUD_IMG" -F qcow2 "$BUILDER_DISK"
fi

# --- generate cidata seed -----------------------------------------------
need_provision=0
if [ ! -f "$PROVISIONED_MARKER" ]; then
    need_provision=1
fi

if [ "$need_provision" = 1 ]; then
    echo "==> building cloud-init seed.iso"
    pubkey=$(cat "$BUILDER_KEY.pub")
    seed_stage=$(mktemp -d)
    cat > "$seed_stage/meta-data" <<EOF
instance-id: mountaineer-builder-001
local-hostname: mountaineer-builder
EOF
    cat > "$seed_stage/user-data" <<EOF
#cloud-config
hostname: mountaineer-builder
manage_etc_hosts: true

ssh_pwauth: false
disable_root: false

users:
  - name: root
    ssh_authorized_keys:
      - $pubkey
  - name: build
    groups: [abuild, wheel]
    shell: /bin/sh
    sudo: ALL=(ALL) NOPASSWD:ALL
    ssh_authorized_keys:
      - $pubkey

growpart:
  mode: auto
  devices: ['/']

package_update: true
packages:
  - alpine-sdk
  - abuild
  - xorriso
  - squashfs-tools
  - mkinitfs
  - grub-efi
  - mtools
  - dosfstools
  - git
  - tar
  - rsync
  - coreutils

runcmd:
  - [ sh, -c, "su build -c 'abuild-keygen -a -i -n' || true" ]
  - [ sh, -c, "mkdir -p /var/lib/cloud/instance && touch /var/lib/cloud/instance/mountaineer-ready" ]

final_message: "Mountaineer builder ready after \$UPTIME seconds."
EOF

    # macOS: hdiutil makehybrid produces an ISO9660 image with the
    # volume label cloud-init's NoCloud datasource looks for.
    if command -v hdiutil >/dev/null 2>&1; then
        rm -f "$SEED_ISO"
        hdiutil makehybrid -iso -joliet -default-volume-name CIDATA -o "$SEED_ISO" "$seed_stage" >/dev/null
    elif command -v xorriso >/dev/null 2>&1; then
        xorriso -as mkisofs -volid CIDATA -joliet -rock -output "$SEED_ISO" "$seed_stage" >/dev/null 2>&1
    elif command -v genisoimage >/dev/null 2>&1; then
        genisoimage -V CIDATA -J -r -o "$SEED_ISO" "$seed_stage" >/dev/null 2>&1
    else
        echo "error: no ISO builder found (need hdiutil on macOS, or xorriso/genisoimage)" >&2
        rm -rf "$seed_stage"
        exit 1
    fi
    rm -rf "$seed_stage"
fi

# --- boot ---------------------------------------------------------------
serial_log="$LOGS_DIR/builder-serial.log"
monitor_sock="$SOCKETS_DIR/builder-mon.sock"

# Cleanup stale sockets/pidfile.
rm -f "$monitor_sock" "$PIDFILE"

seed_drive=""
if [ "$need_provision" = 1 ]; then
    seed_drive="-drive file=$SEED_ISO,if=virtio,format=raw,readonly=on"
fi

echo "==> booting builder VM (serial log: $serial_log)"
# shellcheck disable=SC2046,SC2086
qemu-system-x86_64 \
    $(qemu_base_args builder) \
    -serial file:"$serial_log" \
    -drive file="$BUILDER_DISK",if=virtio,format=qcow2 \
    $seed_drive \
    -netdev user,id=net0,hostfwd=tcp:127.0.0.1:$BUILDER_SSH_PORT-:22 \
    -device virtio-net-pci,netdev=net0 \
    -monitor unix:"$monitor_sock",server,nowait \
    -daemonize \
    -pidfile "$PIDFILE"

if [ "$need_provision" = 1 ]; then
    echo "==> waiting for cloud-init to finish (this is the slow first boot)"
    echo "    serial log: $serial_log"
    echo "    polling sshd on 127.0.0.1:$BUILDER_SSH_PORT every 10s for up to 15 min"

    deadline=$(( $(date +%s) + 900 ))
    while [ "$(date +%s)" -lt "$deadline" ]; do
        if ssh -p "$BUILDER_SSH_PORT" \
            -o StrictHostKeyChecking=accept-new \
            -o UserKnownHostsFile="$VMS/known_hosts" \
            -o ConnectTimeout=3 \
            -o BatchMode=yes \
            -i "$BUILDER_KEY" \
            root@127.0.0.1 \
            'test -f /var/lib/cloud/instance/mountaineer-ready' 2>/dev/null; then
            echo "==> builder is provisioned and reachable"
            touch "$PROVISIONED_MARKER"
            exit 0
        fi
        sleep 10
        printf '.'
    done

    echo ""
    echo "error: builder did not come up in 15 minutes" >&2
    echo "       check $serial_log for what went wrong" >&2
    exit 1
fi

echo "==> builder is running (qemu pid $(cat "$PIDFILE"))"
echo "    ssh: ssh -i $BUILDER_KEY -p $BUILDER_SSH_PORT root@127.0.0.1"
echo "    stop: $0 --stop"
