#!/usr/bin/env bash
# vm-manager.sh — Create, snapshot, restore, and destroy the test VM.
#
# Usage:
#   vm-manager.sh create --iso <path-to-windows.iso>
#   vm-manager.sh snapshot <name>
#   vm-manager.sh restore <name>
#   vm-manager.sh destroy [--keep-logs]
#   vm-manager.sh status

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"

require_vbox
ensure_dirs

# ─── Subcommands ────────────────────────────────────────────

cmd_create() {
  local iso_path=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --iso) iso_path="$2"; shift 2 ;;
      *) log_fail "Unknown flag: $1"; exit 1 ;;
    esac
  done

  if [[ -z "$iso_path" ]]; then
    log_fail "Usage: vm-manager.sh create --iso <path-to-windows.iso>"
    exit 1
  fi

  if [[ ! -f "$iso_path" ]]; then
    log_fail "ISO not found: $iso_path"
    exit 1
  fi

  # Check disk space (~25 GB needed)
  local free_gb
  free_gb=$(df -BG "$(dirname "$VM_DIR")" 2>/dev/null | awk 'NR==2{print $4}' | tr -d 'G' || echo "0")
  if (( free_gb < 25 )); then
    log_warn "Only ${free_gb}GB free. The VM needs ~25GB. Continuing anyway..."
  fi

  if vm_exists; then
    log_warn "VM '$VM_NAME' already exists. Destroying first..."
    cmd_destroy
  fi

  log_step "Creating VM: $VM_NAME"

  # 1. Create and register VM
  "$VBOXMANAGE" createvm \
    --name "$VM_NAME" \
    --ostype Windows11_64 \
    --register \
    --basefolder "$VM_DIR"
  log_info "VM registered"

  # 2. Configure hardware
  "$VBOXMANAGE" modifyvm "$VM_NAME" \
    --memory "$VM_RAM_MB" \
    --cpus "$VM_CPUS" \
    --vram "$VM_VRAM_MB" \
    --nested-hw-virt on \
    --ioapic on \
    --firmware efi \
    --tpm-type 2.0 \
    --secure-boot on \
    --graphicscontroller vboxsvga \
    --audio-driver none \
    --nic1 nat \
    --clipboard-mode bidirectional
  log_info "Hardware configured (${VM_RAM_MB}MB RAM, ${VM_CPUS} CPUs, nested-hw-virt on)"

  # 3. Create and attach disk
  local disk_path="$VM_DIR/$VM_NAME/$VM_NAME.vdi"
  "$VBOXMANAGE" createmedium disk \
    --filename "$disk_path" \
    --size "$VM_DISK_MB" \
    --variant Standard
  log_info "Disk created: ${VM_DISK_MB}MB dynamic VDI"

  "$VBOXMANAGE" storagectl "$VM_NAME" \
    --name "SATA" \
    --add sata \
    --controller IntelAhci \
    --portcount 2

  "$VBOXMANAGE" storageattach "$VM_NAME" \
    --storagectl "SATA" \
    --port 0 --device 0 \
    --type hdd \
    --medium "$disk_path"

  "$VBOXMANAGE" storageattach "$VM_NAME" \
    --storagectl "SATA" \
    --port 1 --device 0 \
    --type dvddrive \
    --medium "$iso_path"
  log_info "Storage attached"

  # 4. Unattended Windows install
  # --post-install-command disables UAC so guestcontrol works without elevation prompts
  log_info "Configuring unattended install..."
  "$VBOXMANAGE" unattended install "$VM_NAME" \
    --iso="$iso_path" \
    --user="$VM_USER" \
    --password="$VM_PASS" \
    --full-user-name="Test User" \
    --install-additions \
    --locale="en_US" \
    --country="US" \
    --time-zone="UTC" \
    --post-install-command="cmd.exe /c \"reg add HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System /v EnableLUA /t REG_DWORD /d 0 /f\""
  log_info "Unattended install configured"

  # 5. Start VM headless
  log_step "Starting VM (headless) for Windows installation"
  "$VBOXMANAGE" startvm "$VM_NAME" --type headless
  log_info "VM started. Windows is installing — this takes 10-20 minutes..."

  # 6. Wait for Guest Additions to respond
  if ! wait_for_guest "$TIMEOUT_INSTALL"; then
    log_fail "Windows installation timed out. Check VirtualBox logs at: $VM_DIR/$VM_NAME/Logs/"
    log_info "You can also start the VM with a GUI to debug: VBoxManage startvm $VM_NAME --type gui"
    exit 1
  fi

  # 7. Wait a bit more for post-install tasks to finish
  log_info "Guest responding. Waiting 30s for post-install tasks..."
  sleep 30

  # 8. Verify guest additions work properly
  log_info "Verifying guest control..."
  local hostname
  hostname=$("$VBOXMANAGE" guestcontrol "$VM_NAME" run \
    --exe "C:\\Windows\\System32\\cmd.exe" \
    --username "$VM_USER" --password "$VM_PASS" \
    --wait-stdout --wait-stderr \
    -- /c "hostname" 2>/dev/null || echo "unknown")
  log_info "Guest hostname: $hostname"

  # 9. Detach install ISO (no longer needed)
  "$VBOXMANAGE" storageattach "$VM_NAME" \
    --storagectl "SATA" \
    --port 1 --device 0 \
    --type dvddrive \
    --medium emptydrive 2>/dev/null || true

  # 10. Take clean snapshot
  log_step "Taking baseline snapshot: $SNAPSHOT_CLEAN"
  "$VBOXMANAGE" snapshot "$VM_NAME" take "$SNAPSHOT_CLEAN" \
    --description "Fresh Windows install with Guest Additions, UAC disabled"
  log_pass "VM created and snapshot '$SNAPSHOT_CLEAN' saved"
  log_info "VM dir: $VM_DIR/$VM_NAME"
}

cmd_snapshot() {
  local name="${1:?Usage: vm-manager.sh snapshot <name>}"

  if ! vm_exists; then
    log_fail "VM '$VM_NAME' does not exist"
    exit 1
  fi

  log_info "Taking snapshot: $name"
  "$VBOXMANAGE" snapshot "$VM_NAME" take "$name" \
    --description "Test harness snapshot at $(timestamp)"
  log_pass "Snapshot '$name' saved"
}

cmd_restore() {
  local name="${1:?Usage: vm-manager.sh restore <name>}"

  if ! vm_exists; then
    log_fail "VM '$VM_NAME' does not exist"
    exit 1
  fi

  # Power off if running
  if vm_running; then
    log_info "Powering off VM..."
    "$VBOXMANAGE" controlvm "$VM_NAME" poweroff 2>/dev/null || true
    sleep 3
  fi

  log_info "Restoring snapshot: $name"
  "$VBOXMANAGE" snapshot "$VM_NAME" restore "$name"
  log_pass "Restored to '$name'"

  # Restart headless
  log_info "Starting VM..."
  "$VBOXMANAGE" startvm "$VM_NAME" --type headless
  wait_for_guest "$TIMEOUT_BOOT"
}

cmd_destroy() {
  local keep_logs=false
  [[ "${1:-}" == "--keep-logs" ]] && keep_logs=true

  if ! vm_exists; then
    log_info "VM '$VM_NAME' does not exist — nothing to destroy"
    return 0
  fi

  # Power off if running
  if vm_running; then
    log_info "Powering off VM..."
    "$VBOXMANAGE" controlvm "$VM_NAME" poweroff 2>/dev/null || true
    sleep 3
  fi

  log_info "Unregistering and deleting VM..."
  "$VBOXMANAGE" unregistervm "$VM_NAME" --delete 2>/dev/null || true

  if ! $keep_logs; then
    rm -rf "$VM_DIR" 2>/dev/null || true
    log_info "Removed $VM_DIR"
  else
    log_info "Logs preserved at $LOG_DIR"
  fi

  log_pass "VM '$VM_NAME' destroyed"
}

cmd_status() {
  echo ""
  if ! vm_exists; then
    log_info "VM '$VM_NAME': does not exist"
    echo ""
    echo "  Create with: vm-manager.sh create --iso <path-to-windows.iso>"
    return 0
  fi

  local state
  state=$("$VBOXMANAGE" showvminfo "$VM_NAME" --machinereadable 2>/dev/null \
    | grep '^VMState=' | cut -d'"' -f2 || echo "unknown")
  log_info "VM '$VM_NAME': $state"

  # List snapshots
  echo ""
  echo "  Snapshots:"
  "$VBOXMANAGE" snapshot "$VM_NAME" list 2>/dev/null | while read -r line; do
    echo "    $line"
  done || echo "    (none)"

  # Disk usage
  echo ""
  local vm_path="$VM_DIR/$VM_NAME"
  if [[ -d "$vm_path" ]]; then
    local size
    size=$(du -sh "$vm_path" 2>/dev/null | awk '{print $1}')
    echo "  Disk usage: $size ($vm_path)"
  fi
  echo ""
}

# ─── Dispatch ──────────────────────────────────────────────

case "${1:-}" in
  create)  shift; cmd_create "$@" ;;
  snapshot) shift; cmd_snapshot "$@" ;;
  restore) shift; cmd_restore "$@" ;;
  destroy) shift; cmd_destroy "$@" ;;
  status)  cmd_status ;;
  *)
    echo "Usage: vm-manager.sh <create|snapshot|restore|destroy|status> [args]"
    echo ""
    echo "  create --iso <path>   Create VM from Windows ISO (unattended)"
    echo "  snapshot <name>       Take a named snapshot"
    echo "  restore <name>        Restore to a named snapshot and start VM"
    echo "  destroy [--keep-logs] Destroy VM and optionally preserve logs"
    echo "  status                Show VM state and snapshots"
    exit 1
    ;;
esac
