#!/usr/bin/env bash
## (c) 2025 Tor Houghton <th at bogus.net>
## Clone a Parallels VM
VMS=()
INDEX=1

DO_UPDATES=false
NEW_VM_NAME=""
NEW_HOSTNAME=""

# Parse options
while getopts ":un:h:" opt; do
    case $opt in
        u)
            DO_UPDATES=true
            ;;
        n)
            NEW_VM_NAME="$OPTARG"
            ;;
        h)
            NEW_HOSTNAME="$OPTARG"
            ;;
        \?)
            echo "Usage: $0 [-u] [-n \"Cloned VM Name\"] [-h hostname]"
            echo "  -u: Update VM before cloning"
            echo "  -n: Name for the cloned VM"
            echo "  -h: Hostname for the cloned VM"
            exit 1
            ;;
    esac
done

shift $((OPTIND -1))

while IFS= read -r line; do
    uuid=$(echo "$line" | awk '{print $1}')
    status=$(echo "$line" | awk '{print $2}')
    if [[ "$status" == "stopped" ]]; then
        name=$(echo "$line" | cut -d' ' -f4-)
        VMS+=("$uuid|$name")
        echo "$INDEX) $name ($uuid)"
        INDEX=$((INDEX + 1))
    fi
done < <(prlctl list --all | tail -n +2)

if [ ${#VMS[@]} -eq 0 ]; then
    echo "No powered-off VMs found."
    exit 1
fi

read -p "Enter the number of the VM to work with: " num

if ! [[ "$num" =~ ^[0-9]+$ ]] || [ "$num" -lt 1 ] || [ "$num" -gt "${#VMS[@]}" ]; then
    echo "Invalid selection."
    exit 1
fi

SELECTED="${VMS[$((num-1))]}"
VM_ID="${SELECTED%%|*}"
VM_NAME="${SELECTED#*|}"

if $DO_UPDATES; then
    prlctl start "$VM_ID"
    echo "Waiting for VM to boot..."
    until prlctl exec "$VM_ID" uptime &>/dev/null; do
        sleep 1
    done
    echo "VM is up, running apt update."
    prlctl exec "$VM_ID" 'apt -y update && apt -y upgrade && apt -y autoclean && apt -y autoremove'
    # Shutdown the VM
    prlctl exec "$VM_ID" 'shutdown -h now'
    echo "Waiting for VM $VM_ID to fully shut down..."
    while true; do
        STATE=$(prlctl list --all | awk -v id="$VM_ID" '$1 == id {print $2}')
        if [[ "$STATE" == "stopped" ]]; then
            break
        fi
        sleep 1
    done
    echo "VM is stopped. Proceeding to clone..."
fi

if [[ -z "$NEW_VM_NAME" ]]; then
    exec < /dev/tty
    read -p "Enter a name for the cloned VM: " NEW_VM_NAME
fi

CLONE_OUTPUT=$(prlctl clone "$VM_ID" --name "$NEW_VM_NAME")

echo "Waiting for cloned VM '$NEW_VM_NAME' to register..."
while true; do
    CLONE_LINE=$(prlctl list --all | awk -v name="$NEW_VM_NAME" '$0 ~ name && $2 == "stopped"')
    if [[ -n "$CLONE_LINE" ]]; then
        break
    fi
    sleep 1
done

CLONE_ID=$(echo "$CLONE_LINE" | awk '{print $1}')
CLONE_NAME=$(echo "$CLONE_LINE" | cut -d' ' -f4-)

echo "  $CLONE_ID $CLONE_NAME"

if [[ -z "$NEW_HOSTNAME" ]]; then
    exec < /dev/tty
    read -p "Enter a new hostname for the cloned VM: " NEW_HOSTNAME
fi

prlctl start "$CLONE_ID"

echo "Waiting for clone to boot..."
until prlctl exec "$CLONE_ID" uptime &>/dev/null; do
    sleep 1
done

echo "Clone is up, setting hostname..."
prlctl exec "$CLONE_ID" "echo '$NEW_HOSTNAME' | tee /etc/hostname"
echo "Shutting down clone..."
prlctl exec "$CLONE_ID" 'shutdown -h now'
echo "Done!"
