#!/bin/bash
# ==========================================================
# ProxMenux - A menu-driven script for Proxmox VE management
# ==========================================================
# Author      : MacRimi
# Copyright   : (c) 2024 MacRimi
# License     : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
# Version     : 1.3
# Last Updated: 07/04/2026
# ==========================================================
# Description:
# This script allows users to assign physical disks to existing
# Proxmox containers (CTs) through an interactive menu.
# - Detects the system disk and excludes it from selection.
# - Lists all available CTs for the user to choose from.
# - Identifies and displays unassigned physical disks.
# - Allows the user to select multiple disks and attach them to a CT.
# - Configures the selected disks for the CT and verifies the assignment.
# - Uses persistent device paths to avoid issues with device order changes.
# ==========================================================

# Configuration ============================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOCAL_SCRIPTS_LOCAL="$(cd "$SCRIPT_DIR/.." && pwd)"
LOCAL_SCRIPTS_DEFAULT="/usr/local/share/proxmenux/scripts"
LOCAL_SCRIPTS="$LOCAL_SCRIPTS_DEFAULT"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$LOCAL_SCRIPTS/utils.sh"

if [[ -f "$LOCAL_SCRIPTS_LOCAL/utils.sh" ]]; then
    LOCAL_SCRIPTS="$LOCAL_SCRIPTS_LOCAL"
    UTILS_FILE="$LOCAL_SCRIPTS/utils.sh"
elif [[ ! -f "$UTILS_FILE" ]]; then
    UTILS_FILE="$BASE_DIR/utils.sh"
fi

# shellcheck source=/dev/null
if [[ -f "$UTILS_FILE" ]]; then
    source "$UTILS_FILE"
fi

# shellcheck source=/dev/null
if [[ -f "$LOCAL_SCRIPTS_LOCAL/global/vm_storage_helpers.sh" ]]; then
    source "$LOCAL_SCRIPTS_LOCAL/global/vm_storage_helpers.sh"
elif [[ -f "$LOCAL_SCRIPTS_DEFAULT/global/vm_storage_helpers.sh" ]]; then
    source "$LOCAL_SCRIPTS_DEFAULT/global/vm_storage_helpers.sh"
fi

BACKTITLE="ProxMenux"
UI_MENU_H=20
UI_MENU_W=84
UI_MENU_LIST_H=10
UI_SHORT_MENU_H=16
UI_SHORT_MENU_W=72
UI_SHORT_MENU_LIST_H=6
UI_MSG_H=10
UI_MSG_W=72
UI_YESNO_H=18
UI_YESNO_W=86
UI_RESULT_H=18
UI_RESULT_W=86

load_language
initialize_cache

if ! command -v pveversion >/dev/null 2>&1; then
    dialog --backtitle "$BACKTITLE" --title "$(translate "Error")" \
        --msgbox "$(translate "This script must be run on a Proxmox host.")" 8 60
    exit 1
fi

# ==========================================================

# Returns the most stable /dev/disk/by-id symlink for a device.
# Prefers ata-/scsi-/nvme- > wwn- > other by-id > by-path > raw path.
get_preferred_disk_path() {
    local disk="$1"
    local real_path
    real_path=$(readlink -f "$disk" 2>/dev/null)
    [[ -z "$real_path" ]] && { echo "$disk"; return 0; }

    local best="" best_score=99999
    local link name score
    for link in /dev/disk/by-id/*; do
        [[ -e "$link" ]] || continue
        [[ "$(readlink -f "$link" 2>/dev/null)" == "$real_path" ]] || continue
        name=$(basename "$link")
        [[ "$name" == *-part* ]] && continue

        case "$name" in
            ata-*|scsi-*|nvme-*) score=100 ;;
            wwn-*)                score=200 ;;
            *)                    score=300 ;;
        esac
        score=$((score + ${#name}))
        if (( score < best_score )); then
            best="$link"
            best_score=$score
        fi
    done

    if [[ -n "$best" ]]; then
        echo "$best"
        return 0
    fi

    for link in /dev/disk/by-path/*; do
        [[ -e "$link" ]] || continue
        [[ "$(readlink -f "$link" 2>/dev/null)" == "$real_path" ]] || continue
        echo "$link"
        return 0
    done

    msg_warn "$(translate "No persistent path found for") $disk — $(translate "using direct path (not guaranteed to survive reboots).")"
    echo "$disk"
}

install_fs_tools_in_ct() {
    local ctid="$1"
    local pkg="$2"

    if pct exec "$ctid" -- sh -c "[ -f /etc/alpine-release ]"; then
        pct exec "$ctid" -- sh -c "apk update >/dev/null 2>&1 && apk add --no-progress $pkg >/dev/null 2>&1"
    elif pct exec "$ctid" -- sh -c "grep -qi 'arch' /etc/os-release 2>/dev/null"; then
        pct exec "$ctid" -- sh -c "pacman -Sy --noconfirm $pkg >/dev/null 2>&1"
    elif pct exec "$ctid" -- sh -c "grep -qiE 'debian|ubuntu' /etc/os-release 2>/dev/null"; then
        pct exec "$ctid" -- sh -c "apt-get update -qq >/dev/null 2>&1 && apt-get install -y -qq $pkg >/dev/null 2>&1"
    else
        return 1
    fi
}

get_disk_info() {
    local disk=$1
    local model size
    model=$(lsblk -dn -o MODEL "$disk" | xargs)
    size=$(lsblk -dn -o SIZE "$disk" | xargs)
    [[ -z "$model" ]] && model="Unknown"
    printf '%s\t%s\n' "$model" "$size"
}

# Suggest an unused mount point inside the CT for the given disk.
# Reads the CT config to collect already-used mp= paths, then returns
# the first free candidate: /mnt/disk_<devname>, /mnt/disk_<devname>_2, ...
_get_suggested_mount_point() {
    local ctid="$1"
    local disk="$2"
    local devname
    devname=$(basename "$disk")
    local base="/mnt/disk_${devname}"

    local used_mps
    used_mps=$(pct config "$ctid" 2>/dev/null | grep '^mp[0-9]*:' | \
               grep -oP 'mp=\K[^,]+' | sort)

    if ! grep -qxF "$base" <<< "$used_mps"; then
        echo "$base"; return
    fi
    local n=2
    while grep -qxF "${base}_${n}" <<< "$used_mps"; do
        ((n++))
    done
    echo "${base}_${n}"
}

get_all_disk_paths() {
    local disk="$1"
    local real_path
    real_path=$(readlink -f "$disk" 2>/dev/null)

    [[ -n "$disk" ]] && echo "$disk"
    [[ -n "$real_path" ]] && echo "$real_path"

    local link
    for link in /dev/disk/by-id/* /dev/disk/by-path/*; do
        [[ -e "$link" ]] || continue
        [[ "$(readlink -f "$link" 2>/dev/null)" == "$real_path" ]] || continue
        echo "$link"
    done | sort -u
}

disk_referenced_in_config() {
    local config_text="$1"
    local disk="$2"
    local alias
    while read -r alias; do
        [[ -z "$alias" ]] && continue
        if grep -Fq "$alias" <<< "$config_text"; then
            return 0
        fi
    done < <(get_all_disk_paths "$disk")
    return 1
}



CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
if [ -z "$CT_LIST" ]; then
    dialog --backtitle "$BACKTITLE" \
           --title "$(translate "Error")" \
           --msgbox "$(translate "No CTs available in the system.")" $UI_MSG_H $UI_MSG_W
    exit 1
fi

# shellcheck disable=SC2086  # CT_LIST is intentionally word-split into dialog menu pairs
CTID=$(dialog --backtitle "$BACKTITLE" \
              --title "$(translate "Select CT for destination disk")" \
              --menu "$(translate "Select the CT to which you want to add disks:")" $UI_MENU_H $UI_MENU_W $UI_MENU_LIST_H \
              $CT_LIST \
              2>&1 >/dev/tty)

if [ -z "$CTID" ]; then
    dialog --backtitle "$BACKTITLE" \
           --title "$(translate "Error")" \
           --msgbox "$(translate "No CT was selected.")" $UI_MSG_H $UI_MSG_W
    exit 1
fi

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

CT_STATUS=$(pct status "$CTID" | awk '{print $2}')
CT_RUNNING=false
[[ "$CT_STATUS" == "running" ]] && CT_RUNNING=true

# ── Check for unprivileged container — also a dialog, stays before show_proxmenux_logo ──
CONF_FILE="/etc/pve/lxc/$CTID.conf"
CONVERT_PRIVILEGED=false
if grep -q '^unprivileged: 1' "$CONF_FILE"; then
    if dialog --backtitle "$BACKTITLE" \
        --title "$(translate "Privileged Container")" \
        --yesno "\n\n$(translate "The selected container is unprivileged. A privileged container is required for direct device passthrough.")\\n\\n$(translate "Do you want to convert it to a privileged container now?")" $UI_YESNO_H $UI_YESNO_W; then
        CONVERT_PRIVILEGED=true
    else
        dialog --backtitle "$BACKTITLE" \
               --title "$(translate "Aborted")" \
               --msgbox "$(translate "Operation cancelled. Cannot continue with an unprivileged container.")" $UI_MSG_H $UI_MSG_W
        exit 1
    fi
fi

# ── TERMINAL PHASE 1 ──────────────────────────────────────────────────────────
show_proxmenux_logo
msg_title "$(translate "Import Disk to LXC")"
msg_ok "$(translate "CT $CTID selected successfully.")"

if [ "$CONVERT_PRIVILEGED" = true ]; then

    show_proxmenux_logo
    msg_title "$(translate "Import Disk to LXC")"

    CURRENT_CT_STATUS=$(pct status "$CTID" | awk '{print $2}')
    if [ "$CURRENT_CT_STATUS" == "running" ]; then
        msg_info "$(translate "Stopping container") $CTID..."
        pct shutdown "$CTID" &>/dev/null
        for i in {1..10}; do
            sleep 1
            [ "$(pct status "$CTID" | awk '{print $2}')" != "running" ] && break
        done
        if [ "$(pct status "$CTID" | awk '{print $2}')" == "running" ]; then
            msg_error "$(translate "Failed to stop the container.")"
            exit 1
        fi
        msg_ok "$(translate "Container stopped.")"
    fi

    cp "$CONF_FILE" "$CONF_FILE.bak"
    sed -i '/^unprivileged: 1/d' "$CONF_FILE"
    echo "unprivileged: 0" >> "$CONF_FILE"
    msg_ok "$(translate "Container successfully converted to privileged.")"

    if [ "$CT_RUNNING" = true ]; then
        msg_info "$(translate "Starting container") $CTID..."
        pct start "$CTID" &>/dev/null
        sleep 2
        if [ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]; then
            msg_error "$(translate "Failed to start the container.")"
            CT_RUNNING=false
        else
            msg_ok "$(translate "Container started successfully.")"
        fi
    fi
fi

##########################################
msg_info "$(translate "Detecting available disks...")"

_refresh_host_storage_cache
# Read this CT's current config for the "already assigned to this CT" check
CT_CONFIG=$(pct config "$CTID" 2>/dev/null | grep -vE '^\s*#|^description:')

FREE_DISKS=()

while read -r DISK; do
    [[ "$DISK" =~ /dev/zd ]] && continue

    IFS=$'\t' read -r MODEL SIZE < <(get_disk_info "$DISK")
    LABEL=""
    SHOW_DISK=true
    IS_MOUNTED=false
    IS_RAID=false
    IS_ZFS=false
    IS_LVM=false
    
    while read -r part fstype; do
        [[ "$fstype" == "zfs_member" ]] && IS_ZFS=true
        [[ "$fstype" == "linux_raid_member" ]] && IS_RAID=true
        [[ "$fstype" == "LVM2_member" ]] && IS_LVM=true
        if grep -q "/dev/$part" <<< "$MOUNTED_DISKS"; then
            IS_MOUNTED=true
        fi
    done < <(lsblk -ln -o NAME,FSTYPE "$DISK" | tail -n +2)
    
    REAL_PATH=$(readlink -f "$DISK")
    if echo "$LVM_DEVICES" | grep -qFx "$REAL_PATH"; then
        IS_MOUNTED=true
    fi
    
    USED_BY=""
    if _disk_used_in_guest_configs "$DISK"; then
        USED_BY="⚠ $(translate "In use")"
    fi

    if $IS_RAID && grep -q "$DISK" <<< "$(cat /proc/mdstat)"; then
        if grep -q "active raid" /proc/mdstat; then
            SHOW_DISK=false
        fi
    fi

    if $IS_ZFS; then
        SHOW_DISK=false
    fi

    # Catch whole-disk ZFS vdevs with no partitions (e.g. bare NVMe ZFS)
    # The tail -n +2 trick misses them; ZFS_DISKS from _refresh_host_storage_cache covers them.
    if [[ -n "$ZFS_DISKS" ]] && \
       { grep -qFx "$DISK" <<< "$ZFS_DISKS" || \
         { [[ -n "$REAL_PATH" ]] && grep -qFx "$REAL_PATH" <<< "$ZFS_DISKS"; }; }; then
        SHOW_DISK=false
    fi

    if $IS_MOUNTED; then
        SHOW_DISK=false
    fi

    if disk_referenced_in_config "$CT_CONFIG" "$DISK"; then
        SHOW_DISK=false
    fi
    
    if $SHOW_DISK; then
        [[ -n "$USED_BY" ]] && LABEL+=" [$USED_BY]"
        [[ "$IS_RAID" == true ]] && LABEL+=" ⚠ RAID"
        [[ "$IS_LVM" == true ]] && LABEL+=" ⚠ LVM"
        [[ "$IS_ZFS" == true ]] && LABEL+=" ⚠ ZFS"
        
        DESCRIPTION=$(printf "%-30s %10s%s" "$MODEL" "$SIZE" "$LABEL")
        FREE_DISKS+=("$DISK" "$DESCRIPTION" "OFF")
    fi
done < <(lsblk -dn -e 7,11 -o PATH)

if [ "${#FREE_DISKS[@]}" -eq 0 ]; then
    stop_spinner
    dialog --backtitle "$BACKTITLE" \
           --title "$(translate "Error")" \
           --msgbox "$(translate "No disks available for this CT.")" $UI_MSG_H $UI_MSG_W
    exit 1
fi

stop_spinner

######################################################
MAX_WIDTH=$(printf "%s\n" "${FREE_DISKS[@]}" | awk '{print length}' | sort -nr | head -n1)
TOTAL_WIDTH=$((MAX_WIDTH + 20))
if [ $TOTAL_WIDTH -lt $UI_MENU_W ]; then
    TOTAL_WIDTH=$UI_MENU_W
fi
if [ $TOTAL_WIDTH -gt 116 ]; then
    TOTAL_WIDTH=116
fi

SELECTED=$(dialog --backtitle "$BACKTITLE" \
    --title "$(translate "Select Disks")" \
    --checklist "$(translate "Select the disks you want to add:")" $UI_MENU_H $TOTAL_WIDTH $UI_MENU_LIST_H \
    "${FREE_DISKS[@]}" \
    2>&1 >/dev/tty)

if [ -z "$SELECTED" ]; then
    dialog --backtitle "$BACKTITLE" \
           --title "$(translate "Error")" \
           --msgbox "$(translate "No disks were selected.")" $UI_MSG_H $UI_MSG_W
    exit 1
fi

show_proxmenux_logo
msg_title "$(translate "Import Disk to LXC")"

msg_ok "$(translate "CT $CTID selected successfully.")"
msg_info "$(translate "Analyzing selected disks...")"



# ── DIALOG PHASE: collect config for each disk ────────────────────────────────
declare -a DISK_LIST=()
declare -a DISK_DESCRIPTIONS=()
declare -a DISK_MOUNT_POINTS=()
declare -a DISK_SKIP_FORMATS=()
declare -a DISK_FORMAT_TYPES=()
declare -a DISK_NEEDS_PARTITION=()
declare -a DISK_PARTITIONS=()
declare -a DISK_ASSIGNED_TOS=()
declare -a DISK_CURRENT_FSes=()

for DISK in $SELECTED; do
    DISK="${DISK//\"/}"
    DISK_INFO=$(get_disk_info "$DISK")

    ASSIGNED_TO=""
    RUNNING_CTS=""
    RUNNING_VMS=""

    while read -r CT_ID CT_NAME; do
        CT_CONFIG_RAW=$(pct config "$CT_ID" 2>/dev/null)
        if [[ "$CT_ID" =~ ^[0-9]+$ ]] && disk_referenced_in_config "$CT_CONFIG_RAW" "$DISK"; then
            ASSIGNED_TO+="CT $CT_ID $CT_NAME\n"
            CT_STATUS=$(pct status "$CT_ID" | awk '{print $2}')
            [[ "$CT_STATUS" == "running" ]] && RUNNING_CTS+="CT $CT_ID $CT_NAME\n"
        fi
    done < <(pct list | awk 'NR>1 {print $1, $3}')

    while read -r VM_ID VM_NAME; do
        VM_CONFIG_RAW=$(qm config "$VM_ID" 2>/dev/null)
        if [[ "$VM_ID" =~ ^[0-9]+$ ]] && disk_referenced_in_config "$VM_CONFIG_RAW" "$DISK"; then
            ASSIGNED_TO+="VM $VM_ID $VM_NAME\n"
            VM_STATUS=$(qm status "$VM_ID" | awk '{print $2}')
            [[ "$VM_STATUS" == "running" ]] && RUNNING_VMS+="VM $VM_ID $VM_NAME\n"
        fi
    done < <(qm list | awk 'NR>1 {print $1, $2}')


    stop_spinner
    if [ -n "$RUNNING_CTS" ] || [ -n "$RUNNING_VMS" ]; then
        dialog --backtitle "$BACKTITLE" \
               --title "$(translate "Disk In Use")" \
               --msgbox "$(translate "The disk") $DISK_INFO $(translate "is in use by the following running VM(s) or CT(s):")\\n$RUNNING_CTS$RUNNING_VMS\\n\\n$(translate "Stop them first and run this script again.")" $UI_RESULT_H $UI_RESULT_W
        continue
    fi

    if [ -n "$ASSIGNED_TO" ]; then
        if ! dialog --backtitle "$BACKTITLE" \
               --title "$(translate "Disk Already Assigned")" \
               --yesno "\n\n$(translate "The disk") $DISK_INFO $(translate "is already assigned to the following VM(s) or CT(s):")\\n$ASSIGNED_TO\\n\\n$(translate "Do you want to continue anyway?")" $UI_YESNO_H $UI_YESNO_W; then
            continue
        fi
    fi

    if lsblk "$DISK" | grep -q "raid" || grep -q "${DISK##*/}" /proc/mdstat; then
        dialog --backtitle "$BACKTITLE" \
               --title "$(translate "RAID Detected")" \
               --msgbox "\n$(translate "The disk") $DISK_INFO $(translate "appears to be part of a") RAID. $(translate "For security reasons, the system cannot format it.")\\n\\n$(translate "If you are sure you want to use it, please remove the") RAID metadata $(translate "or format it manually using external tools.")\\n\\n$(translate "After that, run this script again to add it.")" $UI_RESULT_H $UI_RESULT_W
        continue
    fi

    # 1. Detect current partition/FS state
    PARTITION=$(lsblk -rno NAME "$DISK" | awk -v disk="$(basename "$DISK")" '$1 != disk {print $1; exit}')
    SKIP_FORMAT=false
    NEEDS_PARTITION=false

    if [ -n "$PARTITION" ]; then
        PARTITION="/dev/$PARTITION"
        CURRENT_FS=$(lsblk -no FSTYPE "$PARTITION" | xargs)
    else
        CURRENT_FS=$(lsblk -no FSTYPE "$DISK" | xargs)
        PARTITION="$DISK"
    fi

    # 2. Ask what to do with this disk
    if [ -n "$CURRENT_FS" ]; then
        # Disk already has a filesystem — offer use-as-is or reformat
        DISK_ACTION=$(dialog --backtitle "$BACKTITLE" \
            --title "$(translate "Disk Setup")" \
            --menu "$(translate "Disk") $DISK_INFO\n$(translate "Detected filesystem:") $CURRENT_FS\n\n$(translate "What do you want to do?")" \
            $UI_SHORT_MENU_H $UI_SHORT_MENU_W $UI_SHORT_MENU_LIST_H \
            "use"    "$(translate "Use as-is — keep data and filesystem")" \
            "format" "$(translate "Format — erase and create new filesystem")" \
            2>&1 >/dev/tty)
        [ -z "$DISK_ACTION" ] && continue
    else
        DISK_ACTION="format"
    fi

    FORMAT_TYPE=""
    if [ "$DISK_ACTION" = "use" ]; then
        SKIP_FORMAT=true
        FORMAT_TYPE="$CURRENT_FS"
        # PARTITION already set correctly by the detection block above — do not modify
    else
        # 3. Ask desired filesystem for format
        FORMAT_TYPE=$(dialog --backtitle "$BACKTITLE" \
            --title "$(translate "Select Filesystem")" \
            --menu "$(translate "Select the filesystem for") $DISK_INFO:" \
            $UI_SHORT_MENU_H $UI_SHORT_MENU_W $UI_SHORT_MENU_LIST_H \
            "ext4"  "$(translate "ext4  — recommended, most compatible")" \
            "xfs"   "$(translate "xfs   — better for large files")" \
            "btrfs" "$(translate "btrfs — snapshots and compression")" \
            2>&1 >/dev/tty)
        [ -z "$FORMAT_TYPE" ] && continue

        # Check if already the right FS — otherwise need partition + format
        if [ "$CURRENT_FS" = "$FORMAT_TYPE" ]; then
            SKIP_FORMAT=true
        elif [ -z "$CURRENT_FS" ] && [ "$PARTITION" = "$DISK" ]; then
            NEEDS_PARTITION=true
            PARTITION=""
        fi

        # 4. Warn if data will be erased
        if [ "$SKIP_FORMAT" != true ]; then
            if ! dialog --backtitle "$BACKTITLE" \
                   --title "$(translate "WARNING")" \
                   --yesno "\n$(translate "WARNING: This will FORMAT the disk") $DISK_INFO $(translate "as") $FORMAT_TYPE.\\n\\n$(translate "ALL DATA ON THIS DISK WILL BE PERMANENTLY LOST!")\\n\\n$(translate "Are you sure?")" \
                   $UI_YESNO_H $UI_YESNO_W; then
                continue
            fi
        fi
    fi

    # 5. Ask mount point — suggest unique path based on device name
    SUGGESTED_MP=$(_get_suggested_mount_point "$CTID" "$DISK")
    MOUNT_POINT=$(dialog --backtitle "$BACKTITLE" \
                         --title "$(translate "Mount Point")" \
                         --inputbox "$(translate "Enter the mount point inside the CT for") $DISK_INFO:" \
                         $UI_MSG_H $UI_MSG_W "$SUGGESTED_MP" \
                         2>&1 >/dev/tty)

    if [ -z "$MOUNT_POINT" ]; then
        dialog --backtitle "$BACKTITLE" \
               --title "$(translate "Error")" \
               --msgbox "$(translate "No mount point was specified.")" $UI_MSG_H $UI_MSG_W
        continue
    fi

    DISK_LIST+=("$DISK")
    DISK_DESCRIPTIONS+=("$DISK_INFO")
    DISK_MOUNT_POINTS+=("$MOUNT_POINT")
    DISK_SKIP_FORMATS+=("$SKIP_FORMAT")
    DISK_FORMAT_TYPES+=("$FORMAT_TYPE")
    DISK_NEEDS_PARTITION+=("$NEEDS_PARTITION")
    DISK_PARTITIONS+=("$PARTITION")
    DISK_ASSIGNED_TOS+=("$ASSIGNED_TO")
    DISK_CURRENT_FSes+=("$CURRENT_FS")
done

if [ "${#DISK_LIST[@]}" -eq 0 ]; then
    show_proxmenux_logo
    msg_title "$(translate "Import Disk to LXC")"
    msg_warn "$(translate "No disks were configured for processing.")"
    echo ""
    msg_success "$(translate "Press Enter to return to menu...")"
    read -r
    exit 0
fi

# ── TERMINAL PHASE: execute all disk operations ───────────────────────────────
show_proxmenux_logo
msg_title "$(translate "Import Disk to LXC")"
msg_ok "$(translate "CT $CTID selected successfully.")"
msg_ok "$(translate "Disks to process:") ${#DISK_LIST[@]}"
for i in "${!DISK_LIST[@]}"; do
    IFS=$'\t' read -r _desc_model _desc_size <<< "${DISK_DESCRIPTIONS[$i]}"
    echo -e "${TAB}${BL}${DISK_LIST[$i]}  $_desc_model  $_desc_size${CL}"
done
echo ""

DISKS_ADDED=0

for i in "${!DISK_LIST[@]}"; do
    DISK="${DISK_LIST[$i]}"
    MOUNT_POINT="${DISK_MOUNT_POINTS[$i]}"
    SKIP_FORMAT="${DISK_SKIP_FORMATS[$i]}"
    FORMAT_TYPE="${DISK_FORMAT_TYPES[$i]}"
    NEEDS_PARTITION="${DISK_NEEDS_PARTITION[$i]}"
    PARTITION="${DISK_PARTITIONS[$i]}"
    ASSIGNED_TO="${DISK_ASSIGNED_TOS[$i]}"
    CURRENT_FS="${DISK_CURRENT_FSes[$i]}"
    DISK_INFO=$(get_disk_info "$DISK")

    echo ""
    msg_ok "$(translate "Disk:") $DISK → $MOUNT_POINT"

    if [ "$NEEDS_PARTITION" = true ]; then
        msg_info "$(translate "Creating partition table and partition...")"
        if ! parted -s "$DISK" mklabel gpt mkpart primary 0% 100% >/dev/null 2>&1; then
            msg_error "$(translate "Failed to create partition table on disk") $DISK_INFO."
            continue
        fi
        sleep 2
        partprobe "$DISK" 2>/dev/null || true
        udevadm settle 2>/dev/null || true
        # Wait up to 5 s for by-id symlinks to be created by udev
        for _i in {1..5}; do
            for _p in /dev/disk/by-id/*; do
                [[ "$(readlink -f "$_p" 2>/dev/null)" == "$DISK"* ]] && break 2
            done
            sleep 1
        done
        PARTITION=$(lsblk -rno NAME "$DISK" | awk -v disk="$(basename "$DISK")" '$1 != disk {print $1; exit}')
        if [ -n "$PARTITION" ]; then
            PARTITION="/dev/$PARTITION"
            msg_ok "$(translate "Partition created:") $PARTITION"
        else
            msg_error "$(translate "Failed to detect partition on disk") $DISK_INFO."
            continue
        fi
    fi

    if [ "$SKIP_FORMAT" != true ]; then
        msg_info "$(translate "Formatting partition") $PARTITION $(translate "with") $FORMAT_TYPE..."
        if ! case "$FORMAT_TYPE" in
            "ext4")  mkfs.ext4 -F "$PARTITION" >/dev/null 2>&1 ;;
            "xfs")   mkfs.xfs -f "$PARTITION"  >/dev/null 2>&1 ;;
            "btrfs") mkfs.btrfs -f "$PARTITION" >/dev/null 2>&1 ;;
        esac; then
            msg_error "$(translate "Failed to format partition") $PARTITION $(translate "with") $FORMAT_TYPE."
            continue
        fi
        msg_ok "$(translate "Partition") $PARTITION $(translate "successfully formatted with") $FORMAT_TYPE."
        partprobe "$DISK" >/dev/null 2>&1 || true
        sleep 2
    else
        msg_ok "$(translate "Disk already has") $FORMAT_TYPE $(translate "filesystem. Skipping format.")"
    fi

    INDEX=0
    while pct config "$CTID" | grep -q "mp${INDEX}:"; do
        ((INDEX++))
    done

    FS_PKG=""
    FS_BIN=""
    [[ "$FORMAT_TYPE" == "xfs" ]]   && FS_PKG="xfsprogs"   && FS_BIN="xfs_repair"
    [[ "$FORMAT_TYPE" == "btrfs" ]] && FS_PKG="btrfs-progs" && FS_BIN="btrfsck"

    if [[ -n "$FS_PKG" && -n "$FS_BIN" ]]; then
        if [ "$CT_RUNNING" = true ]; then
            if ! pct exec "$CTID" -- sh -c "command -v $FS_BIN >/dev/null 2>&1"; then
                msg_info "$(translate "Installing required tools for $FORMAT_TYPE in CT $CTID...")"
                if install_fs_tools_in_ct "$CTID" "$FS_PKG"; then
                    msg_ok "$(translate "Required tools for $FORMAT_TYPE installed in CT $CTID.")"
                else
                    msg_warn "$(translate "Could not install") $FS_PKG $(translate "automatically. Install it manually inside the container.")"
                fi
            fi
        else
            # CT is stopped — ask via whiptail (terminal-safe, no dialog on top of output)
            if whiptail --backtitle "$BACKTITLE" \
                        --title "$(translate "Filesystem Tools Required")" \
                        --yesno "$(translate "The filesystem") $FORMAT_TYPE $(translate "requires the package") $FS_PKG $(translate "installed inside CT") $CTID.\n\n$(translate "The container is currently stopped. Do you want to start it now to install the package?")\n\n$(translate "If you choose No, install") $FS_PKG $(translate "manually inside the container before starting it.")" \
                        $UI_YESNO_H $UI_YESNO_W; then
                msg_info "$(translate "Starting CT") $CTID..."
                pct start "$CTID" &>/dev/null
                sleep 2
                if [ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]; then
                    msg_error "$(translate "Failed to start CT") $CTID. $(translate "Install") $FS_PKG $(translate "manually inside the container.")"
                else
                    msg_ok "$(translate "CT") $CTID $(translate "started.")"
                    CT_RUNNING=true
                    msg_info "$(translate "Installing") $FS_PKG $(translate "in CT") $CTID..."
                    if install_fs_tools_in_ct "$CTID" "$FS_PKG"; then
                        msg_ok "$FS_PKG $(translate "installed in CT") $CTID."
                    else
                        msg_warn "$(translate "Could not install") $FS_PKG $(translate "automatically. Install it manually inside the container.")"
                    fi
                fi
            else
                msg_warn "$(translate "Manual install required inside CT") $CTID:"
                echo -e "${DGN}${TAB}  Debian/Ubuntu:${CL} ${BL}apt-get install -y $FS_PKG${CL}"
                echo -e "${DGN}${TAB}  Arch:${CL}          ${BL}pacman -S --noconfirm $FS_PKG${CL}"
                echo -e "${DGN}${TAB}  Alpine:${CL}        ${BL}apk add $FS_PKG${CL}"
                echo
            fi
        fi
    fi

    PERSISTENT_PARTITION=$(get_preferred_disk_path "$PARTITION")

    msg_info "$(translate "Applying passthrough to CT") $CTID..."
    if [ "$FORMAT_TYPE" == "xfs" ]; then
        RESULT=$(pct set "$CTID" -mp${INDEX} "$PERSISTENT_PARTITION,mp=$MOUNT_POINT,backup=0,ro=0" 2>&1)
    else
        RESULT=$(pct set "$CTID" -mp${INDEX} "$PERSISTENT_PARTITION,mp=$MOUNT_POINT,backup=0,ro=0,acl=1" 2>&1)
    fi
    SET_STATUS=$?

    if [ $SET_STATUS -eq 0 ]; then
        msg_ok "$(translate "Disk assigned at") $MOUNT_POINT $(translate "using") $PERSISTENT_PARTITION"
        [[ -n "$ASSIGNED_TO" ]] && msg_warn "$(translate "WARNING: This disk is also assigned to:") $(echo -e "$ASSIGNED_TO" | tr '\n' ' ')"

        # Verify disk is accessible inside the CT
        if [ "$CT_RUNNING" = true ]; then
            msg_info "$(translate "Verifying disk accessibility in CT") $CTID..."
            sleep 1
            if pct exec "$CTID" -- sh -c "mountpoint -q '$MOUNT_POINT' || [ -d '$MOUNT_POINT' ]" 2>/dev/null; then
                msg_ok "$(translate "Disk verified and accessible inside CT at") $MOUNT_POINT"
            fi
        fi

        ((DISKS_ADDED++))
    else
        msg_error "$(translate "Could not add disk") $DISK_INFO $(translate "to CT") $CTID. $(translate "Error:") $RESULT"
    fi
done

echo ""
if [ "$DISKS_ADDED" -gt 0 ]; then
    msg_ok "$(translate "Completed.") $DISKS_ADDED $(translate "disk(s) added to CT") $CTID."
else
    msg_warn "$(translate "No disks were added.")"
fi
msg_success "$(translate "Press Enter to return to menu...")"
read -r
exit 0
