#!/bin/bash

# ==========================================================
# ProxMenux - A menu-driven script for Proxmox VE management
# ==========================================================
# Author      : MacRimi
# Copyright   : (c) 2024 MacRimi
# License     : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE)
# Version     : 1.1
# Last Updated: 29/05/2025
# ==========================================================
# Description:
# This script automates the process of importing disk images into Proxmox VE virtual machines (VMs), 
# making it easy to attach pre-existing disk files without manual configuration.
#
# Before running the script, ensure that disk images are available in /var/lib/vz/template/images/. 
# The script scans this directory for compatible formats (.img, .qcow2, .vmdk, .raw) and lists the available files.
#
# Using an interactive menu, you can:
# - Select a VM to attach the imported disk.
# - Choose one or multiple disk images for import.
# - Pick a storage volume in Proxmox for disk placement.
# - Assign a suitable interface (SATA, SCSI, VirtIO, or IDE).
# - Enable optional settings like SSD emulation or bootable disk configuration.
#
# Once completed, the script ensures the selected images are correctly attached and ready to use.
# ==========================================================

# Configuration ============================================
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
VENV_PATH="/opt/googletrans-env"

[[ -f "$UTILS_FILE" ]] && source "$UTILS_FILE"
load_language
initialize_cache
# Configuration ============================================



detect_image_dir() {
  for store in $(pvesm status -content images | awk 'NR>1 {print $1}'); do
    path=$(pvesm path "${store}:template" 2>/dev/null)
    if [[ -d "$path" ]]; then
      for ext in raw img qcow2 vmdk; do
        if compgen -G "$path/*.$ext" > /dev/null; then
          echo "$path"
          return 0
        fi
      done
      for sub in images iso; do
        dir="$path/$sub"
        if [[ -d "$dir" ]]; then
          for ext in raw img qcow2 vmdk; do
            if compgen -G "$dir/*.$ext" > /dev/null; then
              echo "$dir"
              return 0
            fi
          done
        fi
      done
    fi
  done
  for fallback in /var/lib/vz/template/images /var/lib/vz/template/iso; do
    if [[ -d "$fallback" ]]; then
      for ext in raw img qcow2 vmdk; do
        if compgen -G "$fallback/*.$ext" > /dev/null; then
          echo "$fallback"
          return 0
        fi
      done
    fi
  done
  return 1
}


IMAGES_DIR=$(detect_image_dir)
if [[ -z "$IMAGES_DIR" ]]; then
  dialog --title "$(translate 'No Images Found')" \
         --msgbox "$(translate 'Could not find any directory containing disk images')\n\n$(translate 'Make sure there is at least one file with extension .img, .qcow2, .vmdk or .raw')" 15 60
  exit 1
fi

IMAGES=$(ls -A "$IMAGES_DIR" | grep -E "\.(img|qcow2|vmdk|raw)$")
if [ -z "$IMAGES" ]; then
  dialog --title "$(translate 'No Disk Images Found')" \
         --msgbox "$(translate 'No compatible disk images found in:')\n\n$IMAGES_DIR\n\n$(translate 'Supported formats: .img, .qcow2, .vmdk, .raw')" 15 60
  exit 1
fi


# 1. Select VM
msg_info "$(translate 'Getting VM list')"
VM_LIST=$(qm list | awk 'NR>1 {print $1" "$2}')
if [ -z "$VM_LIST" ]; then
    msg_error "$(translate 'No VMs available in the system')"
    exit 1
fi
msg_ok "$(translate 'VM list obtained')"

VMID=$(whiptail --title "$(translate 'Select VM')" --menu "$(translate 'Select the VM where you want to import the disk image:')" 15 60 8 $VM_LIST 3>&1 1>&2 2>&3)

if [ -z "$VMID" ]; then
   
    exit 1
fi



# 2. Select storage volume
msg_info "$(translate 'Getting storage volumes')"
STORAGE_LIST=$(pvesm status -content images | awk 'NR>1 {print $1}')
if [ -z "$STORAGE_LIST" ]; then
    msg_error "$(translate 'No storage volumes available')"
    exit 1
fi
msg_ok "$(translate 'Storage volumes obtained')"


STORAGE_OPTIONS=()
while read -r storage; do
    STORAGE_OPTIONS+=("$storage" "")
done <<< "$STORAGE_LIST"

STORAGE=$(whiptail --title "$(translate 'Select Storage')" --menu "$(translate 'Select the storage volume for disk import:')" 15 60 8 "${STORAGE_OPTIONS[@]}" 3>&1 1>&2 2>&3)

if [ -z "$STORAGE" ]; then
    
    exit 1
fi



# 3. Select disk images
msg_info "$(translate 'Scanning disk images')"
if [ -z "$IMAGES" ]; then
    msg_warn "$(translate 'No compatible disk images found in') $IMAGES_DIR"
    exit 0
fi
msg_ok "$(translate 'Disk images found')"

IMAGE_OPTIONS=()
while read -r img; do
    IMAGE_OPTIONS+=("$img" "" "OFF")
done <<< "$IMAGES"

SELECTED_IMAGES=$(whiptail --title "$(translate 'Select Disk Images')" --checklist "$(translate 'Select the disk images to import:')" 20 60 10 "${IMAGE_OPTIONS[@]}" 3>&1 1>&2 2>&3)

if [ -z "$SELECTED_IMAGES" ]; then
   
    exit 1
fi



# 4. Import each selected image
for IMAGE in $SELECTED_IMAGES; do


    IMAGE=$(echo "$IMAGE" | tr -d '"')


    INTERFACE=$(whiptail --title "$(translate 'Interface Type')" --menu "$(translate 'Select the interface type for the image:') $IMAGE" 15 40 4 \
    "sata" "SATA" \
    "scsi" "SCSI" \
    "virtio" "VirtIO" \
    "ide" "IDE" 3>&1 1>&2 2>&3)

    if [ -z "$INTERFACE" ]; then
        msg_error "$(translate 'No interface type selected for') $IMAGE"
        continue
    fi

    FULL_PATH="$IMAGES_DIR/$IMAGE"


    msg_info "$(translate 'Importing image:')"


    TEMP_DISK_FILE=$(mktemp)


    qm importdisk "$VMID" "$FULL_PATH" "$STORAGE" 2>&1 | while read -r line; do
        if [[ "$line" =~ transferred ]]; then

            PERCENT=$(echo "$line" | grep -oP "\d+\.\d+(?=%)")
 
            echo -ne "\r${TAB}${BL}-$(translate 'Importing image:') $IMAGE-${CL} ${PERCENT}%"
        elif [[ "$line" =~ successfully\ imported\ disk ]]; then

            echo "$line" | grep -oP "(?<=successfully imported disk ').*(?=')" > "$TEMP_DISK_FILE"
        fi
    done
    echo -ne "\n" 

    IMPORT_STATUS=${PIPESTATUS[0]} 

    if [ $IMPORT_STATUS -eq 0 ]; then
        msg_ok "$(translate 'Image imported successfully')"


        IMPORTED_DISK=$(cat "$TEMP_DISK_FILE")
        rm -f "$TEMP_DISK_FILE" 

   
        if [ -z "$IMPORTED_DISK" ]; then
   
            STORAGE_TYPE=$(pvesm status -storage "$STORAGE" | awk 'NR>1 {print $2}')

            if [[ "$STORAGE_TYPE" == "btrfs" || "$STORAGE_TYPE" == "dir" || "$STORAGE_TYPE" == "nfs" ]]; then
   
                UNUSED_LINE=$(qm config "$VMID" | grep -E '^unused[0-9]+:')
                IMPORTED_ID=$(echo "$UNUSED_LINE" | cut -d: -f1)
                IMPORTED_DISK=$(echo "$UNUSED_LINE" | cut -d: -f2- | xargs)
            else
   
                IMPORTED_DISK=$(qm config "$VMID" | grep -E 'unused[0-9]+' | tail -1 | cut -d: -f2- | xargs)
                IMPORTED_ID=$(qm config "$VMID" | grep -E 'unused[0-9]+' | tail -1 | cut -d: -f1)
            fi
        fi

        if [ -n "$IMPORTED_DISK" ]; then
       
            EXISTING_DISKS=$(qm config "$VMID" | grep -oP "${INTERFACE}\d+" | sort -n)
            if [ -z "$EXISTING_DISKS" ]; then
                NEXT_SLOT=0
            else
                LAST_SLOT=$(echo "$EXISTING_DISKS" | tail -n1 | sed "s/${INTERFACE}//")
                NEXT_SLOT=$((LAST_SLOT + 1))
            fi

   
            if [ "$INTERFACE" != "virtio" ]; then
                if (whiptail --title "$(translate 'SSD Emulation')" --yesno "$(translate 'Do you want to use SSD emulation for this disk?')" 10 60); then
                    SSD_OPTION=",ssd=1"
                else
                    SSD_OPTION=""
                fi
            else
                SSD_OPTION=""
            fi

            msg_info "$(translate 'Configuring disk')"

 
            if qm set "$VMID" --${INTERFACE}${NEXT_SLOT} "$IMPORTED_DISK${SSD_OPTION}" &>/dev/null; then
                msg_ok "$(translate 'Image') $IMAGE $(translate 'configured as') ${INTERFACE}${NEXT_SLOT}"

   
                if [[ -n "$IMPORTED_ID" ]]; then
                    qm set "$VMID" -delete "$IMPORTED_ID" >/dev/null 2>&1
                fi

  
                if (whiptail --title "$(translate 'Make Bootable')" --yesno "$(translate 'Do you want to make this disk bootable?')" 10 60); then
                    msg_info "$(translate 'Configuring disk as bootable')"

                    if qm set "$VMID" --boot c --bootdisk ${INTERFACE}${NEXT_SLOT} &>/dev/null; then
                        msg_ok "$(translate 'Disk configured as bootable')"
                    else
                        msg_error "$(translate 'Could not configure the disk as bootable')"
                    fi
                fi
            else
                msg_error "$(translate 'Could not configure disk') ${INTERFACE}${NEXT_SLOT} $(translate 'for VM') $VMID"
                echo "DEBUG: Tried to configure: --${INTERFACE}${NEXT_SLOT} \"$IMPORTED_DISK${SSD_OPTION}\""
                echo "DEBUG: VM config after import:"
                qm config "$VMID" | grep -E "(unused|${INTERFACE})"
            fi
        else
            msg_error "$(translate 'Could not find the imported disk')"
            echo "DEBUG: VM config after import:"
            qm config "$VMID"
        fi
    else
        msg_error "$(translate 'Could not import') $IMAGE"
    fi
done



msg_ok "$(translate 'All selected images have been processed')"
msg_success "$(translate "Press Enter to return to menu...")"
read -r
