#!/bin/bash
## parallels command line helper 
## v1.00 (c) 2024 th(at)bogus.net

show_help() {
    cat << EOF
Usage: vmmenu.sh [OPTIONS]

Options:
  -l, --list              Show a list of running VMs.
  -n, --number <digit>    Specify the VM number to manipulate (from the list).
  -c, --cmd [<cmd>]       Command to execute on the specified VM (empty for a root shell).
  -h, --help              Show this help message and exit.

Examples:
  vmmenu.sh -n 1 -c "ls /"      # run a specific command (as root!) on vm no. 1
  vmmenu.sh -n 2 -c             # drop to a root shell on vm no. 2
EOF
}

list_vms() {
    flag="$1"
    if [ -z "$flag" ]; then
        echo "Fetching list of running VMs..."
    fi
    vm_list=$(prlctl list --no-header | grep "running")

    if [[ -z "$vm_list" ]]; then
        echo "No running VMs found."
        exit 1
    fi

    declare -a vm_uuids
    declare -a vm_names
    count=1
    
    while IFS= read -r line; do
        uuid=$(echo "$line" | awk '{print $1}')
        name=$(echo "$line" | awk '{for (i=4; i<=NF; i++) printf $i " "; print ""}' | sed 's/ *$//')
        short_uuid=${uuid:1:6}
        vm_uuids+=("$uuid")
        vm_names+=("$name")
        echo "$count) $name ($short_uuid..)"
        ((count++))
    done <<< "$vm_list"

    if [ -z "$flag" ]; then
        echo "0) Exit"
    fi

    # Export data for later use
    export VM_UUIDS=$(printf "%s\n" "${vm_uuids[@]}")
    export VM_NAMES=$(printf "%s\n" "${vm_names[@]}")
}

execute_vm_command() {
    local vm_number="$1"
    local cmd_to_exec="${2:-bash}"

    # Convert exported arrays back into arrays
    IFS=$'\n' read -r -d '' -a vm_uuids <<< "$VM_UUIDS"
    IFS=$'\n' read -r -d '' -a vm_names <<< "$VM_NAMES"

    # Validate VM number
    if [[ -z "${vm_uuids[$((vm_number-1))]}" ]]; then
        echo "Invalid VM number: $vm_number"
        exit 1
    fi

    local selected_uuid="${vm_uuids[$((vm_number-1))]}"
    local selected_vm="${vm_names[$((vm_number-1))]}"

    if [[ "$cmd_to_exec" == "bash" ]]; then
        echo "Dropping to root shell on '$selected_vm' (^D or exit to return)"
        prlctl exec "$selected_uuid" sh
        exit 0
    fi

    echo "Executing '$cmd_to_exec' on '$selected_vm' (as root)..."
    prlctl exec "$selected_uuid" "$cmd_to_exec"
    exit 0
}

interactive_mode() {
    list_vms
    echo
    while true; do
        read -p "VM to manipulate (1-$(($count - 1)) or 0 to exit): " vm_number
        if [[ "$vm_number" == "0" ]]; then
            echo "Exiting..."
            exit 0
        elif [[ "$vm_number" =~ ^[0-9]+$ && "$vm_number" -ge 1 && "$vm_number" -lt $count ]]; then
            break
        else
            echo "Invalid selection. Please try again."
        fi
    done

    read -p "Command to exec (empty for root shell): " cmd_to_exec
    cmd_to_exec="${cmd_to_exec:-bash}"

    execute_vm_command "$vm_number" "$cmd_to_exec"
}

# Main script logic
if [[ $# -eq 0 ]]; then
    interactive_mode
    exit 0
fi

while [[ $# -gt 0 ]]; do
    case "$1" in
        -l|--list)
            list_vms
            exit 0
            ;;
        -n|--number)
            if [[ -z "$2" || ! "$2" =~ ^[0-9]+$ ]]; then
                echo "Error: Invalid or missing number for --number."
                exit 1
            fi
            vm_number="$2"
            shift
            ;;
        -c|--cmd)
            if [[ -z "$2" || "$2" == -* ]]; then
                cmd_to_exec="bash"
            else
                cmd_to_exec="$2"
                shift
            fi
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        *)
            echo "Error: Unknown option '$1'"
            show_help
            exit 1
            ;;
    esac
    shift
done

if [[ -n "$vm_number" ]]; then
    list_vms "$vm_number"
    execute_vm_command "$vm_number" "$cmd_to_exec"
else
    echo "Error: --number is required to specify a VM."
    show_help
    exit 1
fi
