#!/usr/bin/env bash
set -euo pipefail

URI="qemu:///system"

IMGROOT="/var/lib/libvirt/images"
BASEDIR="$IMGROOT/base"
LABDIR="$IMGROOT/lab"

TEMPLATE_DOMAIN="debian13-template"
TEMPLATE_BASE="$BASEDIR/debian13-template.qcow2"

usage() {
  cat <<'EOF'
Usage: kvm-lab-create <lab-name> [--base template|<prefix>|<domain>|<filename-in-base>|/abs/path.qcow2] [--start]

Base resolution order:
  1) template -> /var/lib/libvirt/images/base/debian13-template.qcow2
  2) /abs/path.qcow2 -> that file
  3) <filename in /var/lib/libvirt/images/base> -> /var/lib/libvirt/images/base/<filename>
  4) <domain name> -> vda disk path of that domain (virsh domblklist)
  5) <prefix> -> newest /var/lib/libvirt/images/base/<prefix>-base-*.qcow2
EOF
}

die() { echo "ERROR: $*" >&2; exit 1; }

NAME="${1:-}"
shift || true

BASESEL="template"
START="no"

while [[ $# -gt 0 ]]; do
  case "$1" in
    --base)  BASESEL="${2:-}"; shift 2 ;;
    --start) START="yes"; shift ;;
    -h|--help) usage; exit 0 ;;
    *) die "Unknown argument: $1" ;;
  esac
done

[[ -n "$NAME" ]] || { usage; exit 1; }

DISK="${LABDIR}/${NAME}.qcow2"
XML_TMP="$(mktemp "/tmp/${NAME}.xml.XXXXXX")"

defined="no"
cleanup() {
  rm -f "$XML_TMP"
  if [[ "$defined" != "yes" && -e "$DISK" ]]; then
    echo "WARN: Removing orphan disk: $DISK"
    sudo rm -f "$DISK" || true
  fi
}
trap cleanup EXIT

resolve_base() {
  local sel="$1"

  if [[ "$sel" == "template" ]]; then
    echo "$TEMPLATE_BASE"; return 0
  fi

  if [[ "$sel" == /* ]]; then
    echo "$sel"; return 0
  fi

  if [[ -f "$BASEDIR/$sel" ]]; then
    echo "$BASEDIR/$sel"; return 0
  fi

  if virsh -c "$URI" dominfo "$sel" &>/dev/null; then
    local src
    src="$(virsh -c "$URI" domblklist "$sel" --details \
      | awk '$2=="disk" && $3=="vda" {print $4; exit}')"
    [[ -n "$src" ]] || die "Domain '$sel' found but could not resolve vda disk path."
    echo "$src"; return 0
  fi

  local latest
  latest="$(ls -1t "$BASEDIR"/"${sel}"-base-*.qcow2 2>/dev/null | head -n 1 || true)"
  [[ -n "$latest" ]] || die "Invalid --base '$sel' (no matching domain/file/promoted base in $BASEDIR)."
  echo "$latest"
}

# Preconditions
[[ -d "$LABDIR" ]] || die "Lab directory missing: $LABDIR"
[[ -d "$BASEDIR" ]] || die "Base directory missing: $BASEDIR"
if ! virsh -c "$URI" dominfo "$TEMPLATE_DOMAIN" &>/dev/null; then
  die "Template domain not found in $URI: $TEMPLATE_DOMAIN"
fi

BASE="$(resolve_base "$BASESEL")"
echo "Base selection: $BASESEL -> $BASE"

[[ -f "$BASE" ]] || die "Base image not found: $BASE"
sudo test -r "$BASE" || die "Base image not readable (via sudo): $BASE"

[[ ! -e "$DISK" ]] || die "Disk already exists: $DISK"
if virsh -c "$URI" dominfo "$NAME" &>/dev/null; then
  die "Domain already exists: $NAME"
fi

# Create overlay
echo "Creating overlay disk: $DISK"
sudo qemu-img create -f qcow2 -F qcow2 -b "$BASE" "$DISK" >/dev/null
sudo chown libvirt-qemu:libvirt "$DISK"
sudo chmod 0660 "$DISK"

echo "Validating backing file..."
sudo qemu-img info "$DISK" | grep -E "file format:|virtual size:|backing file:" || true

# Clone template XML and adjust
echo "Cloning domain XML from: $TEMPLATE_DOMAIN"
virsh -c "$URI" dumpxml "$TEMPLATE_DOMAIN" > "$XML_TMP"

# Update: name, disk source, network default
# - replace <name>...</name> once
# - replace template disk path with overlay path (global)
# - force network='default'
sed -i \
  -e "s|<name>${TEMPLATE_DOMAIN}</name>|<name>${NAME}</name>|" \
  -e "s|${TEMPLATE_BASE}|${DISK}|g" \
  -e "s|<source network='[^']*'|<source network='default'|g" \
  "$XML_TMP"

# Remove UUID and MAC addresses to avoid collisions
sed -i -E '/<uuid>[^<]*<\/uuid>/d' "$XML_TMP"
sed -i -E "s/<mac address='[^']*'\/>//g" "$XML_TMP"

# Remove filesystem passthrough (if any)
perl -0777 -i -pe 's/<filesystem[\s\S]*?<\/filesystem>\n?//g' "$XML_TMP"

# Validate substitutions happened
grep -q "<name>${NAME}</name>" "$XML_TMP" || die "XML name substitution failed"
grep -qF "$DISK" "$XML_TMP" || die "XML disk substitution failed"

# Define domain
echo "Defining domain: $NAME"
virsh -c "$URI" define "$XML_TMP" >/dev/null
defined="yes"

# Optional start
if [[ "$START" == "yes" ]]; then
  echo "Starting domain: $NAME"
  virsh -c "$URI" start "$NAME" >/dev/null
fi

echo "OK: Lab '$NAME' created (disk: $DISK)."
if [[ "$START" != "yes" ]]; then
  echo "To start: virsh -c $URI start $NAME"
fi

