#!/bin/sh
# Setup and boot Clawdie-ISO in bhyve VM
# Usage: bhyve-test.sh [ISO_PATH] [--name VM_NAME]
#
# Network isolation: each VM gets its own tap interface on a dedicated
# bhyve0 bridge (10.99.0.0/24), separate from warden0 (jail bridge).
# The script creates bhyve0. PF is not modified by this test harness.

set -eu

VM_NAME="${BHYVE_VM_NAME:-clawdie-test}"
VM_DIR="/var/bhyve/$VM_NAME"
DISK_SIZE="25G"
MEM="2G"
CPUS="2"
ISO_DIR="$(cd "$(dirname "$0")/.." && pwd)"
ISO_OUTPUT_DIR="${ISO_DIR}/tmp/output"

# bhyve network — isolated from warden0 (jail bridge)
BHYVE_BRIDGE="bhyve0"
BHYVE_BRIDGE_IP="10.99.0.1"
BHYVE_NET="10.99.0.0/24"

# Guardrail: bhyve inside a VM is unstable without nested VT-x.
if command -v sysctl >/dev/null 2>&1; then
  VM_GUEST="$(sysctl -n kern.vm_guest 2>/dev/null || true)"
  if [ -n "$VM_GUEST" ] && [ "$VM_GUEST" != "none" ]; then
    echo "ERROR: bhyve test requires bare metal or nested VT-x enabled."
    echo "Detected virtualized host: $VM_GUEST"
    exit 1
  fi
fi

# Parse args
ISO=""
while [ $# -gt 0 ]; do
  case "$1" in
    --name) VM_NAME="$2"; VM_DIR="/var/bhyve/$VM_NAME"; shift 2 ;;
    *)      ISO="$1"; shift ;;
  esac
done

# Auto-detect newest baremetal image if no ISO given
if [ -z "$ISO" ]; then
  if [ -d "$ISO_OUTPUT_DIR" ]; then
    ISO="$(ls -t "${ISO_OUTPUT_DIR}"/clawdie-iso-baremetal-*.img 2>/dev/null | head -1)"
  fi
  if [ -z "$ISO" ]; then
    ISO="$(ls -t "${ISO_DIR}"/clawdie-iso-baremetal-*.img 2>/dev/null | head -1)"
  fi
fi

if [ -z "$ISO" ] || [ ! -f "$ISO" ]; then
  echo "ERROR: No ISO found. Pass path as argument or place a"
  echo "  clawdie-iso-baremetal-*.img in ${ISO_OUTPUT_DIR}/"
  exit 1
fi

ISO="$(realpath "$ISO")"

echo "=== Clawdie-ISO bhyve Test Setup ==="
echo ""

# Cleanup old VM if exists
if bhyvectl --vm="$VM_NAME" --get-stats >/dev/null 2>&1; then
  echo "Destroying old VM: $VM_NAME"
  bhyvectl --vm="$VM_NAME" --destroy 2>/dev/null || true
fi

# Create VM directory
mkdir -p "$VM_DIR"
cd "$VM_DIR"

# Create disk image (sparse — only uses what's written)
if [ ! -f disk.img ]; then
  echo "Creating ${DISK_SIZE} virtual disk (sparse)..."
  truncate -s "$DISK_SIZE" disk.img
else
  echo "Reusing existing disk.img"
fi

# ── Network: dedicated bhyve bridge ────────────────────────────────────────

# Cleanup tap on exit
cleanup() {
  if [ -n "${TAP:-}" ]; then
    ifconfig "$BHYVE_BRIDGE" deletem "$TAP" 2>/dev/null || true
    ifconfig "$TAP" destroy 2>/dev/null || true
  fi
}
trap cleanup EXIT

# Create bhyve0 bridge if it doesn't exist
if ! ifconfig "$BHYVE_BRIDGE" >/dev/null 2>&1; then
  echo "Creating ${BHYVE_BRIDGE} bridge at ${BHYVE_BRIDGE_IP}/24..."
  ifconfig bridge create name "$BHYVE_BRIDGE" >/dev/null
  ifconfig "$BHYVE_BRIDGE" inet "$BHYVE_BRIDGE_IP" netmask 255.255.255.0
  ifconfig "$BHYVE_BRIDGE" up
else
  echo "Bridge ${BHYVE_BRIDGE} already exists"
fi

# Pick a tap interface that isn't already in use
TAP_ID=0
while ifconfig "tap${TAP_ID}" >/dev/null 2>&1; do
  TAP_ID=$((TAP_ID + 1))
done
TAP="tap${TAP_ID}"

echo "Creating ${TAP} interface..."
ifconfig "$TAP" create up

echo "Adding ${TAP} to ${BHYVE_BRIDGE} bridge..."
ifconfig "$BHYVE_BRIDGE" addm "$TAP"

# Locate UEFI bootrom
BOOTROM="/usr/local/share/uefi-firmware/BHYVE_UEFI.fd"
if [ ! -f "$BOOTROM" ]; then
  BOOTROM="/usr/local/share/edk2-bhyve/BHYVE_UEFI.fd"
fi

if [ ! -f "$BOOTROM" ]; then
  echo "ERROR: UEFI bootrom not found"
  exit 1
fi

# Boot parameters
echo ""
echo "Starting VM boot sequence..."
echo "  VM Name: $VM_NAME"
echo "  Disk: $VM_DIR/disk.img ($DISK_SIZE)"
echo "  ISO: $ISO"
echo "  Memory: $MEM"
echo "  CPUs: $CPUS"
echo "  Network: ${TAP} -> ${BHYVE_BRIDGE} (${BHYVE_NET})"
echo ""
echo "  Guest should use:"
echo "    IP:      10.99.0.2/24"
echo "    Gateway: ${BHYVE_BRIDGE_IP}"
echo "    DNS:     1.1.1.1"
echo ""
echo "Booting... (30 min timeout)"
echo ""

# Boot VM from ISO
timeout 1800 bhyve \
  -A -H -P \
  -m "$MEM" \
  -c "$CPUS" \
  -s 0:0,hostbridge \
  -s 1:0,ahci-hd,disk.img \
  -s 2:0,ahci-cd,"$ISO" \
  -s 3:0,virtio-net,"$TAP" \
  -l bootrom,"$BOOTROM" \
  -l com1,stdio \
  "$VM_NAME"

exit_code=$?

# Cleanup tap on exit
echo ""
echo "Boot sequence complete. Cleaning up ${TAP}..."
cleanup
echo "Done."

exit "$exit_code"
