#!/usr/bin/env bash
# Synex Installer
# Supports: ZFS, BTRFS

set -euo pipefail

LOG="/var/log/synex-installer.log"
mkdir -p "$(dirname "$LOG")"
exec > >(tee -a "$LOG") 2>&1

die()  { echo "[ERROR] $*" >&2; exit 1; }
info() { echo "[INFO] $*"; }

require_cmd() { command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1"; }

# Global variables
FS_TYPE=""
POOL_NAME=""
DISK=""
UEFI=0

# ZFS RAID topology (Phase 1)
ZFS_TOPOLOGY="single"     # single|mirror|raidz1|raidz2|raidz3
declare -a ZFS_DISKS=()   # whole disks: /dev/sda /dev/sdb ...
declare -a ROOT_PARTS=()  # zfs partitions to build pool: /dev/sda3 /dev/sdb3 ...
declare -a EFI_PARTS=()   # (future boot redundancy) /dev/sda1 ...
declare -a BOOT_PARTS=()  # (future boot redundancy) /dev/sda2 ...

# BTRFS variables
BTRFS_MKFS_OPTS=""
BTRFS_MOUNT_OPTS=""
declare -a BTRFS_SUBVOLS_NAME
declare -a BTRFS_SUBVOLS_MP

# Simple FS (ext4/xfs) variables
SIMPLE_FS_TYPE=""
SWAP_SIZE=0
declare -a SIMPLE_PARTS_MP
declare -a SIMPLE_PARTS_SIZE
declare -a SIMPLE_PARTS_DEV
declare -a SIMPLE_PARTS_SIZE_MIB

# LUKS + LVM variables (ext4 encryption only)
LUKS_ENABLED=0
LUKS_PASSWORD=""
LUKS_MAPPER="synex-luks"
VG_NAME="synex-vg"
LUKS_PART=""
declare -a LVM_LV_NAMES
declare -a LVM_LV_SIZES_MIB
declare -a LVM_LV_MP
declare -a LVM_LV_DEV
LVM_SWAP_SIZE=0
LVM_SWAP_DEV=""

# RAID variables (mdadm) - for ext4/xfs
RAID_ENABLED=0
RAID_LEVEL=""          # raid0|raid1|raid5|raid6|raid10
RAID_DEVICE="/dev/md0"
declare -a RAID_DISKS=()
declare -a RAID_PARTS=()  # partitions for RAID: /dev/sda3 /dev/sdb3 ...

# LVM standalone (without LUKS)
LVM_ENABLED=0

# ZFS native encryption variables
ZFS_ENCRYPTED=0
ZFS_PASSPHRASE=""

cleanup_mounts() {
  set +e

  if [[ "$FS_TYPE" == "zfs" ]]; then
    # ZFS cleanup
    if [[ -n "${POOL_NAME:-}" ]] && command -v zfs >/dev/null 2>&1; then
      zfs unmount -a >/dev/null 2>&1 || true
      for p in /target/var/log /target/var/cache /target/home /target/.snapshots /target; do
        mountpoint -q "$p" && umount -lf "$p" || true
      done
    fi
  else
    # BTRFS cleanup
    for p in /target/var/log /target/var/cache /target/home /target/.snapshots /target; do
      mountpoint -q "$p" && umount -lf "$p" || true
    done
  fi

  # Unmount chroot binds
  for p in /target/dev/pts /target/dev /target/proc /target/sys /target/run; do
    mountpoint -q "$p" && umount -lf "$p" || true
  done

  # /boot and EFI
  mountpoint -q /target/boot/efi && umount -lf /target/boot/efi || true
  mountpoint -q /target/boot && umount -lf /target/boot || true

  # Root
  mountpoint -q /target && umount -lf /target || true

  # Export ZFS pool if still imported
  if [[ "$FS_TYPE" == "zfs" && -n "${POOL_NAME:-}" ]] && command -v zpool >/dev/null 2>&1; then
    if zpool list -H -o name 2>/dev/null | grep -qx "$POOL_NAME"; then
      zpool export "$POOL_NAME" >/dev/null 2>&1 || true
    fi
  fi
  # Restore CTRL+C on exit
  stty intr ^C 2>/dev/null || true
}
trap cleanup_mounts EXIT

# Base requirements (common)
require_cmd lsblk
require_cmd sgdisk
require_cmd wipefs
require_cmd mkfs.ext4
require_cmd mkfs.vfat
require_cmd blkid
require_cmd unsquashfs
require_cmd chroot
require_cmd grub-install
require_cmd update-grub
require_cmd update-initramfs
require_cmd partprobe
require_cmd cryptsetup
require_cmd pvcreate
require_cmd vgcreate
require_cmd lvcreate
require_cmd mdadm

mkdir -p /target

# Main configuration loop (allows going back to filesystem selection)
while true; do

# Filesystem selection
echo
echo "========================================"
echo "        Synex Server Installer"
echo "========================================"
echo
echo "Select filesystem:"
echo "  1) ZFS   (pooling, RAIDZ, snapshots, native encryption)"
echo "  2) ext4  (single, LVM, RAID, LUKS2 encryption)"
echo "  3) XFS   (single, LVM, RAID, LUKS2 encryption)"
echo "  4) BTRFS (subvolumes, snapshots, LUKS2 encryption)"
echo
echo "Type 'q' or 'quit' to exit."
echo

while true; do
  read -r -p "Select option [1-4]: " FS_CHOICE

  [[ "$FS_CHOICE" == "q" || "$FS_CHOICE" == "quit" ]] && { info "Aborted by user."; exit 0; }

  case "$FS_CHOICE" in
    1)
      FS_TYPE="zfs"
      break
      ;;
    2)
      FS_TYPE="simple"
      SIMPLE_FS_TYPE="ext4"
      break
      ;;
    3)
      FS_TYPE="simple"
      SIMPLE_FS_TYPE="xfs"
      break
      ;;
    4)
      FS_TYPE="btrfs"
      break
      ;;
    *)
      echo "[ERROR] Invalid option. Please select 1-4, or 'q' to quit."
      echo
      ;;
  esac
done

info "Selected filesystem: $FS_TYPE$([ "$FS_TYPE" = "simple" ] && echo " ($SIMPLE_FS_TYPE)")"

# Ask for storage configuration (ext4/xfs)
if [[ "$FS_TYPE" == "simple" ]]; then
  # ============================================================
  # ext4/XFS Unified Block
  # ============================================================
  SIMPLE_STEP=1
  while true; do
    case $SIMPLE_STEP in
      1)
        # === STEP 1: Storage Configuration ===
        echo
        echo "========================================"
        echo "      Storage Configuration"
        echo "========================================"
        echo
        echo "  1) Single disk"
        echo "  2) RAID (mdadm)"
        echo
        echo "Type 'b' to go back, or 'q' to quit."
        echo

        while true; do
          read -r -p "Select storage type [1-2]: " STORAGE_CHOICE
          case "$STORAGE_CHOICE" in
            1)
              RAID_ENABLED=0
              info "Storage: Single disk"
              SIMPLE_STEP=2
              break
              ;;
            2)
              RAID_ENABLED=1
              info "Storage: RAID (mdadm)"
              SIMPLE_STEP=2
              break
              ;;
            b|back)
              info "Returning to filesystem selection..."
              continue 3
              ;;
            q|quit)
              info "Aborted by user."
              exit 0
              ;;
            *)
              echo "[ERROR] Please select 1, 2, 'b', or 'q'"
              ;;
          esac
        done
        ;;

      2)
        # === STEP 2: Encryption ===
        echo
        echo "========================================"
        echo "        Disk Encryption (LUKS2)"
        echo "========================================"
        echo
        echo "Full disk encryption protects your data if the"
        echo "server is physically stolen or accessed offline."
        echo
        echo "Note: /boot will remain unencrypted (required for GRUB)"
        echo
        echo "Type 'b' to go back, or 'q' to quit."
        echo

        while true; do
          read -r -p "Enable disk encryption (LUKS2)? (y/n): " LUKS_ANSWER
          case "$LUKS_ANSWER" in
            y|Y)
              LUKS_ENABLED=1
              LVM_ENABLED=1  # LUKS always uses LVM
              info "LUKS encryption enabled (with LVM)"
              echo
              while true; do
                read -r -s -p "Enter encryption password: " LUKS_PASSWORD
                echo
                if [[ ${#LUKS_PASSWORD} -lt 8 ]]; then
                  echo "[ERROR] Password must be at least 8 characters"
                  continue
                fi
                read -r -s -p "Confirm encryption password: " LUKS_PASSWORD_CONFIRM
                echo
                if [[ "$LUKS_PASSWORD" != "$LUKS_PASSWORD_CONFIRM" ]]; then
                  echo "[ERROR] Passwords do not match"
                  continue
                fi
                break
              done
              info "Encryption password set"
              SIMPLE_STEP=3
              break
              ;;
            n|N)
              LUKS_ENABLED=0
              info "Encryption disabled"
              SIMPLE_STEP=3
              break
              ;;
            b|back)
              SIMPLE_STEP=1
              break
              ;;
            q|quit)
              info "Aborted by user."
              exit 0
              ;;
            *)
              echo "[ERROR] Please answer y, n, b, or q"
              ;;
          esac
        done
        ;;

      3)
        # === STEP 3: LVM or RAID Level ===
        if [[ "$RAID_ENABLED" -eq 1 ]]; then
          # RAID Level Selection
          LVM_ENABLED=1  # RAID always uses LVM
          echo
          echo "========================================"
          echo "        RAID Configuration"
          echo "========================================"
          echo
          echo "  1) RAID0   (stripe, min 2 disks, NO redundancy)"
          echo "  2) RAID1   (mirror, min 2 disks)"
          echo "  3) RAID5   (parity, min 3 disks)"
          echo "  4) RAID6   (double parity, min 4 disks)"
          echo "  5) RAID10  (mirror+stripe, min 4 disks)"
          echo
          echo "Type 'b' to go back, or 'q' to quit."
          echo

          while true; do
            read -r -p "Select RAID level [1-5]: " RAID_CHOICE
            case "$RAID_CHOICE" in
              1) RAID_LEVEL="raid0"; RAID_MIN_DISKS=2; SIMPLE_STEP=4; break ;;
              2) RAID_LEVEL="raid1"; RAID_MIN_DISKS=2; SIMPLE_STEP=4; break ;;
              3) RAID_LEVEL="raid5"; RAID_MIN_DISKS=3; SIMPLE_STEP=4; break ;;
              4) RAID_LEVEL="raid6"; RAID_MIN_DISKS=4; SIMPLE_STEP=4; break ;;
              5) RAID_LEVEL="raid10"; RAID_MIN_DISKS=4; SIMPLE_STEP=4; break ;;
              b|back) SIMPLE_STEP=2; break ;;
              q|quit) info "Aborted by user."; exit 0 ;;
              *) echo "[ERROR] Please select 1-5, 'b', or 'q'" ;;
            esac
          done
          [[ "$SIMPLE_STEP" -eq 2 ]] && continue
          info "RAID level: $RAID_LEVEL (min $RAID_MIN_DISKS disks)"
        else
          # Single disk - LVM selection (only if no LUKS)
          if [[ "$LUKS_ENABLED" -eq 0 ]]; then
            echo
            echo "========================================"
            echo "        Volume Management (LVM)"
            echo "========================================"
            echo
            echo "LVM allows flexible partition management:"
            echo "  - Resize volumes after installation"
            echo "  - Create snapshots"
            echo "  - Add disks to extend storage"
            echo
            echo "Type 'b' to go back, or 'q' to quit."
            echo

            while true; do
              read -r -p "Enable LVM? (y/n): " LVM_ANSWER
              case "$LVM_ANSWER" in
                y|Y)
                  LVM_ENABLED=1
                  info "LVM enabled"
                  SIMPLE_STEP=4
                  break
                  ;;
                n|N)
                  LVM_ENABLED=0
                  info "Using simple partitions (no LVM)"
                  SIMPLE_STEP=4
                  break
                  ;;
                b|back)
                  SIMPLE_STEP=2
                  break
                  ;;
                q|quit)
                  info "Aborted by user."
                  exit 0
                  ;;
                *)
                  echo "[ERROR] Please answer y, n, b, or q"
                  ;;
              esac
            done
            [[ "$SIMPLE_STEP" -eq 2 ]] && continue
          else
            # LUKS enabled, skip LVM question (already enabled)
            SIMPLE_STEP=4
          fi
        fi
        ;;

      4)
        # === STEP 4: Disk Selection ===
        info "Filesystem: $SIMPLE_FS_TYPE"
        info "Configuration: $(
          if [[ "$RAID_ENABLED" -eq 1 ]]; then
            echo -n "RAID ($RAID_LEVEL) → "
          fi
          if [[ "$LUKS_ENABLED" -eq 1 ]]; then
            echo -n "LUKS → "
          fi
          if [[ "$LVM_ENABLED" -eq 1 ]]; then
            echo -n "LVM → "
          fi
          echo "$SIMPLE_FS_TYPE"
        )"

        info "Available disks:"
        printf "  %-8s %s\n" "NAME" "SIZE"
        lsblk -d -n -o NAME,SIZE,TYPE | grep -E 'disk$' | awk '{printf "  %-8s %s\n", $1, $2}'
        echo

        echo "Enter target disk(s) separated by spaces."
        echo
        echo "Type 'b' to go back, or 'q' to quit."
        echo

        if [[ "$RAID_ENABLED" -eq 1 ]]; then
          # RAID disk selection
          while true; do
            read -r -p "Disk(s): " RAID_DISK_INPUT
            [[ "$RAID_DISK_INPUT" == "q" || "$RAID_DISK_INPUT" == "quit" ]] && { info "Aborted by user."; exit 0; }
            [[ "$RAID_DISK_INPUT" == "b" || "$RAID_DISK_INPUT" == "back" ]] && { SIMPLE_STEP=3; break; }

            RAID_DISKS=()
            has_invalid=0
            for d in $RAID_DISK_INPUT; do
              [[ "$d" != /dev/* ]] && d="/dev/$d"
              if [[ -b "$d" ]]; then
                RAID_DISKS+=("$d")
              else
                echo "[ERROR] Invalid disk: $d"
                has_invalid=1
              fi
            done

            if [[ $has_invalid -eq 1 ]]; then
              echo "[ERROR] Please re-enter all disks."
              echo
              continue
            fi

            if [[ ${#RAID_DISKS[@]} -lt $RAID_MIN_DISKS ]]; then
              echo "[ERROR] $RAID_LEVEL requires at least $RAID_MIN_DISKS disks. You selected ${#RAID_DISKS[@]}."
              echo
              continue
            fi

            # RAID10 requires even number of disks
            if [[ "$RAID_LEVEL" == "raid10" && $((${#RAID_DISKS[@]} % 2)) -ne 0 ]]; then
              echo "[ERROR] RAID10 requires an even number of disks. You selected ${#RAID_DISKS[@]}."
              echo
              continue
            fi

            # RAID0 warning
            if [[ "$RAID_LEVEL" == "raid0" ]]; then
              echo
              echo "========================================"
              echo "              WARNING"
              echo "========================================"
              echo "RAID0 provides NO redundancy."
              echo "If ANY disk fails, ALL data is lost."
              echo "========================================"
              echo
              while true; do
                read -r -p "Are you sure? Type 'yes' to confirm or 'b' to go back: " RAID0_CONFIRM
                [[ "$RAID0_CONFIRM" == "yes" ]] && break
                [[ "$RAID0_CONFIRM" == "b" || "$RAID0_CONFIRM" == "back" ]] && break 2
                [[ "$RAID0_CONFIRM" == "q" || "$RAID0_CONFIRM" == "quit" ]] && { info "Aborted by user."; exit 0; }
                echo "[ERROR] Type 'yes' to confirm, 'b' to go back, or 'q' to quit."
              done
              [[ "$RAID0_CONFIRM" != "yes" ]] && continue
            fi

            info "RAID disks: ${RAID_DISKS[*]}"
            DISK="${RAID_DISKS[0]}"
            info "Boot disk: $DISK (/boot and EFI)"
            SIMPLE_STEP=5
            break
          done
          [[ "$SIMPLE_STEP" -eq 3 ]] && continue
        else
          # Single disk selection
          while true; do
            read -r -p "Disk(s): " DISK
            [[ "$DISK" == "q" || "$DISK" == "quit" ]] && { info "Aborted by user."; exit 0; }
            [[ "$DISK" == "b" || "$DISK" == "back" ]] && { SIMPLE_STEP=3; break; }
            [[ "$DISK" != /dev/* ]] && DISK="/dev/$DISK"

            if [[ -b "$DISK" ]] && lsblk -d -n -o NAME 2>/dev/null | grep -qx "$(basename "$DISK")"; then
              SIMPLE_STEP=5
              break
            else
              echo "[ERROR] Invalid disk. Please enter a valid block device."
              echo
            fi
          done
          [[ "$SIMPLE_STEP" -eq 3 ]] && continue
        fi
        ;;

      5)
        # === STEP 5: Confirmation ===
        echo
        echo "========================================"
        echo "         Installation Summary"
        echo "========================================"
        echo "Filesystem: $SIMPLE_FS_TYPE"
        if [[ "$RAID_ENABLED" -eq 1 ]]; then
          echo "Storage  : RAID ($RAID_LEVEL)"
          echo "Disks    : ${RAID_DISKS[*]}"
        else
          echo "Storage  : Single disk"
          echo "Disk     : $DISK"
        fi
        echo "Encrypted: $([ "$LUKS_ENABLED" -eq 1 ] && echo "Yes (LUKS2)" || echo "No")"
        echo "LVM      : $([ "$LVM_ENABLED" -eq 1 ] && echo "Yes" || echo "No")"
        echo "========================================"
        echo

        if [[ "$RAID_ENABLED" -eq 1 ]]; then
          echo "WARNING: THIS WILL ERASE THE ENTIRE DISK(S):"
          for d in "${RAID_DISKS[@]}"; do echo "  - $d"; done
        else
          echo "WARNING: THIS WILL ERASE THE ENTIRE DISK: $DISK"
        fi
        echo

        while true; do
          read -r -p "Type YES to confirm, 'b' to go back, or 'q' to quit: " CONFIRM
          [[ "$CONFIRM" == "q" || "$CONFIRM" == "quit" ]] && { info "Aborted by user."; exit 0; }
          [[ "$CONFIRM" == "b" || "$CONFIRM" == "back" ]] && { SIMPLE_STEP=4; break; }
          [[ "$CONFIRM" == "YES" ]] && break 2
          echo "[ERROR] Please type 'YES' to confirm, 'b' to go back, or 'q' to quit."
          echo
        done
        ;;
    esac
  done
fi

# Load configuration based on FS type
CONF_DIR="${SYNEX_INSTALLER_CONF:-/etc/synex-installer}"

if false; then  # ZFS config moved to unified block below
  # ============================================================
  # ZFS Configuration Loading
  # ============================================================
  require_cmd zpool
  require_cmd zfs
  require_cmd modprobe

  info "Loading ZFS kernel module..."
  modprobe zfs || die "Unable to load the zfs module. ZFS kernel modules/support must be included in the ISO."

  # Select config file based on encryption choice
  if [[ "$ZFS_ENCRYPTED" -eq 1 ]]; then
    CONF_PATH="${CONF_DIR}/zfs-encrypted.conf"
    if [[ ! -f "$CONF_PATH" && -f "./zfs-encrypted.conf" ]]; then
      CONF_PATH="./zfs-encrypted.conf"
    fi
    [[ -f "$CONF_PATH" ]] || die "Cannot find zfs-encrypted.conf at ${CONF_DIR}/zfs-encrypted.conf"
  else
    CONF_PATH="${CONF_DIR}/zfs.conf"
    if [[ ! -f "$CONF_PATH" && -f "./zfs.conf" ]]; then
      CONF_PATH="./zfs.conf"
    fi
    [[ -f "$CONF_PATH" ]] || die "Cannot find zfs.conf at ${CONF_DIR}/zfs.conf"
  fi
  info "Using config: $CONF_PATH"

  POOL_NAME="$(awk -F': ' '/^[[:space:]]*poolName:[[:space:]]*/{print $2; exit}' "$CONF_PATH" | tr -d '"' | tr -d "'")"
  [[ -n "${POOL_NAME:-}" ]] || die "Unable to read poolName from zfs.conf"

  POOL_OPTS="$(awk -F': ' '/^[[:space:]]*poolOptions:[[:space:]]*/{sub(/^[^:]+:[[:space:]]*/, "", $0); print $0; exit}' "$CONF_PATH" | sed 's/^"//; s/"$//')"
  [[ -n "${POOL_OPTS:-}" ]] || die "Unable to read poolOptions from zfs.conf"

  DATASET_OPTS="$(awk -F': ' '/^[[:space:]]*datasetOptions:[[:space:]]*/{sub(/^[^:]+:[[:space:]]*/, "", $0); print $0; exit}' "$CONF_PATH" | sed 's/^"//; s/"$//')"
  [[ -n "${DATASET_OPTS:-}" ]] || die "Unable to read datasetOptions from zfs.conf"

  mapfile -t DATASETS < <(
    awk '
      BEGIN{inlist=0; ds=""; mp=""; cm=""}
      /^[[:space:]]*datasets:[[:space:]]*$/ {inlist=1; next}
      inlist==1 && /^[[:space:]]*-[[:space:]]*dsName:/ {
        ds=$0; sub(/.*dsName:[[:space:]]*/, "", ds);
        gsub(/"/, "", ds); gsub(/\r/, "", ds);
        mp=""; cm="";
        next
      }
      inlist==1 && /^[[:space:]]*mountpoint:/ {
        mp=$0; sub(/.*mountpoint:[[:space:]]*/, "", mp);
        gsub(/"/, "", mp); gsub(/\r/, "", mp);
        next
      }
      inlist==1 && /^[[:space:]]*canMount:/ {
        cm=$0; sub(/.*canMount:[[:space:]]*/, "", cm);
        gsub(/"/, "", cm); gsub(/\r/, "", cm);
        if (ds!="") print ds "|" mp "|" cm
        next
      }
    ' "$CONF_PATH"
  )
  [[ "${#DATASETS[@]}" -gt 0 ]] || die "Unable to read datasets from zfs.conf"

  BOOTFS_DS="${POOL_NAME}/ROOT/synex/root"

elif false; then  # BTRFS config moved to unified block below
  # ============================================================
  # BTRFS Configuration Loading
  # ============================================================
  require_cmd mkfs.btrfs
  require_cmd btrfs

  CONF_PATH="${CONF_DIR}/btrfs.conf"
  if [[ ! -f "$CONF_PATH" && -f "./btrfs.conf" ]]; then
    CONF_PATH="./btrfs.conf"
  fi
  [[ -f "$CONF_PATH" ]] || die "Cannot find btrfs.conf at ${CONF_DIR}/btrfs.conf"
  info "Using btrfs.conf: $CONF_PATH"

  BTRFS_MKFS_OPTS="$(awk -F': ' '/^[[:space:]]*mkfsOptions:[[:space:]]*/{print $2; exit}' "$CONF_PATH" | tr -d '"' | tr -d "'")"
  BTRFS_MKFS_OPTS="${BTRFS_MKFS_OPTS:--f}"

  BTRFS_MOUNT_OPTS="$(awk -F': ' '/^[[:space:]]*mountOptions:[[:space:]]*/{print $2; exit}' "$CONF_PATH" | tr -d '"' | tr -d "'")"
  BTRFS_MOUNT_OPTS="${BTRFS_MOUNT_OPTS:-defaults,relatime,compress=zstd:1}"

  mapfile -t BTRFS_SUBVOLS < <(
    awk '
      BEGIN{inlist=0; sv=""; mp=""}
      /^[[:space:]]*subvolumes:[[:space:]]*$/ {inlist=1; next}
      inlist==1 && /^[[:space:]]*-[[:space:]]*subvol:/ {
        sv=$0; sub(/.*subvol:[[:space:]]*/, "", sv);
        gsub(/"/, "", sv); gsub(/\r/, "", sv);
        mp="";
        next
      }
      inlist==1 && /^[[:space:]]*mountpoint:/ {
        mp=$0; sub(/.*mountpoint:[[:space:]]*/, "", mp);
        gsub(/"/, "", mp); gsub(/\r/, "", mp);
        if (sv!="") print sv "|" mp
        next
      }
    ' "$CONF_PATH"
  )
  [[ "${#BTRFS_SUBVOLS[@]}" -gt 0 ]] || die "Unable to read subvolumes from btrfs.conf"

  # Parse into separate arrays
  for entry in "${BTRFS_SUBVOLS[@]}"; do
    BTRFS_SUBVOLS_NAME+=("${entry%%|*}")
    BTRFS_SUBVOLS_MP+=("${entry#*|}")
  done

elif [[ "$FS_TYPE" == "simple" ]]; then
  # ============================================================
  # Simple FS (ext4/XFS) - Interactive Configuration
  # ============================================================

  if [[ "$SIMPLE_FS_TYPE" == "xfs" ]]; then
    require_cmd mkfs.xfs
    require_cmd xfs_admin
  fi

  info "Filesystem: $SIMPLE_FS_TYPE"
  if [[ "$RAID_ENABLED" -ne 1 ]]; then
    info "Configuration will continue after disk selection..."
  fi

fi

if [[ "$FS_TYPE" == "zfs" ]]; then
  ZFS_STEP=1
  while true; do
    case $ZFS_STEP in
      1)
        # === STEP 1: ZFS Native Encryption ===
        echo
        echo "========================================"
        echo "        ZFS Native Encryption"
        echo "========================================"
        echo
        echo "ZFS native encryption protects your data with"
        echo "AES-256-GCM encryption at the filesystem level."
        echo
        echo "Note: /boot will remain unencrypted (required for GRUB)"
        echo
        echo "Type 'b' to go back, or 'q' to quit."
        echo

        while true; do
          read -r -p "Enable ZFS native encryption? (y/n): " ZFS_ENC_ANSWER
          case "$ZFS_ENC_ANSWER" in
            y|Y)
              ZFS_ENCRYPTED=1
              info "ZFS encryption enabled"
              echo
              while true; do
                read -r -s -p "Enter encryption passphrase: " ZFS_PASSPHRASE
                echo
                if [[ ${#ZFS_PASSPHRASE} -lt 8 ]]; then
                  echo "[ERROR] Passphrase must be at least 8 characters"
                  continue
                fi
                read -r -s -p "Confirm encryption passphrase: " ZFS_PASSPHRASE_CONFIRM
                echo
                if [[ "$ZFS_PASSPHRASE" != "$ZFS_PASSPHRASE_CONFIRM" ]]; then
                  echo "[ERROR] Passphrases do not match"
                  continue
                fi
                break
              done
              info "Encryption passphrase set"
              ZFS_STEP=2
              break
              ;;
            n|N)
              ZFS_ENCRYPTED=0
              info "Encryption disabled, using standard ZFS"
              ZFS_STEP=2
              break
              ;;
            b|back)
              info "Returning to filesystem selection..."
              continue 3
              ;;
            q|quit)
              info "Aborted by user."
              exit 0
              ;;
            *)
              echo "[ERROR] Please answer y, n, b, or q"
              ;;
          esac
        done
        ;;

      2)
        # === Config Loading (runs after encryption choice) ===
        info "Loading ZFS kernel module..."
        modprobe zfs || die "Unable to load the zfs module."

        if [[ "$ZFS_ENCRYPTED" -eq 1 ]]; then
          CONF_PATH="${CONF_DIR}/zfs-encrypted.conf"
          [[ ! -f "$CONF_PATH" && -f "./zfs-encrypted.conf" ]] && CONF_PATH="./zfs-encrypted.conf"
          [[ -f "$CONF_PATH" ]] || die "Cannot find zfs-encrypted.conf"
        else
          CONF_PATH="${CONF_DIR}/zfs.conf"
          [[ ! -f "$CONF_PATH" && -f "./zfs.conf" ]] && CONF_PATH="./zfs.conf"
          [[ -f "$CONF_PATH" ]] || die "Cannot find zfs.conf"
        fi
        info "Using config: $CONF_PATH"

        POOL_NAME="$(awk -F': ' '/^[[:space:]]*poolName:[[:space:]]*/{print $2; exit}' "$CONF_PATH" | tr -d '"' | tr -d "'")"
        [[ -n "${POOL_NAME:-}" ]] || die "Unable to read poolName from zfs.conf"

        POOL_OPTS="$(awk -F': ' '/^[[:space:]]*poolOptions:[[:space:]]*/{sub(/^[^:]+:[[:space:]]*/, "", $0); print $0; exit}' "$CONF_PATH" | sed 's/^"//; s/"$//')"
        [[ -n "${POOL_OPTS:-}" ]] || die "Unable to read poolOptions from zfs.conf"

        DATASET_OPTS="$(awk -F': ' '/^[[:space:]]*datasetOptions:[[:space:]]*/{sub(/^[^:]+:[[:space:]]*/, "", $0); print $0; exit}' "$CONF_PATH" | sed 's/^"//; s/"$//')"
        [[ -n "${DATASET_OPTS:-}" ]] || die "Unable to read datasetOptions from zfs.conf"

        mapfile -t DATASETS < <(
          awk '
            BEGIN{inlist=0; ds=""; mp=""; cm=""}
            /^[[:space:]]*datasets:[[:space:]]*$/ {inlist=1; next}
            inlist==1 && /^[[:space:]]*-[[:space:]]*dsName:/ {
              ds=$0; sub(/.*dsName:[[:space:]]*/, "", ds);
              gsub(/"/, "", ds); gsub(/\r/, "", ds);
              mp=""; cm="";
              next
            }
            inlist==1 && /^[[:space:]]*mountpoint:/ {
              mp=$0; sub(/.*mountpoint:[[:space:]]*/, "", mp);
              gsub(/"/, "", mp); gsub(/\r/, "", mp);
              next
            }
            inlist==1 && /^[[:space:]]*canMount:/ {
              cm=$0; sub(/.*canMount:[[:space:]]*/, "", cm);
              gsub(/"/, "", cm); gsub(/\r/, "", cm);
              if (ds!="") print ds "|" mp "|" cm
              next
            }
          ' "$CONF_PATH"
        )
        [[ "${#DATASETS[@]}" -gt 0 ]] || die "Unable to read datasets from zfs.conf"

        BOOTFS_DS="${POOL_NAME}/ROOT/synex/root"

        # === STEP 2: ZFS Topology Selection ===
        echo
        echo "========================================"
        echo "        ZFS Topology Selection"
        echo "========================================"
        echo "  1) Single / Stripe  (no redundancy)"
        echo "  2) Mirror / Performance  (min 2 disks)"
        echo "  3) RAIDZ1  (min 3 disks)"
        echo "  4) RAIDZ2  (min 4 disks)"
        echo "  5) RAIDZ3  (min 5 disks)"
        echo
        echo "Type 'b' to go back, or 'q' to quit."
        echo

        while true; do
          read -r -p "Select ZFS topology [1-5]: " topo
          case "$topo" in
            1) ZFS_TOPOLOGY="single"; break ;;
            2) ZFS_TOPOLOGY="mirror"; break ;;
            3) ZFS_TOPOLOGY="raidz1"; break ;;
            4) ZFS_TOPOLOGY="raidz2"; break ;;
            5) ZFS_TOPOLOGY="raidz3"; break ;;
            b|back) ZFS_STEP=1; break ;;
            q|quit) info "Aborted by user."; exit 0 ;;
            *) echo "[ERROR] Invalid option. Choose 1-5, 'b', or 'q'." ;;
          esac
        done

        [[ "$ZFS_STEP" -eq 1 ]] && continue
        ZFS_STEP=3
        ;;

      3)
        # === STEP 3: Disk Selection ===
        info "Pool: $POOL_NAME"
        info "Pool options: $POOL_OPTS"
        info "Dataset options: $DATASET_OPTS"
        info "Expected bootfs dataset: $BOOTFS_DS"

        info "Available disks:"
        printf "  %-8s %s\n" "NAME" "SIZE"
        lsblk -d -n -o NAME,SIZE,TYPE | grep -E 'disk$' | awk '{printf "  %-8s %s\n", $1, $2}'

        echo
        echo "Enter target disk(s) separated by spaces."
        echo
        echo "Type 'b' to go back, or 'q' to quit."
        echo

        while true; do
          read -r -p "Disk(s): " disks_line
          [[ "$disks_line" == "q" || "$disks_line" == "quit" ]] && { info "Aborted by user."; exit 0; }
          [[ "$disks_line" == "b" || "$disks_line" == "back" ]] && { ZFS_STEP=2; break; }

          read -r -a _tmp_disks <<<"$disks_line"
          [[ "${#_tmp_disks[@]}" -gt 0 ]] || { echo "[ERROR] No disks provided."; echo; continue; }

          ZFS_DISKS=()
          ok=1
          for d in "${_tmp_disks[@]}"; do
            [[ "$d" != /dev/* ]] && d="/dev/$d"

            if [[ -b "$d" ]] && lsblk -d -n -o NAME 2>/dev/null | grep -qx "$(basename "$d")"; then
              for e in "${ZFS_DISKS[@]}"; do
                [[ "$e" == "$d" ]] && { ok=0; echo "[ERROR] Duplicate disk: $d"; break; }
              done
              [[ $ok -eq 0 ]] && break
              ZFS_DISKS+=("$d")
            else
              ok=0
              echo "[ERROR] Invalid disk: $d (must be whole disk like /dev/sda)"
              break
            fi
          done
          [[ $ok -eq 1 ]] || { echo; continue; }

          need=1
          case "$ZFS_TOPOLOGY" in
            single) need=1 ;;
            mirror) need=2 ;;
            raidz1) need=3 ;;
            raidz2) need=4 ;;
            raidz3) need=5 ;;
          esac

          if [[ "${#ZFS_DISKS[@]}" -lt "$need" ]]; then
            echo "[ERROR] $ZFS_TOPOLOGY requires at least $need disk(s). You entered ${#ZFS_DISKS[@]}."
            echo
            continue
          fi

          if [[ "$ZFS_TOPOLOGY" == "single" && "${#ZFS_DISKS[@]}" -gt 1 ]]; then
            echo
            echo "========================================"
            echo "             *** WARNING ***"
            echo "========================================"
            echo "You selected ${#ZFS_DISKS[@]} disks with NO REDUNDANCY (stripe/RAID0)."
            echo "If ANY disk fails, ALL DATA WILL BE LOST."
            echo "========================================"
            echo
            read -r -p "Are you sure? (yes/no): " stripe_confirm
            if [[ "$stripe_confirm" != "yes" ]]; then
              echo "Returning to disk selection..."
              echo
              continue
            fi
          fi

          if [[ "$ZFS_TOPOLOGY" == "mirror" ]]; then
            disk_count="${#ZFS_DISKS[@]}"
            if [[ $((disk_count % 2)) -eq 0 ]]; then
              if [[ "$disk_count" -eq 2 ]]; then
                info "Configuration: mirror (2 disks)"
              else
                info "Configuration: $((disk_count / 2)) striped mirrors (RAID10)"
              fi
            else
              info "Configuration: $(((disk_count - 1) / 2)) striped mirror(s) + 1 hot spare"
            fi
          fi

          DISK="${ZFS_DISKS[0]}"
          ZFS_STEP=4
          break
        done

        [[ "$ZFS_STEP" -eq 2 ]] && continue
        ;;

      4)
        # === STEP 4: Confirmation ===
        echo
        echo "========================================"
        echo "            ZFS Install Summary"
        echo "========================================"
        echo "Topology : $ZFS_TOPOLOGY"
        echo "Disks    : ${ZFS_DISKS[*]}"
        echo "Boot disk: $DISK  (Phase 1: /boot and EFI live here)"
        echo "========================================"
        echo

        echo "WARNING: THIS WILL ERASE THE ENTIRE DISK(S):"
        for d in "${ZFS_DISKS[@]}"; do echo "  - $d"; done
        echo

        while true; do
          read -r -p "Type YES to confirm, 'b' to go back, or 'q' to quit: " CONFIRM
          [[ "$CONFIRM" == "q" || "$CONFIRM" == "quit" ]] && { info "Aborted by user."; exit 0; }
          [[ "$CONFIRM" == "b" || "$CONFIRM" == "back" ]] && { ZFS_STEP=3; break; }
          [[ "$CONFIRM" == "YES" ]] && break 2
          echo "[ERROR] Please type 'YES' to confirm, 'b' to go back, or 'q' to quit."
          echo
        done
        ;;
    esac
  done

elif [[ "$FS_TYPE" == "btrfs" ]]; then
  # ============================================================
  # BTRFS Unified Block
  # ============================================================
  BTRFS_STEP=1
  while true; do
    case $BTRFS_STEP in
      1)
        # === STEP 1: Config Loading + Encryption ===
        require_cmd mkfs.btrfs
        require_cmd btrfs

        CONF_PATH="${CONF_DIR}/btrfs.conf"
        [[ ! -f "$CONF_PATH" && -f "./btrfs.conf" ]] && CONF_PATH="./btrfs.conf"
        [[ -f "$CONF_PATH" ]] || die "Cannot find btrfs.conf"
        info "Using btrfs.conf: $CONF_PATH"

        BTRFS_MKFS_OPTS="$(awk -F': ' '/^[[:space:]]*mkfsOptions:[[:space:]]*/{print $2; exit}' "$CONF_PATH" | tr -d '"' | tr -d "'")"
        BTRFS_MKFS_OPTS="${BTRFS_MKFS_OPTS:--f}"

        BTRFS_MOUNT_OPTS="$(awk -F': ' '/^[[:space:]]*mountOptions:[[:space:]]*/{print $2; exit}' "$CONF_PATH" | tr -d '"' | tr -d "'")"
        BTRFS_MOUNT_OPTS="${BTRFS_MOUNT_OPTS:-defaults,relatime,compress=zstd:1}"

        mapfile -t BTRFS_SUBVOLS < <(
          awk '
            BEGIN{inlist=0; sv=""; mp=""}
            /^[[:space:]]*subvolumes:[[:space:]]*$/ {inlist=1; next}
            inlist==1 && /^[[:space:]]*-[[:space:]]*subvol:/ {
              sv=$0; sub(/.*subvol:[[:space:]]*/, "", sv);
              gsub(/"/, "", sv); gsub(/\r/, "", sv);
              mp="";
              next
            }
            inlist==1 && /^[[:space:]]*mountpoint:/ {
              mp=$0; sub(/.*mountpoint:[[:space:]]*/, "", mp);
              gsub(/"/, "", mp); gsub(/\r/, "", mp);
              if (sv!="") print sv "|" mp
              next
            }
          ' "$CONF_PATH"
        )
        [[ "${#BTRFS_SUBVOLS[@]}" -gt 0 ]] || die "Unable to read subvolumes from btrfs.conf"

        BTRFS_SUBVOLS_NAME=()
        BTRFS_SUBVOLS_MP=()
        for entry in "${BTRFS_SUBVOLS[@]}"; do
          BTRFS_SUBVOLS_NAME+=("${entry%%|*}")
          BTRFS_SUBVOLS_MP+=("${entry#*|}")
        done

        echo
        echo "========================================"
        echo "        Disk Encryption (LUKS2)"
        echo "========================================"
        echo
        echo "Full disk encryption protects your data if the"
        echo "server is physically stolen or accessed offline."
        echo
        echo "Note: /boot will remain unencrypted (required for GRUB)"
        echo
        echo "Type 'b' to go back, or 'q' to quit."
        echo

        while true; do
          read -r -p "Enable full disk encryption (LUKS2)? (y/n): " LUKS_ANSWER
          case "$LUKS_ANSWER" in
            y|Y)
              LUKS_ENABLED=1
              info "LUKS encryption enabled"
              echo
              while true; do
                read -r -s -p "Enter encryption password: " LUKS_PASSWORD
                echo
                if [[ ${#LUKS_PASSWORD} -lt 8 ]]; then
                  echo "[ERROR] Password must be at least 8 characters"
                  continue
                fi
                read -r -s -p "Confirm encryption password: " LUKS_PASSWORD_CONFIRM
                echo
                if [[ "$LUKS_PASSWORD" != "$LUKS_PASSWORD_CONFIRM" ]]; then
                  echo "[ERROR] Passwords do not match"
                  continue
                fi
                break
              done
              info "Encryption password set"
              BTRFS_STEP=2
              break
              ;;
            n|N)
              LUKS_ENABLED=0
              info "Encryption disabled, using plain BTRFS"
              BTRFS_STEP=2
              break
              ;;
            b|back)
              info "Returning to filesystem selection..."
              continue 3
              ;;
            q|quit)
              info "Aborted by user."
              exit 0
              ;;
            *)
              echo "[ERROR] Please answer y, n, b, or q"
              ;;
          esac
        done
        ;;

      2)
        # === STEP 2: Disk Selection ===
        info "BTRFS mkfs options: $BTRFS_MKFS_OPTS"
        info "BTRFS mount options: $BTRFS_MOUNT_OPTS"
        info "Subvolumes to create: ${#BTRFS_SUBVOLS[@]}"

        info "Available disks:"
        printf "  %-8s %s\n" "NAME" "SIZE"
        lsblk -d -n -o NAME,SIZE,TYPE | grep -E 'disk$' | awk '{printf "  %-8s %s\n", $1, $2}'
        echo

        echo "Enter target disk(s) separated by spaces."
        echo
        echo "Type 'b' to go back, or 'q' to quit."
        echo

        while true; do
          read -r -p "Disk(s): " DISK
          [[ "$DISK" == "q" || "$DISK" == "quit" ]] && { info "Aborted by user."; exit 0; }
          [[ "$DISK" == "b" || "$DISK" == "back" ]] && { BTRFS_STEP=1; break; }
          [[ "$DISK" != /dev/* ]] && DISK="/dev/$DISK"

          if [[ -b "$DISK" ]] && lsblk -d -n -o NAME 2>/dev/null | grep -qx "$(basename "$DISK")"; then
            BTRFS_STEP=3
            break
          else
            echo "[ERROR] Invalid disk. Please enter a valid block device."
            echo
          fi
        done

        [[ "$BTRFS_STEP" -eq 1 ]] && continue
        ;;

      3)
        # === STEP 3: Confirmation ===
        echo
        echo "========================================"
        echo "          BTRFS Install Summary"
        echo "========================================"
        echo "Disk     : $DISK"
        echo "Encrypted: $([ "$LUKS_ENABLED" -eq 1 ] && echo "Yes (LUKS2)" || echo "No")"
        echo "Subvols  : ${#BTRFS_SUBVOLS[@]}"
        echo "========================================"
        echo
        echo "WARNING: THIS WILL ERASE THE ENTIRE DISK: $DISK"
        echo

        while true; do
          read -r -p "Type YES to confirm, 'b' to go back, or 'q' to quit: " CONFIRM
          [[ "$CONFIRM" == "q" || "$CONFIRM" == "quit" ]] && { info "Aborted by user."; exit 0; }
          [[ "$CONFIRM" == "b" || "$CONFIRM" == "back" ]] && { BTRFS_STEP=2; break; }
          [[ "$CONFIRM" == "YES" ]] && break 2
          echo "[ERROR] Please type 'YES' to confirm, 'b' to go back, or 'q' to quit."
          echo
        done
        ;;
    esac
  done
fi

# Confirmed - exit main configuration loop
break
done  # End main configuration loop

# Function to configure simple FS partitions interactively
configure_simple_partitions() {
  local disk_size_bytes disk_size_gb reserved_gb available_gb

  # Get disk size in GB
  disk_size_bytes=$(lsblk -b -d -n -o SIZE "$DISK")
  disk_size_gb=$(awk "BEGIN {printf \"%.2f\", $disk_size_bytes / 1024 / 1024 / 1024}")

  # Reserved: EFI (300MB) + boot (512MB) ≈ 1GB
  if [[ $UEFI -eq 1 ]]; then
    reserved_gb=1
  else
    reserved_gb=0.5
  fi

  available_gb=$(awk "BEGIN {printf \"%.2f\", $disk_size_gb - $reserved_gb}")

  echo
  echo "========================================"
  echo "     Partition Configuration ($SIMPLE_FS_TYPE)"
  echo "========================================"
  echo
  echo "Disk: $DISK ($disk_size_gb GB)"
  echo "Reserved for boot: $reserved_gb GB"
  echo "Available for system: $available_gb GB"
  echo

  # Ask for swap
  echo "----------------------------------------"
  while true; do
    read -r -p "Create swap partition? (y/n): " SWAP_ANSWER
    case "$SWAP_ANSWER" in
      y|Y|yes|YES)
        while true; do
          read -r -p "Swap size in GB [suggested: 4]: " SWAP_SIZE
          SWAP_SIZE="${SWAP_SIZE:-4}"

          if [[ "$SWAP_SIZE" =~ ^[0-9]+\.?[0-9]*$ ]]; then
            if awk "BEGIN {exit !($SWAP_SIZE >= 0.5 && $SWAP_SIZE <= $available_gb)}"; then
              available_gb=$(awk "BEGIN {printf \"%.2f\", $available_gb - $SWAP_SIZE}")
              info "Swap: ${SWAP_SIZE} GB"
              break
            else
              echo "[ERROR] Size must be between 0.5 and $available_gb GB"
            fi
          else
            echo "[ERROR] Invalid number"
          fi
        done
        break
        ;;
      n|N|no|NO)
        SWAP_SIZE=0
        info "No swap partition"
        break
        ;;
      *)
        echo "[ERROR] Please answer y or n"
        ;;
    esac
  done

  echo
  echo "Available space: $available_gb GB"
  echo

  # Partition loop
  echo "----------------------------------------"
  echo "Define mount points (max 10 partitions)"
  echo "Root (/) is mandatory"
  echo "----------------------------------------"
  echo

  local part_count=0
  local root_defined=false

  while [[ $part_count -lt 10 ]]; do
    # Ask for mount point
    local mp=""
    while true; do
      read -r -p "Mount point (e.g., /, /home, /var) or 'done' to finish: " mp

      [[ "$mp" == "done" ]] && break 2
      [[ "$mp" == "q" || "$mp" == "quit" ]] && { info "Aborted by user."; exit 0; }

      # Validate mount point format
      if [[ ! "$mp" =~ ^/ ]]; then
        echo "[ERROR] Mount point must start with /"
        continue
      fi

      # Check for duplicates
      local duplicate=false
      for existing in "${SIMPLE_PARTS_MP[@]}"; do
        if [[ "$existing" == "$mp" ]]; then
          duplicate=true
          break
        fi
      done

      if [[ "$duplicate" == true ]]; then
        echo "[ERROR] Mount point '$mp' already defined"
        continue
      fi

      break
    done

    # Ask for size
    local size=""
    local size_mib=""
    while true; do
      echo "Available: $available_gb GB"
      read -r -p "Size in GB (or 'rest' for remaining space): " size

      if [[ "$size" == "rest" ]]; then
        size="$available_gb"
        size_mib="REST"
        info "Using all remaining space: $size GB"
        available_gb="0.00"
        break
      fi

      if [[ "$size" =~ ^[0-9]+\.?[0-9]*$ ]]; then
        # Minimum 1GB (10GB for root)
        local min_size=1
        [[ "$mp" == "/" ]] && min_size=10

        # Check minimum
        if awk "BEGIN {exit !($size < $min_size)}"; then
          echo "[ERROR] Minimum size is $min_size GB"
          continue
        fi

        # If user asks for more than available, use all available
        if awk "BEGIN {exit !($size >= $available_gb)}"; then
          size="$available_gb"
          size_mib="REST"
          info "Adjusted to all remaining space: $size GB"
          available_gb="0.00"
          break
        fi

        # Calculate remainder
        local remainder
        remainder=$(awk "BEGIN {printf \"%.2f\", $available_gb - $size}")

        # If remainder < 1GB, absorb it (take all remaining)
        if awk "BEGIN {exit !($remainder > 0 && $remainder < 1)}"; then
          info "Remainder ($remainder GB) < 1GB, absorbing into this partition"
          size="$available_gb"
          size_mib="REST"
          available_gb="0.00"
        else
          # Convert GB to MiB (integer) for sgdisk
          size_mib=$(awk "BEGIN {printf \"%.0f\", $size * 1024}")
          available_gb="$remainder"
        fi
        break
      else
        echo "[ERROR] Invalid number"
      fi
    done

    # Store partition info
    SIMPLE_PARTS_MP+=("$mp")
    SIMPLE_PARTS_SIZE+=("$size")
    SIMPLE_PARTS_SIZE_MIB+=("$size_mib")
    part_count=$((part_count + 1))

    [[ "$mp" == "/" ]] && root_defined=true

    echo
    info "Partition $part_count: $mp (${size} GB, $SIMPLE_FS_TYPE)"
    echo "Remaining space: $available_gb GB"
    echo

    # Check if space left
    if awk "BEGIN {exit !($available_gb < 1)}"; then
      info "Less than 1 GB remaining, finishing partition setup"
      break
    fi

    # Ask to continue only if not first partition (root might be mandatory)
    if [[ "$root_defined" == true ]]; then
      while true; do
        read -r -p "Add another partition? (y/n): " MORE
        case "$MORE" in
          y|Y) break ;;
          n|N) break 2 ;;
          *) echo "[ERROR] Please answer y or n" ;;
        esac
      done
    fi
  done

  # Validate root exists
  if [[ "$root_defined" != true ]]; then
    die "Root partition (/) is mandatory"
  fi

  # Show summary
  echo
  echo "========================================"
  echo "         Partition Summary"
  echo "========================================"
  echo
  if [[ $UEFI -eq 1 ]]; then
    echo "  /boot/efi    300 MB   (FAT32, auto)"
  fi
  echo "  /boot        512 MB   (ext4, auto)"
  if [[ "$SWAP_SIZE" != "0" ]]; then
    echo "  [swap]       $SWAP_SIZE GB   (swap)"
  fi
  for i in "${!SIMPLE_PARTS_MP[@]}"; do
    printf "  %-12s %s GB   (%s)\n" "${SIMPLE_PARTS_MP[$i]}" "${SIMPLE_PARTS_SIZE[$i]}" "$SIMPLE_FS_TYPE"
  done
  echo "========================================"
  echo
}

# Function to configure LUKS+LVM partitions interactively (ext4/xfs)
configure_luks_lvm_partitions() {
  local disk_size_bytes disk_size_gb reserved_gb available_gb
  local storage_desc

  # Determine storage source (RAID or single disk)
  if [[ "$RAID_ENABLED" -eq 1 ]]; then
    # For RAID with redundancy, EFI+boot partitions exist on EACH disk
    local reserved_per_disk_bytes
    if [[ $UEFI -eq 1 ]]; then
      reserved_per_disk_bytes=$((512*1024*1024 + 1024*1024*1024))
    else
      reserved_per_disk_bytes=$((1*1024*1024 + 1024*1024*1024))
    fi

    # Calculate total DATA partition space
    local data_total=0
    for d in "${RAID_DISKS[@]}"; do
      local dsize=$(lsblk -b -d -n -o SIZE "$d")
      if [[ "$RAID_LEVEL" == "raid0" ]]; then
        if [[ "$d" == "${RAID_DISKS[0]}" ]]; then
          data_total=$((data_total + dsize - reserved_per_disk_bytes))
        else
          data_total=$((data_total + dsize))
        fi
      else
        data_total=$((data_total + dsize - reserved_per_disk_bytes))
      fi
    done

    # Apply RAID factor
    case "$RAID_LEVEL" in
      raid0)  disk_size_bytes=$data_total ;;
      raid1)  disk_size_bytes=$((data_total / ${#RAID_DISKS[@]})) ;;
      raid5)  disk_size_bytes=$((data_total - (data_total / ${#RAID_DISKS[@]}))) ;;
      raid6)  disk_size_bytes=$((data_total - (2 * data_total / ${#RAID_DISKS[@]}))) ;;
      raid10) disk_size_bytes=$((data_total / 2)) ;;
    esac

    storage_desc="RAID ($RAID_LEVEL, ${#RAID_DISKS[@]} disks)"
    reserved_gb=0
  else
    disk_size_bytes=$(lsblk -b -d -n -o SIZE "$DISK")
    storage_desc="$DISK"
    if [[ $UEFI -eq 1 ]]; then
      reserved_gb=1
    else
      reserved_gb=0.5
    fi
  fi

  disk_size_gb=$(awk "BEGIN {printf \"%.2f\", $disk_size_bytes / 1024 / 1024 / 1024}")
  available_gb=$(awk "BEGIN {printf \"%.2f\", $disk_size_gb - $reserved_gb}")

  echo
  echo "========================================"
  echo "   LVM Volume Configuration ($SIMPLE_FS_TYPE)"
  echo "========================================"
  echo
  echo "Storage: $storage_desc (~$disk_size_gb GB)"
  echo "Reserved for boot: $reserved_gb GB"
  echo "Available for LVM: $available_gb GB"
  echo
  echo "Disk layout:"
  echo "  - /boot/efi (300MB) - unencrypted"
  echo "  - /boot (512MB ext4) - unencrypted"
  echo "  - LUKS2 container -> LVM (rest)"
  echo

  # Ask for swap
  echo "----------------------------------------"
  while true; do
    read -r -p "Create swap volume? (y/n): " SWAP_ANSWER
    case "$SWAP_ANSWER" in
      y|Y|yes|YES)
        while true; do
          read -r -p "Swap size in GB [suggested: 4]: " LVM_SWAP_SIZE
          LVM_SWAP_SIZE="${LVM_SWAP_SIZE:-4}"

          if [[ "$LVM_SWAP_SIZE" =~ ^[0-9]+\.?[0-9]*$ ]]; then
            if awk "BEGIN {exit !($LVM_SWAP_SIZE >= 0.5 && $LVM_SWAP_SIZE <= $available_gb)}"; then
              available_gb=$(awk "BEGIN {printf \"%.2f\", $available_gb - $LVM_SWAP_SIZE}")
              info "Swap: ${LVM_SWAP_SIZE} GB"
              break
            else
              echo "[ERROR] Size must be between 0.5 and $available_gb GB"
            fi
          else
            echo "[ERROR] Invalid number"
          fi
        done
        break
        ;;
      n|N|no|NO)
        LVM_SWAP_SIZE=0
        info "No swap volume"
        break
        ;;
      *)
        echo "[ERROR] Please answer y or n"
        ;;
    esac
  done

  echo
  echo "Available space: $available_gb GB"
  echo

  # Volume loop
  echo "----------------------------------------"
  echo "Define logical volumes (max 10)"
  echo "Root (/) is mandatory"
  echo "----------------------------------------"
  echo

  local vol_count=0
  local root_defined=false

  while [[ $vol_count -lt 10 ]]; do
    # Ask for mount point
    local mp=""
    while true; do
      read -r -p "Mount point (e.g., /, /home, /var) or 'done' to finish: " mp

      [[ "$mp" == "done" ]] && break 2
      [[ "$mp" == "q" || "$mp" == "quit" ]] && { info "Aborted by user."; exit 0; }

      # Validate mount point format
      if [[ ! "$mp" =~ ^/ ]]; then
        echo "[ERROR] Mount point must start with /"
        continue
      fi

      # Check for duplicates
      local duplicate=false
      for existing in "${LVM_LV_MP[@]}"; do
        if [[ "$existing" == "$mp" ]]; then
          duplicate=true
          break
        fi
      done

      if [[ "$duplicate" == true ]]; then
        echo "[ERROR] Mount point '$mp' already defined"
        continue
      fi

      break
    done

    # Generate LV name from mount point
    local lv_name
    if [[ "$mp" == "/" ]]; then
      lv_name="root"
    else
      lv_name="${mp//\//-}"  # Replace / with -
      lv_name="${lv_name#-}"  # Remove leading -
      lv_name="${lv_name//-/_}"  # Replace remaining - with _
    fi

    # Ask for size
    local size=""
    local size_mib=""
    while true; do
      echo "Available: $available_gb GB"
      read -r -p "Size in GB (or 'rest' for remaining space): " size

      if [[ "$size" == "rest" ]]; then
        size="$available_gb"
        size_mib="REST"
        info "Using all remaining space: $size GB"
        available_gb="0.00"
        break
      fi

      if [[ "$size" =~ ^[0-9]+\.?[0-9]*$ ]]; then
        # Minimum 1GB (10GB for root)
        local min_size=1
        [[ "$mp" == "/" ]] && min_size=10

        # Check minimum
        if awk "BEGIN {exit !($size < $min_size)}"; then
          echo "[ERROR] Minimum size is $min_size GB"
          continue
        fi

        # If user asks for more than available, use all available
        if awk "BEGIN {exit !($size >= $available_gb)}"; then
          size="$available_gb"
          size_mib="REST"
          info "Adjusted to all remaining space: $size GB"
          available_gb="0.00"
          break
        fi

        # Calculate remainder
        local remainder
        remainder=$(awk "BEGIN {printf \"%.2f\", $available_gb - $size}")

        # If remainder < 1GB, absorb it
        if awk "BEGIN {exit !($remainder > 0 && $remainder < 1)}"; then
          info "Remainder ($remainder GB) < 1GB, absorbing into this volume"
          size="$available_gb"
          size_mib="REST"
          available_gb="0.00"
        else
          # Convert GB to MiB (integer)
          size_mib=$(awk "BEGIN {printf \"%.0f\", $size * 1024}")
          available_gb="$remainder"
        fi
        break
      else
        echo "[ERROR] Invalid number"
      fi
    done

    # Store volume info
    LVM_LV_NAMES+=("$lv_name")
    LVM_LV_SIZES_MIB+=("$size_mib")
    LVM_LV_MP+=("$mp")
    vol_count=$((vol_count + 1))

    [[ "$mp" == "/" ]] && root_defined=true

    echo
    info "Volume $vol_count: lv-$lv_name -> $mp (${size} GB, $SIMPLE_FS_TYPE)"
    echo "Remaining space: $available_gb GB"
    echo

    # Check if space left
    if awk "BEGIN {exit !($available_gb < 1)}"; then
      info "Less than 1 GB remaining, finishing volume setup"
      break
    fi

    # Ask to continue only if root defined
    if [[ "$root_defined" == true ]]; then
      while true; do
        read -r -p "Add another volume? (y/n): " MORE
        case "$MORE" in
          y|Y) break ;;
          n|N) break 2 ;;
          *) echo "[ERROR] Please answer y or n" ;;
        esac
      done
    fi
  done

  # Validate root exists
  if [[ "$root_defined" != true ]]; then
    die "Root volume (/) is mandatory"
  fi

  # Show summary
  echo
  echo "========================================"
  echo "       LUKS + LVM Volume Summary"
  echo "========================================"
  echo
  echo "Encryption: LUKS2 on single partition"
  echo "Volume Group: $VG_NAME"
  echo
  if [[ $UEFI -eq 1 ]]; then
    echo "  /boot/efi    300 MB   (FAT32, unencrypted)"
  fi
  echo "  /boot        512 MB   (ext4, unencrypted)"
  echo "  [LUKS2 container]"
  if [[ "$LVM_SWAP_SIZE" != "0" ]]; then
    echo "    lv-swap    $LVM_SWAP_SIZE GB   (swap)"
  fi
  for i in "${!LVM_LV_MP[@]}"; do
    local size_display
    if [[ "${LVM_LV_SIZES_MIB[$i]}" == "REST" ]]; then
      size_display="(rest)"
    else
      size_display="$(awk "BEGIN {printf \"%.1f\", ${LVM_LV_SIZES_MIB[$i]} / 1024}") GB"
    fi
    printf "    lv-%-8s %-10s (%s) -> %s\n" "${LVM_LV_NAMES[$i]}" "$size_display" "$SIMPLE_FS_TYPE" "${LVM_LV_MP[$i]}"
  done
  echo "========================================"
  echo
}

# Function to configure LVM partitions WITHOUT encryption (ext4/xfs)
configure_lvm_partitions() {
  local disk_size_bytes disk_size_gb reserved_gb available_gb
  local storage_desc storage_device

  # Determine storage source (RAID or single disk)
  # Determine storage source (RAID or single disk)
  if [[ "$RAID_ENABLED" -eq 1 ]]; then
    # For RAID with redundancy, EFI+boot partitions exist on EACH disk
    # Calculate data partition size per disk first, then apply RAID factor

    local reserved_per_disk_bytes
    if [[ $UEFI -eq 1 ]]; then
      # 512MB EFI + 1GB boot = 1.5GB per disk
      reserved_per_disk_bytes=$((512*1024*1024 + 1024*1024*1024))
    else
      # 1MB BIOS + 1GB boot = ~1GB per disk
      reserved_per_disk_bytes=$((1*1024*1024 + 1024*1024*1024))
    fi

    # Calculate total DATA partition space (after subtracting boot from each disk)
    local data_total=0
    for d in "${RAID_DISKS[@]}"; do
      local dsize=$(lsblk -b -d -n -o SIZE "$d")
      if [[ "$RAID_LEVEL" == "raid0" ]]; then
        # RAID0: only first disk has boot partitions
        if [[ "$d" == "${RAID_DISKS[0]}" ]]; then
          data_total=$((data_total + dsize - reserved_per_disk_bytes))
        else
          data_total=$((data_total + dsize))
        fi
      else
        # RAID1/5/6/10: all disks have boot partitions
        data_total=$((data_total + dsize - reserved_per_disk_bytes))
      fi
    done

    # Apply RAID factor to data partitions total
    case "$RAID_LEVEL" in
      raid0)  disk_size_bytes=$data_total ;;
      raid1)  disk_size_bytes=$((data_total / ${#RAID_DISKS[@]})) ;;
      raid5)  disk_size_bytes=$((data_total - (data_total / ${#RAID_DISKS[@]}))) ;;
      raid6)  disk_size_bytes=$((data_total - (2 * data_total / ${#RAID_DISKS[@]}))) ;;
      raid10) disk_size_bytes=$((data_total / 2)) ;;
    esac

    storage_desc="RAID ($RAID_LEVEL, ${#RAID_DISKS[@]} disks)"
    storage_device="$RAID_DEVICE"
    reserved_gb=0  # Already subtracted above
  else
    disk_size_bytes=$(lsblk -b -d -n -o SIZE "$DISK")
    storage_desc="$DISK"
    storage_device="$DISK"
    # Reserved for single disk
    if [[ $UEFI -eq 1 ]]; then
      reserved_gb=1
    else
      reserved_gb=0.5
    fi
  fi

  disk_size_gb=$(awk "BEGIN {printf \"%.2f\", $disk_size_bytes / 1024 / 1024 / 1024}")
  available_gb=$(awk "BEGIN {printf \"%.2f\", $disk_size_gb - $reserved_gb}")

  echo
  echo "========================================"
  echo "   LVM Volume Configuration ($SIMPLE_FS_TYPE)"
  echo "========================================"
  echo
  echo "Storage: $storage_desc (~$disk_size_gb GB)"
  echo "Reserved for boot: $reserved_gb GB"
  echo "Available for LVM: $available_gb GB"
  echo
  echo "Disk layout:"
  if [[ $UEFI -eq 1 ]]; then
    echo "  - /boot/efi (300MB FAT32)"
  fi
  echo "  - /boot (512MB ext4)"
  if [[ "$RAID_ENABLED" -eq 1 ]]; then
    echo "  - RAID ($RAID_LEVEL) -> LVM (rest)"
  else
    echo "  - LVM partition (rest)"
  fi
  echo

  # Ask for swap
  echo "----------------------------------------"
  while true; do
    read -r -p "Create swap volume? (y/n): " SWAP_ANSWER
    case "$SWAP_ANSWER" in
      y|Y|yes|YES)
        while true; do
          read -r -p "Swap size in GB [suggested: 4]: " LVM_SWAP_SIZE
          LVM_SWAP_SIZE="${LVM_SWAP_SIZE:-4}"

          if [[ "$LVM_SWAP_SIZE" =~ ^[0-9]+\.?[0-9]*$ ]]; then
            if awk "BEGIN {exit !($LVM_SWAP_SIZE >= 0.5 && $LVM_SWAP_SIZE <= $available_gb)}"; then
              available_gb=$(awk "BEGIN {printf \"%.2f\", $available_gb - $LVM_SWAP_SIZE}")
              info "Swap: ${LVM_SWAP_SIZE} GB"
              break
            else
              echo "[ERROR] Size must be between 0.5 and $available_gb GB"
            fi
          else
            echo "[ERROR] Invalid number"
          fi
        done
        break
        ;;
      n|N|no|NO)
        LVM_SWAP_SIZE=0
        info "No swap volume"
        break
        ;;
      *)
        echo "[ERROR] Please answer y or n"
        ;;
    esac
  done

  echo
  echo "Available space: $available_gb GB"
  echo

  # Volume loop
  echo "----------------------------------------"
  echo "Define logical volumes (max 10)"
  echo "Root (/) is mandatory"
  echo "----------------------------------------"
  echo

  local vol_count=0
  local root_defined=false

  while [[ $vol_count -lt 10 ]]; do
    # Ask for mount point
    local mp=""
    while true; do
      read -r -p "Mount point (e.g., /, /home, /var) or 'done' to finish: " mp

      [[ "$mp" == "done" ]] && break 2
      [[ "$mp" == "q" || "$mp" == "quit" ]] && { info "Aborted by user."; exit 0; }

      # Validate mount point format
      if [[ ! "$mp" =~ ^/ ]]; then
        echo "[ERROR] Mount point must start with /"
        continue
      fi

      # Check for duplicates
      local duplicate=false
      for existing in "${LVM_LV_MP[@]}"; do
        if [[ "$existing" == "$mp" ]]; then
          duplicate=true
          break
        fi
      done

      if [[ "$duplicate" == true ]]; then
        echo "[ERROR] Mount point '$mp' already defined"
        continue
      fi

      # Skip /boot and /boot/efi
      if [[ "$mp" == "/boot" || "$mp" == "/boot/efi" ]]; then
        echo "[ERROR] /boot and /boot/efi are configured automatically"
        continue
      fi

      break
    done

    [[ "$mp" == "done" ]] && break

    # Track root
    [[ "$mp" == "/" ]] && root_defined=true

    # Ask for size
    local size_gb=""
    while true; do
      local size_prompt="Size in GB (or 'rest' for remaining space)"
      read -r -p "$size_prompt: " size_gb

      [[ "$size_gb" == "q" || "$size_gb" == "quit" ]] && { info "Aborted by user."; exit 0; }

      if [[ "$size_gb" == "rest" ]]; then
        info "Using remaining space (~$available_gb GB)"
        size_mib="REST"
        available_gb=0
        break
      fi

      if [[ "$size_gb" =~ ^[0-9]+\.?[0-9]*$ ]]; then
        if awk "BEGIN {exit !($size_gb >= 1)}"; then
          # If user asks for >= available, use REST (100%FREE)
          if awk "BEGIN {exit !($size_gb >= $available_gb)}"; then
            info "Adjusted to remaining space (~$available_gb GB)"
            size_mib="REST"
            available_gb=0
            break
          fi
          # If remainder < 1GB, absorb it and use REST
          local remainder=$(awk "BEGIN {printf \"%.2f\", $available_gb - $size_gb}")
          if awk "BEGIN {exit !($remainder < 1)}"; then
            info "Absorbing remaining space (~$available_gb GB)"
            size_mib="REST"
            available_gb=0
            break
          fi
          available_gb="$remainder"
          break
        else
          echo "[ERROR] Size must be at least 1 GB"
        fi
      else
        echo "[ERROR] Invalid number (or 'rest')"
      fi
    done

    # Generate LV name from mount point
    local lv_name
    if [[ "$mp" == "/" ]]; then
      lv_name="root"
    else
      lv_name="${mp//\//-}"
      lv_name="${lv_name#-}"
      lv_name="${lv_name//-/_}"
    fi

    # Convert GB to MiB for LVM (unless REST)
    if [[ "${size_mib:-}" != "REST" ]]; then
      size_mib=$(awk "BEGIN {printf \"%.0f\", $size_gb * 1024}")
    fi

    LVM_LV_NAMES+=("$lv_name")
    LVM_LV_SIZES_MIB+=("$size_mib")
    LVM_LV_MP+=("$mp")

    vol_count=$((vol_count + 1))

    # Show volume info
    if [[ "$size_mib" == "REST" ]]; then
      info "Volume $vol_count: lv-$lv_name -> $mp (rest, $SIMPLE_FS_TYPE)"
    else
      local size_display=$(awk "BEGIN {printf \"%.1f\", $size_mib / 1024}")
      info "Volume $vol_count: lv-$lv_name -> $mp ($size_display GB, $SIMPLE_FS_TYPE)"
    fi
    echo "Remaining space: $available_gb GB"

    # Check if space exhausted
    if awk "BEGIN {exit !($available_gb < 1)}"; then
      info "No more space available"
      break
    fi

    # Ask to continue (unless this was root and it's the first volume)
    if [[ "$root_defined" == true ]]; then
      while true; do
        read -r -p "Add another volume? (y/n): " MORE
        case "$MORE" in
          y|Y) break ;;
          n|N) break 2 ;;
          *) echo "[ERROR] Please answer y or n" ;;
        esac
      done
    fi
  done

  # Validate root exists
  if [[ "$root_defined" != true ]]; then
    die "Root volume (/) is mandatory"
  fi

  # Show summary
  echo
  echo "========================================"
  echo "         LVM Volume Summary"
  echo "========================================"
  echo
  if [[ "$RAID_ENABLED" -eq 1 ]]; then
    echo "Storage: RAID $RAID_LEVEL (${#RAID_DISKS[@]} disks)"
  fi
  echo "Volume Group: $VG_NAME"
  echo
  if [[ $UEFI -eq 1 ]]; then
    echo "  /boot/efi    300 MB   (FAT32)"
  fi
  echo "  /boot        512 MB   (ext4)"
  if [[ "$LVM_SWAP_SIZE" != "0" ]]; then
    echo "  lv-swap      $LVM_SWAP_SIZE GB   (swap)"
  fi
  for i in "${!LVM_LV_MP[@]}"; do
    local size_display
    if [[ "${LVM_LV_SIZES_MIB[$i]}" == "REST" ]]; then
      size_display="(rest)"
    else
      size_display="$(awk "BEGIN {printf \"%.1f\", ${LVM_LV_SIZES_MIB[$i]} / 1024}") GB"
    fi
    printf "  lv-%-10s %-10s (%s) -> %s\n" "${LVM_LV_NAMES[$i]}" "$size_display" "$SIMPLE_FS_TYPE" "${LVM_LV_MP[$i]}"
  done
  echo "========================================"
  echo
}

# Detect firmware mode
UEFI=0
[[ -d /sys/firmware/efi/efivars ]] && UEFI=1
info "Firmware mode: $([[ $UEFI -eq 1 ]] && echo UEFI || echo BIOS)"

# Configure simple FS partitions (interactive) - needs disk selected first
if [[ "$FS_TYPE" == "simple" ]]; then
  while true; do
    if [[ "$LUKS_ENABLED" -eq 1 ]]; then
      configure_luks_lvm_partitions
    elif [[ "$LVM_ENABLED" -eq 1 ]]; then
      configure_lvm_partitions
    else
      configure_simple_partitions
    fi

    echo
    while true; do
      read -r -p "Proceed with installation? (y=yes, n=reconfigure partitions, q=quit): " PART_CONFIRM
      case "$PART_CONFIRM" in
        y|Y) break 2 ;;
        n|N) info "Reconfiguring partitions..."; break ;;
        q|quit) info "Aborted by user."; exit 0 ;;
        *) echo "[ERROR] Please answer y, n, or q." ;;
      esac
    done

    # Reset partition arrays for reconfiguration
    SIMPLE_PARTS_MP=()
    SIMPLE_PARTS_SIZE=()
    SIMPLE_PARTS_DEV=()
    SIMPLE_PARTS_SIZE_MIB=()
    SWAP_SIZE=0
    LVM_LV_NAMES=()
    LVM_LV_SIZES_MIB=()
    LVM_LV_MP=()
    LVM_SWAP_SIZE=0
  done
fi

# Disable CTRL+C during installation
stty intr '' -echoctl

# Mount efivarfs on the LIVE system if in UEFI mode
if [[ $UEFI -eq 1 ]]; then
  mkdir -p /sys/firmware/efi/efivars
  mountpoint -q /sys/firmware/efi/efivars || mount -t efivarfs efivarfs /sys/firmware/efi/efivars || true
fi

# Locate squashfs
SQUASH=""
if [[ -f /run/live/medium/live/filesystem.squashfs ]]; then
  SQUASH="/run/live/medium/live/filesystem.squashfs"
elif [[ -f /run/live/rootfs/filesystem.squashfs ]]; then
  SQUASH="/run/live/rootfs/filesystem.squashfs"
else
  SQUASH="$(find /run/live -maxdepth 5 -type f -name filesystem.squashfs -print -quit 2>/dev/null || true)"
fi
[[ -n "$SQUASH" && -f "$SQUASH" ]] || die "filesystem.squashfs not found under /run/live"
info "Installing from squashfs: $SQUASH"

if [[ "$FS_TYPE" == "zfs" ]]; then
  # Safety fallback
  [[ "${#ZFS_DISKS[@]}" -gt 0 ]] || ZFS_DISKS=("$DISK")

  # Clean up existing LVM (if any)
  if command -v vgdisplay >/dev/null 2>&1; then
    for vg in $(vgs --noheadings -o vg_name 2>/dev/null | tr -d ' '); do
      info "Removing existing VG: $vg"
      vgchange -an "$vg" 2>/dev/null || true
      vgremove -ff "$vg" 2>/dev/null || true
    done
  fi
  for pv in $(pvs --noheadings -o pv_name 2>/dev/null | tr -d ' '); do
    pvremove -ff "$pv" 2>/dev/null || true
  done

  # Clean up existing mdadm arrays
  for md in /dev/md/*; do
    [[ -b "$md" ]] && mdadm --stop "$md" 2>/dev/null || true
  done
  for md in /dev/md[0-9]*; do
    [[ -b "$md" ]] && mdadm --stop "$md" 2>/dev/null || true
  done

  for d in "${ZFS_DISKS[@]}"; do
    # Zero mdadm superblocks on all partitions
    for part in "${d}"*; do
      [[ -b "$part" && "$part" != "$d" ]] && mdadm --zero-superblock "$part" 2>/dev/null || true
    done
    mdadm --zero-superblock "$d" 2>/dev/null || true

    info "Wiping old signatures on $d..."
    wipefs -a "$d" || true

    info "Creating GPT on $d..."
    sgdisk --zap-all "$d"
    sgdisk -og "$d"
  done
else
  # Clean up existing LVM (if any)
  if command -v vgdisplay >/dev/null 2>&1; then
    for vg in $(vgs --noheadings -o vg_name 2>/dev/null | tr -d ' '); do
      info "Removing existing VG: $vg"
      vgchange -an "$vg" 2>/dev/null || true
      vgremove -ff "$vg" 2>/dev/null || true
    done
  fi
  for pv in $(pvs --noheadings -o pv_name 2>/dev/null | tr -d ' '); do
    pvremove -ff "$pv" 2>/dev/null || true
  done

  # Clean up orphaned RAID metadata on inactive arrays
  for md in /dev/md/*; do
    if [[ -b "$md" ]] && mdadm --detail "$md" 2>/dev/null | grep -qi "state.*inactive"; then
      info "Cleaning orphaned RAID metadata on $md..."
      devs=$(mdadm --detail "$md" 2>/dev/null | awk '/\/dev\/[sv]d/{print $NF}')
      mdadm --stop "$md" 2>/dev/null || true
      for dev in $devs; do
        [[ -b "$dev" ]] && wipefs -a -f "$dev" 2>/dev/null || true
      done
    else
      [[ -b "$md" ]] && mdadm --stop "$md" 2>/dev/null || true
    fi
  done
  for md in /dev/md[0-9]*; do
    if [[ -b "$md" ]] && mdadm --detail "$md" 2>/dev/null | grep -qi "state.*inactive"; then
      info "Cleaning orphaned RAID metadata on $md..."
      devs=$(mdadm --detail "$md" 2>/dev/null | awk '/\/dev\/[sv]d/{print $NF}')
      mdadm --stop "$md" 2>/dev/null || true
      for dev in $devs; do
        [[ -b "$dev" ]] && wipefs -a -f "$dev" 2>/dev/null || true
      done
    else
      [[ -b "$md" ]] && mdadm --stop "$md" 2>/dev/null || true
    fi
  done
  # Zero mdadm superblocks on all partitions of the disk
  for part in "${DISK}"*; do
    [[ -b "$part" && "$part" != "$DISK" ]] && mdadm --zero-superblock "$part" 2>/dev/null || true
  done
  # Also zero on the disk itself (for whole-disk arrays)
  mdadm --zero-superblock "$DISK" 2>/dev/null || true

  info "Wiping old signatures..."
  wipefs -a "$DISK" || true

  info "Creating GPT..."
  sgdisk --zap-all "$DISK"
  sgdisk -og "$DISK"
fi

part_path() {
  local disk="$DISK"
  local n=""

  if [[ $# -eq 1 ]]; then
    n="$1"
  else
    disk="$1"
    n="$2"
  fi

  if [[ "$disk" =~ nvme ]] || [[ "$disk" =~ mmcblk ]]; then
    echo "${disk}p${n}"
  else
    echo "${disk}${n}"
  fi
}

if [[ "$FS_TYPE" == "simple" ]]; then
  if [[ "$RAID_ENABLED" -eq 1 ]]; then
    # ============================================================
    # RAID partitioning (mdadm) - for ext4/xfs with LVM
    # ============================================================
    info "Creating RAID partition layout on ${#RAID_DISKS[@]} disks..."

    # Arrays for RAID partitions
    declare -a EFI_PARTS=()
    declare -a BOOT_RAID_PARTS=()
    declare -a DATA_RAID_PARTS=()

    # Clean up orphaned RAID metadata on inactive arrays
    info "Stopping any existing RAID arrays..."
    for md in /dev/md[0-9]*; do
      if [[ -b "$md" ]] && mdadm --detail "$md" 2>/dev/null | grep -qi "state.*inactive"; then
        info "Cleaning orphaned RAID metadata on $md..."
        devs=$(mdadm --detail "$md" 2>/dev/null | awk '/\/dev\/[sv]d/{print $NF}')
        mdadm --stop "$md" 2>/dev/null || true
        for dev in $devs; do
          [[ -b "$dev" ]] && wipefs -a -f "$dev" 2>/dev/null || true
        done
      else
        [[ -b "$md" ]] && mdadm --stop "$md" 2>/dev/null || true
      fi
    done

    # Clean up existing LVM on RAID disks
    for d in "${RAID_DISKS[@]}"; do
      # Deactivate VGs that use this disk
      for vg in $(pvs --noheadings -o vg_name "$d"* 2>/dev/null | tr -d ' ' | sort -u); do
        [[ -n "$vg" ]] && vgchange -an "$vg" 2>/dev/null || true
        [[ -n "$vg" ]] && vgremove -ff "$vg" 2>/dev/null || true
      done
      # Remove PVs on this disk
      for pv in $(pvs --noheadings -o pv_name 2>/dev/null | grep "$d" | tr -d ' '); do
        pvremove -ff "$pv" 2>/dev/null || true
      done
      # Zero superblocks on all partitions
      for part in "$d"*; do
        [[ -b "$part" && "$part" != "$d" ]] && mdadm --zero-superblock "$part" 2>/dev/null || true
      done
    done
    sleep 1

    # Wipe all RAID disks
    for d in "${RAID_DISKS[@]}"; do
      info "  [$d] Wiping disk..."
      wipefs -a "$d" || true
      sgdisk --zap-all "$d"
      sgdisk -og "$d"
    done

    if [[ "$RAID_LEVEL" == "raid0" ]]; then
      # ============================================================
      # RAID0: No redundancy - boot on first disk only
      # ============================================================
      BOOT_DISK="${RAID_DISKS[0]}"
      part_num=1

      if [[ $UEFI -eq 1 ]]; then
        info "  [$BOOT_DISK] Creating EFI partition..."
        sgdisk -n ${part_num}:1MiB:+300MiB -t ${part_num}:EF00 -c ${part_num}:"EFI" "$BOOT_DISK"
        EFI_PART="$(part_path "$BOOT_DISK" $part_num)"
        ((part_num++))
      else
        info "  [$BOOT_DISK] Creating BIOS boot partition..."
        sgdisk -n ${part_num}:1MiB:+1MiB -t ${part_num}:EF02 -c ${part_num}:"BIOS_GRUB" "$BOOT_DISK"
        ((part_num++))
      fi

      info "  [$BOOT_DISK] Creating /boot partition..."
      sgdisk -n ${part_num}:0:+512MiB -t ${part_num}:8300 -c ${part_num}:"boot" "$BOOT_DISK"
      BOOT_PART="$(part_path "$BOOT_DISK" $part_num)"
      ((part_num++))

      # RAID partition on boot disk (rest of disk)
      info "  [$BOOT_DISK] Creating RAID partition..."
      sgdisk -n ${part_num}:0:0 -t ${part_num}:FD00 -c ${part_num}:"raid" "$BOOT_DISK"
      DATA_RAID_PARTS+=("$(part_path "$BOOT_DISK" $part_num)")
      partprobe "$BOOT_DISK" || true

      # Create RAID partition on other disks (entire disk minus alignment)
      for d in "${RAID_DISKS[@]:1}"; do
        info "  [$d] Creating RAID partition..."
        sgdisk -n 1:1MiB:0 -t 1:FD00 -c 1:"raid" "$d"
        DATA_RAID_PARTS+=("$(part_path "$d" 1)")
        partprobe "$d" || true
      done

      sleep 2

      # Create single RAID0 array for data
      RAID_DEVICE="/dev/md0"
      mdadm --stop "$RAID_DEVICE" 2>/dev/null || true
      for p in "${DATA_RAID_PARTS[@]}"; do
        mdadm --zero-superblock "$p" 2>/dev/null || true
      done

      info "Creating RAID0 array (data) with ${#DATA_RAID_PARTS[@]} partitions..."
      mdadm --create --run "$RAID_DEVICE" \
        --level=raid0 \
        --raid-devices="${#DATA_RAID_PARTS[@]}" \
        --metadata=1.2 \
        --homehost=synex \
        --name=synex-data \
        "${DATA_RAID_PARTS[@]}"

    else
      # ============================================================
      # RAID1/5/6/10: Full redundancy - boot/efi on RAID too
      # ============================================================

      declare -a EFI_RAID_PARTS=()

      # Create identical partitions on ALL disks
      for d in "${RAID_DISKS[@]}"; do
        part_num=1

        if [[ $UEFI -eq 1 ]]; then
          info "  [$d] Creating EFI partition..."
          sgdisk -n ${part_num}:1MiB:+512MiB -t ${part_num}:FD00 -c ${part_num}:"EFI" "$d"
          EFI_RAID_PARTS+=("$(part_path "$d" $part_num)")
          ((part_num++))
        else
          info "  [$d] Creating BIOS boot partition..."
          sgdisk -n ${part_num}:1MiB:+1MiB -t ${part_num}:EF02 -c ${part_num}:"BIOS_GRUB" "$d"
          ((part_num++))
        fi

        info "  [$d] Creating /boot partition..."
        sgdisk -n ${part_num}:0:+1GiB -t ${part_num}:FD00 -c ${part_num}:"boot" "$d"
        BOOT_RAID_PARTS+=("$(part_path "$d" $part_num)")
        ((part_num++))

        info "  [$d] Creating data partition..."
        sgdisk -n ${part_num}:0:0 -t ${part_num}:FD00 -c ${part_num}:"raid" "$d"
        DATA_RAID_PARTS+=("$(part_path "$d" $part_num)")

        partprobe "$d" || true
      done

      # Wait for kernel to update partition table
      sleep 2
      partprobe 2>/dev/null || true
      sleep 1

      # Stop any existing arrays
      for md in /dev/md0 /dev/md1 /dev/md2 /dev/md3; do
        mdadm --stop "$md" 2>/dev/null || true
      done
      for p in "${EFI_RAID_PARTS[@]}" "${BOOT_RAID_PARTS[@]}" "${DATA_RAID_PARTS[@]}"; do
        mdadm --zero-superblock "$p" 2>/dev/null || true
      done

      # Clean up any remaining inactive arrays (orphaned RAID from non-selected disks)
      for md in /dev/md[0-9]*; do
        if [[ -b "$md" ]] && mdadm --detail "$md" 2>/dev/null | grep -qi "state.*inactive"; then
          info "Cleaning orphaned RAID metadata on $md..."
          devs=$(mdadm --detail "$md" 2>/dev/null | awk '/\/dev\/[sv]d/{print $NF}')
          mdadm --stop "$md" 2>/dev/null || true
          for dev in $devs; do
            [[ -b "$dev" ]] && wipefs -a -f "$dev" 2>/dev/null || true
          done
        fi
      done

      if [[ $UEFI -eq 1 ]]; then
        # Create RAID1 for /boot/efi (metadata=1.0 so UEFI can see FAT32)
        info "Creating RAID1 array for /boot/efi with ${#EFI_RAID_PARTS[@]} partitions..."
        mdadm --create --run --bitmap=internal /dev/md0 \
          --level=raid1 \
          --raid-devices="${#EFI_RAID_PARTS[@]}" \
          --metadata=1.0 \
          --homehost=synex \
          --name=synex-efi \
          "${EFI_RAID_PARTS[@]}"
        EFI_PART="/dev/md0"

        # Create RAID1 for /boot
        info "Creating RAID1 array for /boot with ${#BOOT_RAID_PARTS[@]} partitions..."
        mdadm --create --run --bitmap=internal /dev/md1 \
          --level=raid1 \
          --raid-devices="${#BOOT_RAID_PARTS[@]}" \
          --metadata=1.0 \
          --homehost=synex \
          --name=synex-boot \
          "${BOOT_RAID_PARTS[@]}"
        BOOT_PART="/dev/md1"

        # Create data array with selected RAID level
        RAID_DEVICE="/dev/md2"
      else
        # BIOS: no EFI array needed
        # Create RAID1 for /boot
        info "Creating RAID1 array for /boot with ${#BOOT_RAID_PARTS[@]} partitions..."
        mdadm --create --run --bitmap=internal /dev/md0 \
          --level=raid1 \
          --raid-devices="${#BOOT_RAID_PARTS[@]}" \
          --metadata=1.0 \
          --homehost=synex \
          --name=synex-boot \
          "${BOOT_RAID_PARTS[@]}"
        BOOT_PART="/dev/md0"

        # Create data array with selected RAID level
        RAID_DEVICE="/dev/md1"
      fi

      info "Creating $RAID_LEVEL array (data) with ${#DATA_RAID_PARTS[@]} partitions..."
      mdadm --create --run --bitmap=internal "$RAID_DEVICE" \
        --level="$RAID_LEVEL" \
        --raid-devices="${#DATA_RAID_PARTS[@]}" \
        --metadata=1.2 \
        --homehost=synex \
        --name=synex-data \
        "${DATA_RAID_PARTS[@]}"
    fi

    # Wait for arrays to be ready
    info "Waiting for RAID arrays..."
    sleep 3

    # Verify data array
    if [[ ! -b "$RAID_DEVICE" ]]; then
      die "RAID array $RAID_DEVICE not created"
    fi
    info "RAID arrays created:"
    cat /proc/mdstat

    if [[ "$LUKS_ENABLED" -eq 1 ]]; then
      # ============================================================
      # RAID -> LUKS -> LVM
      # ============================================================
      info "Setting up LUKS on RAID array..."

      echo -n "$LUKS_PASSWORD" | cryptsetup luksFormat --type luks2 --batch-mode "$RAID_DEVICE" -
      echo -n "$LUKS_PASSWORD" | cryptsetup open "$RAID_DEVICE" "$LUKS_MAPPER" -

      info "Creating LVM on LUKS container..."
      pvcreate -ff -y "/dev/mapper/$LUKS_MAPPER"
      vgcreate "$VG_NAME" "/dev/mapper/$LUKS_MAPPER"

      LUKS_PART="$RAID_DEVICE"  # For crypttab later
    else
      # ============================================================
      # RAID -> LVM (no encryption)
      # ============================================================
      info "Creating LVM directly on RAID array..."
      pvcreate -ff -y "$RAID_DEVICE"
      vgcreate "$VG_NAME" "$RAID_DEVICE"
    fi

    # Create swap LV if requested
    if [[ "$LVM_SWAP_SIZE" != "0" ]]; then
      swap_mib=$(awk "BEGIN {printf \"%.0f\", $LVM_SWAP_SIZE * 1024}")
      info "Creating swap volume: lv-swap (${LVM_SWAP_SIZE} GB)"
      lvcreate -y -L "${swap_mib}MiB" -n "lv-swap" "$VG_NAME"
      LVM_SWAP_DEV="/dev/$VG_NAME/lv-swap"
    fi

    # Create data LVs
    for i in "${!LVM_LV_NAMES[@]}"; do
      lv_name="${LVM_LV_NAMES[$i]}"
      size_mib="${LVM_LV_SIZES_MIB[$i]}"

      if [[ "$size_mib" == "REST" ]]; then
        info "Creating volume: lv-$lv_name (remaining space)"
        lvcreate -y -l 100%FREE -n "lv-$lv_name" "$VG_NAME"
      else
        info "Creating volume: lv-$lv_name (${size_mib} MiB)"
        lvcreate -y -L "${size_mib}MiB" -n "lv-$lv_name" "$VG_NAME"
      fi
      LVM_LV_DEV+=("/dev/$VG_NAME/lv-$lv_name")
    done

    info "RAID + LVM setup complete"
    lsblk "$RAID_DEVICE"

    # Save mdadm configuration
    mkdir -p /target/etc/mdadm
    mdadm --detail --scan 2>/dev/null | grep -v "INACTIVE-ARRAY" > /target/etc/mdadm/mdadm.conf || true

  elif [[ "$LUKS_ENABLED" -eq 1 ]]; then
    # ============================================================
    # Single disk: LUKS + LVM partitioning (ext4/xfs)
    # ============================================================
    part_num=1

    if [[ $UEFI -eq 1 ]]; then
      info "Creating UEFI + LUKS partitions..."
      sgdisk -n ${part_num}:1MiB:+300MiB -t ${part_num}:EF00 -c ${part_num}:"EFI" "$DISK"
      EFI_PART="$(part_path $part_num)"
      ((part_num++))
    else
      info "Creating BIOS + LUKS partitions..."
      sgdisk -n ${part_num}:1MiB:+1MiB -t ${part_num}:EF02 -c ${part_num}:"BIOS_GRUB" "$DISK"
      ((part_num++))
    fi

    sgdisk -n ${part_num}:0:+512MiB -t ${part_num}:8300 -c ${part_num}:"boot" "$DISK"
    BOOT_PART="$(part_path $part_num)"
    ((part_num++))

    sgdisk -n ${part_num}:0:0 -t ${part_num}:8309 -c ${part_num}:"luks" "$DISK"
    LUKS_PART="$(part_path $part_num)"

    partprobe "$DISK" || true
    sleep 2

    info "Creating LUKS2 container on $LUKS_PART..."
    echo -n "$LUKS_PASSWORD" | cryptsetup luksFormat --type luks2 --batch-mode "$LUKS_PART" -

    info "Opening LUKS container..."
    echo -n "$LUKS_PASSWORD" | cryptsetup open "$LUKS_PART" "$LUKS_MAPPER" -

    info "Creating LVM physical volume..."
    pvcreate "/dev/mapper/$LUKS_MAPPER"

    info "Creating volume group: $VG_NAME"
    vgcreate "$VG_NAME" "/dev/mapper/$LUKS_MAPPER"

    if [[ "$LVM_SWAP_SIZE" != "0" ]]; then
      swap_mib=$(awk "BEGIN {printf \"%.0f\", $LVM_SWAP_SIZE * 1024}")
      info "Creating swap volume: lv-swap (${LVM_SWAP_SIZE} GB)"
      lvcreate -y -L "${swap_mib}MiB" -n "lv-swap" "$VG_NAME"
      LVM_SWAP_DEV="/dev/$VG_NAME/lv-swap"
    fi

    for i in "${!LVM_LV_NAMES[@]}"; do
      lv_name="${LVM_LV_NAMES[$i]}"
      size_mib="${LVM_LV_SIZES_MIB[$i]}"

      if [[ "$size_mib" == "REST" ]]; then
        info "Creating volume: lv-$lv_name (remaining space)"
        lvcreate -y -l 100%FREE -n "lv-$lv_name" "$VG_NAME"
      else
        info "Creating volume: lv-$lv_name (${size_mib} MiB)"
        lvcreate -y -L "${size_mib}MiB" -n "lv-$lv_name" "$VG_NAME"
      fi
      LVM_LV_DEV+=("/dev/$VG_NAME/lv-$lv_name")
    done

    info "LVM setup complete"
    lsblk "/dev/mapper/$LUKS_MAPPER"

  elif [[ "$LVM_ENABLED" -eq 1 ]]; then
    # ============================================================
    # Single disk: LVM without encryption (ext4/xfs)
    # ============================================================
    part_num=1

    if [[ $UEFI -eq 1 ]]; then
      info "Creating UEFI + LVM partitions..."
      sgdisk -n ${part_num}:1MiB:+300MiB -t ${part_num}:EF00 -c ${part_num}:"EFI" "$DISK"
      EFI_PART="$(part_path $part_num)"
      ((part_num++))
    else
      info "Creating BIOS + LVM partitions..."
      sgdisk -n ${part_num}:1MiB:+1MiB -t ${part_num}:EF02 -c ${part_num}:"BIOS_GRUB" "$DISK"
      ((part_num++))
    fi

    sgdisk -n ${part_num}:0:+512MiB -t ${part_num}:8300 -c ${part_num}:"boot" "$DISK"
    BOOT_PART="$(part_path $part_num)"
    ((part_num++))

    # LVM partition (rest of disk)
    sgdisk -n ${part_num}:0:0 -t ${part_num}:8E00 -c ${part_num}:"lvm" "$DISK"
    LVM_PART="$(part_path $part_num)"

    partprobe "$DISK" || true
    sleep 2

    info "Creating LVM physical volume on $LVM_PART..."
    pvcreate -ff -y "$LVM_PART"

    info "Creating volume group: $VG_NAME"
    vgcreate "$VG_NAME" "$LVM_PART"

    if [[ "$LVM_SWAP_SIZE" != "0" ]]; then
      swap_mib=$(awk "BEGIN {printf \"%.0f\", $LVM_SWAP_SIZE * 1024}")
      info "Creating swap volume: lv-swap (${LVM_SWAP_SIZE} GB)"
      lvcreate -y -L "${swap_mib}MiB" -n "lv-swap" "$VG_NAME"
      LVM_SWAP_DEV="/dev/$VG_NAME/lv-swap"
    fi

    for i in "${!LVM_LV_NAMES[@]}"; do
      lv_name="${LVM_LV_NAMES[$i]}"
      size_mib="${LVM_LV_SIZES_MIB[$i]}"

      if [[ "$size_mib" == "REST" ]]; then
        info "Creating volume: lv-$lv_name (remaining space)"
        lvcreate -y -l 100%FREE -n "lv-$lv_name" "$VG_NAME"
      else
        info "Creating volume: lv-$lv_name (${size_mib} MiB)"
        lvcreate -y -L "${size_mib}MiB" -n "lv-$lv_name" "$VG_NAME"
      fi
      LVM_LV_DEV+=("/dev/$VG_NAME/lv-$lv_name")
    done

    info "LVM setup complete"
    lsblk "$LVM_PART"

  else
    # ============================================================
    # Single disk: Simple FS partitioning (ext4/XFS) - no LVM
    # ============================================================
    part_num=1
    start_pos="1MiB"

    if [[ $UEFI -eq 1 ]]; then
      info "Creating UEFI partitions..."
      sgdisk -n ${part_num}:${start_pos}:+300MiB -t ${part_num}:EF00 -c ${part_num}:"EFI" "$DISK"
      start_pos="301MiB"
      ((part_num++))
    else
      info "Creating BIOS partitions..."
      sgdisk -n ${part_num}:${start_pos}:+1MiB -t ${part_num}:EF02 -c ${part_num}:"BIOS_GRUB" "$DISK"
      start_pos="2MiB"
      ((part_num++))
    fi

    sgdisk -n ${part_num}:${start_pos}:+512MiB -t ${part_num}:8300 -c ${part_num}:"boot" "$DISK"
    BOOT_PART="$(part_path $part_num)"
    start_pos="0"
    ((part_num++))

    if [[ "$SWAP_SIZE" != "0" ]]; then
      sgdisk -n ${part_num}:0:+${SWAP_SIZE}G -t ${part_num}:8200 -c ${part_num}:"swap" "$DISK"
      SWAP_PART="$(part_path $part_num)"
      ((part_num++))
    fi

    for i in "${!SIMPLE_PARTS_MP[@]}"; do
      mp="${SIMPLE_PARTS_MP[$i]}"
      size="${SIMPLE_PARTS_SIZE[$i]}"
      size_mib="${SIMPLE_PARTS_SIZE_MIB[$i]}"
      label="${mp//\//_}"
      label="${label:-root}"
      label="${label#_}"

      if [[ "$size_mib" == "REST" ]]; then
        sgdisk -n ${part_num}:0:0 -t ${part_num}:8300 -c ${part_num}:"$label" "$DISK"
      else
        sgdisk -n ${part_num}:0:+${size_mib}MiB -t ${part_num}:8300 -c ${part_num}:"$label" "$DISK"
      fi
      SIMPLE_PARTS_DEV+=("$(part_path $part_num)")
      ((part_num++))
    done

    if [[ $UEFI -eq 1 ]]; then
      EFI_PART="$(part_path 1)"
    fi
  fi

elif [[ "$FS_TYPE" == "zfs" ]]; then
  info "Creating ZFS partition layout on all disks (topology=$ZFS_TOPOLOGY)..."

  [[ "${#ZFS_DISKS[@]}" -gt 0 ]] || ZFS_DISKS=("$DISK")

  EFI_PARTS=()
  BOOT_PARTS=()
  ROOT_PARTS=()

  for d in "${ZFS_DISKS[@]}"; do
    if [[ $UEFI -eq 1 ]]; then
      info "  [$d] Creating UEFI partitions..."
      sgdisk -n 1:1MiB:+300MiB -t 1:EF00 -c 1:"EFI"  "$d"
      sgdisk -n 2:0:+1GiB      -t 2:8300 -c 2:"boot" "$d"
      sgdisk -n 3:0:0          -t 3:8300 -c 3:"zfs"  "$d"

      EFI_PARTS+=( "$(part_path "$d" 1)" )
      BOOT_PARTS+=( "$(part_path "$d" 2)" )
      ROOT_PARTS+=( "$(part_path "$d" 3)" )
    else
      info "  [$d] Creating BIOS partitions..."
      sgdisk -n 1:1MiB:+1MiB   -t 1:EF02 -c 1:"BIOS_GRUB" "$d"
      sgdisk -n 2:0:+1GiB      -t 2:8300 -c 2:"boot"     "$d"
      sgdisk -n 3:0:0          -t 3:8300 -c 3:"zfs"      "$d"

      BOOT_PARTS+=( "$(part_path "$d" 2)" )
      ROOT_PARTS+=( "$(part_path "$d" 3)" )
    fi

    partprobe "$d" || true
  done

  sleep 2

  # Phase 1: /boot (+EFI) on first disk only
  BOOT_PART="${BOOT_PARTS[0]}"
  ROOT_PART="${ROOT_PARTS[0]}"
  if [[ $UEFI -eq 1 ]]; then
    EFI_PART="${EFI_PARTS[0]}"
  fi

  [[ -b "$BOOT_PART" ]] || die "Missing BOOT_PART: $BOOT_PART"
  for rp in "${ROOT_PARTS[@]}"; do
    [[ -b "$rp" ]] || die "Missing ZFS root partition: $rp"
  done
  if [[ $UEFI -eq 1 ]]; then
    [[ -b "$EFI_PART" ]] || die "Missing EFI_PART: $EFI_PART"
  fi

elif [[ "$FS_TYPE" == "btrfs" && "$LUKS_ENABLED" -eq 1 ]]; then
  # BTRFS + LUKS partitioning
  if [[ $UEFI -eq 1 ]]; then
    info "Creating UEFI + LUKS partitions for BTRFS..."
    sgdisk -n 1:1MiB:+300MiB -t 1:EF00 -c 1:"EFI" "$DISK"
    sgdisk -n 2:0:+1GiB      -t 2:8300 -c 2:"boot" "$DISK"
    sgdisk -n 3:0:0          -t 3:8309 -c 3:"luks" "$DISK"
  else
    info "Creating BIOS + LUKS partitions for BTRFS..."
    sgdisk -n 1:1MiB:+1MiB   -t 1:EF02 -c 1:"BIOS_GRUB" "$DISK"
    sgdisk -n 2:0:+1GiB      -t 2:8300 -c 2:"boot" "$DISK"
    sgdisk -n 3:0:0          -t 3:8309 -c 3:"luks" "$DISK"
  fi

  partprobe "$DISK" || true
  sleep 2

  # Assign partition variables
  if [[ $UEFI -eq 1 ]]; then
    EFI_PART="$(part_path 1)"
    BOOT_PART="$(part_path 2)"
    LUKS_PART="$(part_path 3)"
  else
    BOOT_PART="$(part_path 2)"
    LUKS_PART="$(part_path 3)"
  fi

  # Setup LUKS
  info "Creating LUKS2 container on $LUKS_PART..."
  echo -n "$LUKS_PASSWORD" | cryptsetup luksFormat --type luks2 --batch-mode "$LUKS_PART" -

  info "Opening LUKS container..."
  echo -n "$LUKS_PASSWORD" | cryptsetup open "$LUKS_PART" "$LUKS_MAPPER" -

  # ROOT_PART is now the opened LUKS container
  ROOT_PART="/dev/mapper/$LUKS_MAPPER"

  info "LUKS container ready: $ROOT_PART"

elif [[ $UEFI -eq 1 ]]; then
  info "Creating UEFI partitions..."
  sgdisk -n 1:1MiB:+300MiB -t 1:EF00 -c 1:"EFI" "$DISK"
  sgdisk -n 2:0:+1GiB      -t 2:8300 -c 2:"boot" "$DISK"
  sgdisk -n 3:0:0          -t 3:8300 -c 3:"$FS_TYPE" "$DISK"
else
  info "Creating BIOS partitions..."
  sgdisk -n 1:1MiB:+1MiB   -t 1:EF02 -c 1:"BIOS_GRUB" "$DISK"
  sgdisk -n 2:0:+1GiB      -t 2:8300 -c 2:"boot" "$DISK"
  sgdisk -n 3:0:0          -t 3:8300 -c 3:"$FS_TYPE" "$DISK"
fi

if [[ "$FS_TYPE" != "zfs" ]]; then
  partprobe "$DISK" || true
  sleep 2
fi

# Assign partition variables for BTRFS only (ZFS sets them above when RAIDZ is used)
# Skip if BTRFS+LUKS (already assigned in partitioning section above)
if [[ "$FS_TYPE" == "btrfs" && "$LUKS_ENABLED" -eq 0 ]]; then
  if [[ $UEFI -eq 1 ]]; then
    EFI_PART="$(part_path 1)"
    BOOT_PART="$(part_path 2)"
    ROOT_PART="$(part_path 3)"
  else
    BOOT_PART="$(part_path 2)"
    ROOT_PART="$(part_path 3)"
  fi

  [[ -b "$BOOT_PART" ]] || die "Missing BOOT_PART: $BOOT_PART"
  [[ -b "$ROOT_PART" ]] || die "Missing ROOT_PART: $ROOT_PART"
  if [[ $UEFI -eq 1 ]]; then
    [[ -b "$EFI_PART" ]] || die "Missing EFI_PART: $EFI_PART"
  fi
fi

# Validate boot partition devices (for all modes)
[[ -b "$BOOT_PART" ]] || die "Missing BOOT_PART: $BOOT_PART"
if [[ $UEFI -eq 1 ]]; then
  [[ -b "$EFI_PART" ]] || die "Missing EFI_PART: $EFI_PART"
fi

# Format boot partitions (required for all modes)
info "Formatting /boot (ext4)..."
mkfs.ext4 -F -L boot "$BOOT_PART"

if [[ $UEFI -eq 1 ]]; then
  info "Formatting EFI (FAT32) on $EFI_PART..."
  mkfs.vfat -F 32 -n EFI "$EFI_PART"
fi

# ============================================================
# Filesystem-specific: Create and mount
# ============================================================

if [[ "$FS_TYPE" == "simple" ]]; then
  # ============================================================
  # Simple FS (ext4/XFS): Format and mount
  # ============================================================


  if [[ "$LVM_ENABLED" -eq 1 || "$LUKS_ENABLED" -eq 1 ]]; then
    # ============================================================
    # LUKS + LVM: Format and mount
    # ============================================================

    # Format swap if exists
    if [[ -n "$LVM_SWAP_DEV" ]]; then
      info "Formatting swap on $LVM_SWAP_DEV..."
      mkswap -L swap "$LVM_SWAP_DEV"
    fi

    # Format LVM volumes
    for i in "${!LVM_LV_NAMES[@]}"; do
      lv_name="${LVM_LV_NAMES[$i]}"
      mp="${LVM_LV_MP[$i]}"
      dev="/dev/$VG_NAME/lv-$lv_name"
      label="${lv_name}"

      info "Formatting $dev ($mp) as $SIMPLE_FS_TYPE..."
      if [[ "$SIMPLE_FS_TYPE" == "xfs" ]]; then
        mkfs.xfs -f -L "$label" "$dev"
      else
        mkfs.ext4 -F -L "$label" "$dev"
      fi
    done

    # Mount root first
    for i in "${!LVM_LV_MP[@]}"; do
      if [[ "${LVM_LV_MP[$i]}" == "/" ]]; then
        lv_name="${LVM_LV_NAMES[$i]}"
        dev="/dev/$VG_NAME/lv-$lv_name"
        mount "$dev" /target
        info "Mounted / at /target"
        break
      fi
    done

    # Mount non-root LVM volumes (sorted by depth)
    declare -a _lvm_mount_order=()
    for i in "${!LVM_LV_MP[@]}"; do
      mp="${LVM_LV_MP[$i]}"
      [[ "$mp" == "/" ]] && continue

      depth=$(( $(tr -cd '/' <<<"$mp" | wc -c) ))
      len=${#mp}
      _lvm_mount_order+=( "${depth}|${len}|${i}" )
    done

    mapfile -t _lvm_mount_sorted < <(printf '%s\n' "${_lvm_mount_order[@]}" | sort -t'|' -k1,1n -k2,2n)

    for entry in "${_lvm_mount_sorted[@]}"; do
      i="${entry##*|}"
      mp="${LVM_LV_MP[$i]}"
      lv_name="${LVM_LV_NAMES[$i]}"
      dev="/dev/$VG_NAME/lv-$lv_name"

      mkdir -p "/target${mp}"
      mount "$dev" "/target${mp}"
      info "Mounted $mp at /target${mp}"
    done

    # Mount /boot
    mkdir -p /target/boot
    mount "$BOOT_PART" /target/boot

    # Mount EFI
    if [[ $UEFI -eq 1 ]]; then
      mkdir -p /target/boot/efi
      mount "$EFI_PART" /target/boot/efi
    fi

  else
    # ============================================================
    # Plain ext4/XFS (no encryption)
    # ============================================================

    if [[ "$SWAP_SIZE" != "0" ]]; then
      info "Formatting swap..."
      mkswap -L swap "$SWAP_PART"
    fi

    # --- Validate mountpoints (warnings only) ---
    for i in "${!SIMPLE_PARTS_MP[@]}"; do
      mp="${SIMPLE_PARTS_MP[$i]}"
      if [[ "$mp" != "/" ]]; then
        mp="${mp%/}"
        SIMPLE_PARTS_MP[$i]="$mp"
      fi
    done

    _warn() {
      if declare -F warn >/dev/null 2>&1; then
        warn "$*"
      else
        info "[WARN] $*"
      fi
    }

    declare -A _mp_seen=()
    for i in "${!SIMPLE_PARTS_MP[@]}"; do
      mp="${SIMPLE_PARTS_MP[$i]}"
      dev="${SIMPLE_PARTS_DEV[$i]}"

      if [[ -z "$mp" ]]; then
        _warn "Empty mountpoint for device $dev (index=$i)."
        continue
      fi
      if [[ "$mp" == "/boot" || "$mp" == "/boot/efi" ]]; then
        _warn "Mountpoint '$mp' is managed by the installer."
      fi
      if [[ "$mp" != /* ]]; then
        _warn "Mountpoint '$mp' does not start with '/'."
      fi
      if [[ "$mp" == *" "* ]]; then
        _warn "Mountpoint '$mp' contains spaces."
      fi
      if [[ "$mp" == *".."* ]]; then
        _warn "Mountpoint '$mp' contains '..'."
      fi
      if [[ "$mp" == *"//"* ]]; then
        _warn "Mountpoint '$mp' contains '//'."
      fi

      if [[ -n "${_mp_seen[$mp]:-}" ]]; then
        _warn "Duplicate mountpoint '$mp' detected."
      else
        _mp_seen[$mp]="$dev"
      fi
    done

    for i in "${!SIMPLE_PARTS_MP[@]}"; do
      a="${SIMPLE_PARTS_MP[$i]}"
      [[ "$a" == "/" ]] && continue
      [[ -z "$a" ]] && continue

      for j in "${!SIMPLE_PARTS_MP[@]}"; do
        [[ "$i" == "$j" ]] && continue
        b="${SIMPLE_PARTS_MP[$j]}"
        [[ -z "$b" ]] && continue

        if [[ "$b" == "$a/"* ]]; then
          _warn "Nested mountpoints: '$a' and '$b'."
        fi
      done
    done
    # --- End validate mountpoints ---

    # Format data partitions
    for i in "${!SIMPLE_PARTS_MP[@]}"; do
      mp="${SIMPLE_PARTS_MP[$i]}"
      dev="${SIMPLE_PARTS_DEV[$i]}"
      label="${mp//\//_}"
      label="${label:-root}"
      label="${label#_}"

      info "Formatting $dev ($mp) as $SIMPLE_FS_TYPE..."
      if [[ "$SIMPLE_FS_TYPE" == "xfs" ]]; then
        mkfs.xfs -f -L "$label" "$dev"
      else
        mkfs.ext4 -F -L "$label" "$dev"
      fi
    done

    # Mount root first
    for i in "${!SIMPLE_PARTS_MP[@]}"; do
      if [[ "${SIMPLE_PARTS_MP[$i]}" == "/" ]]; then
        mount "${SIMPLE_PARTS_DEV[$i]}" /target
        info "Mounted / at /target"
        break
      fi
    done

    # Mount non-root partitions (sorted by depth)
    declare -a _mount_order=()
    for i in "${!SIMPLE_PARTS_MP[@]}"; do
      mp="${SIMPLE_PARTS_MP[$i]}"
      [[ "$mp" == "/" ]] && continue

      depth=$(( $(tr -cd '/' <<<"$mp" | wc -c) ))
      len=${#mp}
      _mount_order+=( "${depth}|${len}|${i}" )
    done

    mapfile -t _mount_order_sorted < <(printf '%s\n' "${_mount_order[@]}" | sort -t'|' -k1,1n -k2,2n)

    for entry in "${_mount_order_sorted[@]}"; do
      i="${entry##*|}"
      mp="${SIMPLE_PARTS_MP[$i]}"
      dev="${SIMPLE_PARTS_DEV[$i]}"

      mkdir -p "/target${mp}"
      mount "$dev" "/target${mp}"
      info "Mounted $mp at /target${mp}"
    done

    # Mount /boot
    mkdir -p /target/boot
    mount "$BOOT_PART" /target/boot

    # Mount EFI
    if [[ $UEFI -eq 1 ]]; then
      mkdir -p /target/boot/efi
      mount "$EFI_PART" /target/boot/efi
    fi
  fi

elif [[ "$FS_TYPE" == "zfs" ]]; then
  # ZFS pool + datasets

  # Build vdev args based on topology
  vdev_args=()
  case "$ZFS_TOPOLOGY" in
    single)
      # Single disk or stripe (multiple disks, no redundancy)
      if [[ "${#ROOT_PARTS[@]}" -gt 0 ]]; then
        vdev_args+=( "${ROOT_PARTS[@]}" )
      else
        vdev_args+=( "$ROOT_PART" )
      fi
      ;;
    mirror)
      # Mirror configurations: simple mirror, striped mirrors, or mirrors + spare
      parts=()
      if [[ "${#ROOT_PARTS[@]}" -gt 0 ]]; then
        parts=( "${ROOT_PARTS[@]}" )
      else
        parts=( "$ROOT_PART" )
      fi

      disk_count="${#parts[@]}"
      spare_disk=""

      # If odd number, last disk becomes hot spare
      if [[ $((disk_count % 2)) -eq 1 ]]; then
        spare_disk="${parts[$((disk_count - 1))]}"
        unset 'parts[$((disk_count - 1))]'
        parts=( "${parts[@]}" )
        disk_count="${#parts[@]}"
      fi

      # Build mirror vdevs (pairs)
      i=0
      while [[ $i -lt $disk_count ]]; do
        vdev_args+=( "mirror" "${parts[$i]}" "${parts[$((i + 1))]}" )
        i=$((i + 2))
      done

      # Add hot spare if exists
      if [[ -n "$spare_disk" ]]; then
        vdev_args+=( "spare" "$spare_disk" )
      fi
      ;;
    raidz1|raidz2|raidz3)
      vdev_args+=( "$ZFS_TOPOLOGY" )
      if [[ "${#ROOT_PARTS[@]}" -gt 0 ]]; then
        vdev_args+=( "${ROOT_PARTS[@]}" )
      else
        vdev_args+=( "$ROOT_PART" )
      fi
      ;;
    *)
      die "Unknown ZFS topology: $ZFS_TOPOLOGY"
      ;;
  esac

  info "Creating ZFS pool with altroot=/target (topology=$ZFS_TOPOLOGY)..."
  # shellcheck disable=SC2086
  if [[ "$ZFS_ENCRYPTED" -eq 1 ]]; then
    echo "$ZFS_PASSPHRASE" | zpool create -R /target $POOL_OPTS "$POOL_NAME" "${vdev_args[@]}"
  else
    zpool create -R /target $POOL_OPTS "$POOL_NAME" "${vdev_args[@]}"
  fi

  info "Creating datasets..."
  for entry in "${DATASETS[@]}"; do
    DS_NAME="${entry%%|*}"
    REST="${entry#*|}"
    MP="${REST%%|*}"
    CM="${REST#*|}"

    FULL="${POOL_NAME}/${DS_NAME}"

    args=()
    # shellcheck disable=SC2206
    args+=( $DATASET_OPTS )

    [[ -n "$MP" ]] && args+=( -o "mountpoint=$MP" )

    case "$CM" in
      off)    args+=( -o canmount=off ) ;;
      on)     args+=( -o canmount=on ) ;;
      noauto) args+=( -o canmount=noauto ) ;;
      *)      args+=( -o canmount=on ) ;;
    esac

    info "  zfs create ${FULL} (mp=${MP}, canmount=${CM})"
    zfs create "${args[@]}" "$FULL"
  done

  info "Mounting datasets (explicit root noauto mount)..."
  zfs mount "$BOOTFS_DS"

else
  # BTRFS filesystem + subvolumes
  info "Creating BTRFS filesystem..."
  # shellcheck disable=SC2086
  mkfs.btrfs $BTRFS_MKFS_OPTS -L synex "$ROOT_PART"

  info "Mounting BTRFS root temporarily to create subvolumes..."
  mount "$ROOT_PART" /target

  info "Creating subvolumes..."
  for sv in "${BTRFS_SUBVOLS_NAME[@]}"; do
    info "  btrfs subvolume create /target/$sv"
    btrfs subvolume create "/target/$sv"
  done

  info "Unmounting temporary mount..."
  umount /target

  info "Mounting subvolumes with proper options..."
  # Find root subvolume (mountpoint /)
  ROOT_SUBVOL=""
  for i in "${!BTRFS_SUBVOLS_MP[@]}"; do
    if [[ "${BTRFS_SUBVOLS_MP[$i]}" == "/" ]]; then
      ROOT_SUBVOL="${BTRFS_SUBVOLS_NAME[$i]}"
      break
    fi
  done
  [[ -n "$ROOT_SUBVOL" ]] || die "No root subvolume (/) defined in btrfs.conf"

  # Mount root subvolume first
  mount -o "subvol=${ROOT_SUBVOL},${BTRFS_MOUNT_OPTS}" "$ROOT_PART" /target

  # Create mount points and mount other subvolumes
  for i in "${!BTRFS_SUBVOLS_NAME[@]}"; do
    sv="${BTRFS_SUBVOLS_NAME[$i]}"
    mp="${BTRFS_SUBVOLS_MP[$i]}"

    [[ "$mp" == "/" ]] && continue  # Already mounted

    mkdir -p "/target${mp}"
    mount -o "subvol=${sv},${BTRFS_MOUNT_OPTS}" "$ROOT_PART" "/target${mp}"
    info "  Mounted $sv at /target${mp}"
  done
fi

# Mount /boot
mkdir -p /target/boot
mount "$BOOT_PART" /target/boot

# Mount EFI
if [[ $UEFI -eq 1 ]]; then
  mkdir -p /target/boot/efi
  mount "$EFI_PART" /target/boot/efi
fi

# Extract squashfs
info "Extracting system from squashfs (this may take a while)..."
unsquashfs -f -d /target "$SQUASH"

# For ZFS: mount child datasets AFTER squashfs extraction
if [[ "$FS_TYPE" == "zfs" ]]; then
  info "Mounting ZFS child datasets..."
  zfs mount -a || true
fi

# Bind mounts for chroot
info "Mounting system filesystems for chroot..."
mount --bind /dev  /target/dev
mount --bind /proc /target/proc
mount --bind /sys  /target/sys
mount --bind /run  /target/run
[[ -d /target/dev/pts ]] || mkdir -p /target/dev/pts
mount --bind /dev/pts /target/dev/pts

# Avoid cryptsetup noise in initramfs
: > /target/etc/crypttab 2>/dev/null || true
rm -f /target/etc/crypttab.initramfs 2>/dev/null || true

mkdir -p /target/etc/default

[ -f /etc/default/keyboard ] && cp -a /etc/default/keyboard /target/etc/default/keyboard
[ -f /etc/default/locale ]   && cp -a /etc/default/locale   /target/etc/default/locale

# Capture LANG from live for use in chroot
LIVE_LANG=$(grep "^LANG=" /etc/default/locale 2>/dev/null | cut -d= -f2 || echo "en_US.UTF-8")

# Optional but recommended (helps locale/console setup)
[ -f /etc/locale.gen ] && cp -a /etc/locale.gen /target/etc/locale.gen

# Console-setup cache (optional, but helps keep console keymap/font consistent)
mkdir -p /target/etc/console-setup

for f in \
  /etc/console-setup/cached_setup_font.sh \
  /etc/console-setup/cached_setup_keyboard.sh \
  /etc/console-setup/cached_setup_terminal.sh \
  /etc/console-setup/cached_UTF-8_del.kmap.gz \
  /etc/console-setup/cached_Uni2-Fixed16.psf.gz
do
  [ -f "$f" ] && cp -a "$f" /target/etc/console-setup/
done

# Configure hostname
echo
read -r -p "Hostname (default: synex): " NEW_HOSTNAME
NEW_HOSTNAME="${NEW_HOSTNAME:-synex}"

# Validate hostname (RFC 1123)
[[ "$NEW_HOSTNAME" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$ ]] || die "Invalid hostname format"

echo "$NEW_HOSTNAME" > /target/etc/hostname

cat > /target/etc/hosts <<EOF
127.0.0.1	localhost
127.0.1.1	$NEW_HOSTNAME

# The following lines are desirable for IPv6 capable hosts
::1		localhost ip6-localhost ip6-loopback
ff02::1		ip6-allnodes
ff02::2		ip6-allrouters
EOF

info "Hostname configured: $NEW_HOSTNAME"

# ------------------------------------------------------------
# Network configuration
# ------------------------------------------------------------
info "Configuring network interface..."

# Prefer interface with default route, fallback to first non-lo
NET_IFACE="$(ip -o -4 route show to default 2>/dev/null | awk '{print $5}' | head -n1 || true)"
if [[ -z "${NET_IFACE:-}" ]]; then
  NET_IFACE="$(ip -o link show | awk -F': ' '$2 != "lo" {print $2; exit}' || true)"
fi

# ----------------------------
# Helpers IPv4 / Netmask
# ----------------------------
is_ipv4() {
  local ip="$1"
  [[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || return 1
  local o1 o2 o3 o4
  IFS='.' read -r o1 o2 o3 o4 <<<"$ip"
  for o in "$o1" "$o2" "$o3" "$o4"; do
    [[ "$o" =~ ^[0-9]+$ ]] || return 1
    (( o >= 0 && o <= 255 )) || return 1
  done
  return 0
}

ip2int() {
  local ip="$1"
  local a b c d
  IFS='.' read -r a b c d <<<"$ip"
  echo $(( (a<<24) | (b<<16) | (c<<8) | d ))
}

int2ip() {
  local n="$1"
  echo "$(( (n>>24)&255 )).$(( (n>>16)&255 )).$(( (n>>8)&255 )).$(( n&255 ))"
}

is_cidr() {
  local c="$1"
  [[ "$c" =~ ^[0-9]{1,2}$ ]] || return 1
  (( c >= 0 && c <= 32 )) || return 1
  return 0
}

# Dotted netmask must be contiguous 1s then 0s
is_netmask_dotted() {
  local m="$1"
  is_ipv4 "$m" || return 1
  local mi inv
  mi="$(ip2int "$m")"
  (( mi != 0 )) || return 1
  inv=$(( (~mi) & 0xFFFFFFFF ))
  (( ( (inv + 1) & inv ) == 0 )) || return 1
  return 0
}

mask_to_cidr() {
  local m="$1"
  local mi cidr=0 bit
  mi="$(ip2int "$m")"
  for ((bit=31; bit>=0; bit--)); do
    if (( (mi>>bit) & 1 )); then
      ((cidr++))
    else
      break
    fi
  done
  echo "$cidr"
}

cidr_to_mask() {
  local c="$1"
  local mi
  if (( c == 0 )); then
    mi=0
  else
    mi=$(( (0xFFFFFFFF << (32-c)) & 0xFFFFFFFF ))
  fi
  int2ip "$mi"
}

suggest_gateway() {
  local ip="$1"
  local mask="$2"
  local ipi mi neti gwi
  ipi="$(ip2int "$ip")"
  mi="$(ip2int "$mask")"
  neti=$(( ipi & mi ))
  gwi=$(( neti + 1 ))
  int2ip "$gwi"
}

validate_dns_list() {
  local s="$1" tok
  for tok in $s; do
    is_ipv4 "$tok" || return 1
  done
  return 0
}

if [[ -n "${NET_IFACE:-}" ]]; then
  echo
  echo "Detected interface: $NET_IFACE"
  echo
  echo "Network configuration:"
  echo "  1) DHCP (automatic)"
  echo "  2) Static IP"
  echo
  read -r -p "Select option [1-2] (default: 1): " NET_CHOICE

  mkdir -p /target/etc/network /target/etc

  case "${NET_CHOICE:-1}" in
    2)
      # ----------------------------
      # Static IP (validated + defaults)
      # ----------------------------
      echo

      # IP (required, validated)
      STATIC_IP=""
      while true; do
        read -r -p "IP address (e.g., 192.168.1.100): " STATIC_IP
        [[ -n "$STATIC_IP" ]] || { echo "[ERROR] IP address cannot be empty."; continue; }
        is_ipv4 "$STATIC_IP" && break
        echo "[ERROR] Invalid IP address: $STATIC_IP"
      done

      # Netmask/CIDR (required, validated) -> normalize to CIDR + dotted
      STATIC_MASK_IN=""
      STATIC_CIDR=""
      STATIC_MASK_DOTTED=""

      while true; do
        read -r -p "Netmask or CIDR (e.g., 255.255.255.0 or 24): " STATIC_MASK_IN
        [[ -n "$STATIC_MASK_IN" ]] || { echo "[ERROR] Netmask/CIDR cannot be empty."; continue; }

        if is_cidr "$STATIC_MASK_IN"; then
          STATIC_CIDR="$STATIC_MASK_IN"
          STATIC_MASK_DOTTED="$(cidr_to_mask "$STATIC_CIDR")"
          break
        elif is_netmask_dotted "$STATIC_MASK_IN"; then
          STATIC_MASK_DOTTED="$STATIC_MASK_IN"
          STATIC_CIDR="$(mask_to_cidr "$STATIC_MASK_DOTTED")"
          break
        else
          echo "[ERROR] Invalid netmask/CIDR: $STATIC_MASK_IN (examples: 24 or 255.255.255.0)"
        fi
      done

      # Gateway default suggestion (network + 1), validated, cannot be empty
      GW_DEFAULT=""
      if (( STATIC_CIDR < 32 )); then
        GW_DEFAULT="$(suggest_gateway "$STATIC_IP" "$STATIC_MASK_DOTTED")"
        is_ipv4 "$GW_DEFAULT" || GW_DEFAULT="$(awk -F. '{print $1"."$2"."$3".1"}' <<<"$STATIC_IP")"
      fi

      STATIC_GW=""
      while true; do
        if [[ -n "$GW_DEFAULT" ]]; then
          read -r -p "Gateway (default: $GW_DEFAULT): " STATIC_GW
          STATIC_GW="${STATIC_GW:-$GW_DEFAULT}"
        else
          read -r -p "Gateway (e.g., 192.168.1.1): " STATIC_GW
        fi

        [[ -n "$STATIC_GW" ]] || { echo "[ERROR] Gateway cannot be empty."; continue; }
        is_ipv4 "$STATIC_GW" && break
        echo "[ERROR] Invalid gateway: $STATIC_GW"
      done

      # DNS default = gateway, validated list; allow user to add more (space-separated)
      DNS_DEFAULT="$STATIC_GW"
      read -r -p "DNS servers (space-separated) (default: $DNS_DEFAULT): " STATIC_DNS
      STATIC_DNS="${STATIC_DNS:-$DNS_DEFAULT}"

      while ! validate_dns_list "$STATIC_DNS"; do
        echo "[ERROR] Invalid DNS list. Use valid IPs separated by spaces (e.g., 1.1.1.1 8.8.8.8)."
        read -r -p "DNS servers (space-separated) (default: $DNS_DEFAULT): " STATIC_DNS
        STATIC_DNS="${STATIC_DNS:-$DNS_DEFAULT}"
      done

      # Write interfaces (use CIDR form to be consistent)
      cat > /target/etc/network/interfaces <<EOF
# interfaces(5) file used by ifup(8) and ifdown(8)
# Include files from /etc/network/interfaces.d:
source /etc/network/interfaces.d/*

auto lo
iface lo inet loopback

auto $NET_IFACE
iface $NET_IFACE inet static
    address ${STATIC_IP}/${STATIC_CIDR}
    gateway $STATIC_GW
EOF

      # Write resolv.conf
      : > /target/etc/resolv.conf
      echo "# Generated by Synex Installer" >> /target/etc/resolv.conf
      for dns in $STATIC_DNS; do
        echo "nameserver $dns" >> /target/etc/resolv.conf
      done

      info "Network configured: $NET_IFACE (Static: ${STATIC_IP}/${STATIC_CIDR})"
      ;;
    *)
      # DHCP (default)
      cat > /target/etc/network/interfaces <<EOF
# interfaces(5) file used by ifup(8) and ifdown(8)
# Include files from /etc/network/interfaces.d:
source /etc/network/interfaces.d/*

auto lo
iface lo inet loopback

auto $NET_IFACE
iface $NET_IFACE inet dhcp
EOF
      info "Network configured: $NET_IFACE (DHCP)"
      ;;
  esac
else
  info "Warning: No network interface detected, skipping network configuration"
fi

# ------------------------------------------------------------
# Timezone configuration (tzdata) - paginated picker
# Default: Etc/UTC
# ------------------------------------------------------------

TZ_DEFAULT="Etc/UTC"
ZONEINFO_DIR="/usr/share/zoneinfo"

# Fallback warn/info if not defined in script (just in case)
command -v warn >/dev/null 2>&1 || warn(){ echo "[WARN] $*"; }
command -v info >/dev/null 2>&1 || info(){ echo "[INFO] $*"; }

is_valid_tz() {
  local tz="$1"
  [[ -n "$tz" ]] || return 1
  [[ -f "$ZONEINFO_DIR/$tz" ]] || return 1
  # reject some internal dirs by path (extra safety)
  [[ "$tz" != posix/* && "$tz" != right/* && "$tz" != SystemV/* ]] || return 1
  return 0
}

apply_tz_to_target() {
  local tz="$1"
  is_valid_tz "$tz" || { warn "Invalid timezone: '$tz'"; return 1; }

  mkdir -p /target/etc
  echo "$tz" > /target/etc/timezone

  # Prefer the canonical symlink used by Debian
  mkdir -p /target/etc
  ln -sf "/usr/share/zoneinfo/$tz" /target/etc/localtime

  info "Timezone configured: $tz"
  return 0
}

paged_select() {
  # Usage:
  #   paged_select "Title" outvar arrayname [page_size]
  # Returns:
  #   0 if selected (outvar set)
  #   1 if back/cancel (Enter/b)
  local title="$1"
  local __outvar="$2"
  local __arrname="$3"
  local page_size="${4:-20}"

  local -n items="$__arrname"  # bash nameref
  local total=0
  local page=0
  local filter=""
  local -a view=()

  rebuild_view() {
    view=()
    if [[ -z "$filter" ]]; then
      view=("${items[@]}")
    else
      local it
      for it in "${items[@]}"; do
        [[ "${it,,}" == *"${filter,,}"* ]] && view+=("$it")
      done
    fi
    total="${#view[@]}"
    page=0
  }

  rebuild_view

  while true; do
    echo
    echo "$title"
    echo "Commands: number | n=next | p=prev | /text=filter | /-=clear | b=back | Enter=back to main menu"
    [[ -n "$filter" ]] && echo "Filter: '$filter'"
    echo

    if (( total == 0 )); then
      warn "No matches."
    else
      local start=$(( page * page_size ))
      local end=$(( start + page_size ))
      (( end > total )) && end="$total"

      local shown=0
      local idx
      for ((idx=start; idx<end; idx++)); do
        shown=$((shown+1))
        printf "  %2d) %s\n" "$shown" "${view[$idx]}"
      done

      local pages=$(( (total + page_size - 1) / page_size ))
      printf "\nPage %d/%d (items %d-%d of %d)\n" \
        $((page+1)) "$pages" $((start+1)) "$end" "$total"
    fi

    echo
    read -r -p "Select: " ans

    # ENTER => back
    [[ -z "${ans:-}" ]] && return 1

    # back
    [[ "${ans,,}" == "b" ]] && return 1

    # next/prev
    if [[ "${ans}" == n ]]; then
      local pages=$(( (total + page_size - 1) / page_size ))
      (( page + 1 < pages )) && page=$((page+1)) || warn "Already at last page."
      continue
    fi
    if [[ "${ans}" == p ]]; then
      (( page > 0 )) && page=$((page-1)) || warn "Already at first page."
      continue
    fi

    # filter
    if [[ "${ans}" == /* ]]; then
      if [[ "${ans}" == "/-" ]]; then
        filter=""
      else
        filter="${ans#/}"
      fi
      rebuild_view
      continue
    fi

    # numeric selection (1..page_size relative to current page)
    if [[ "$ans" =~ ^[0-9]+$ ]]; then
      (( ans >= 1 && ans <= page_size )) || { warn "Out of range."; continue; }
      local pick_index=$(( page * page_size + ans - 1 ))
      (( pick_index < total )) || { warn "Out of range."; continue; }
      printf -v "$__outvar" '%s' "${view[$pick_index]}"
      return 0
    fi

    warn "Invalid input."
  done
}

timezone_menu() {
  local tz_choice=""
  while true; do
    echo
    echo "Timezone configuration:"
    echo "  1) Use default (recommended): $TZ_DEFAULT"
    echo "  2) Choose from list (region/city) [paged + filter]"
    echo "  3) Enter manually (IANA, e.g., America/Argentina/Buenos_Aires)"
    echo "  4) Skip"
    echo
    read -r -p "Select option [1-4] (default: 1): " tz_opt
    tz_opt="${tz_opt:-1}"

    case "$tz_opt" in
      1)
        apply_tz_to_target "$TZ_DEFAULT" || true
        return 0
        ;;
      2)
        # Build regions
        if [[ ! -d "$ZONEINFO_DIR" ]]; then
          warn "Missing zoneinfo directory: $ZONEINFO_DIR"
          apply_tz_to_target "$TZ_DEFAULT" || true
          return 0
        fi

        local -a REGIONS=()
        mapfile -t REGIONS < <(
          find "$ZONEINFO_DIR" -mindepth 1 -maxdepth 1 -type d -printf '%f\n' 2>/dev/null \
            | grep -Ev '^(posix|right|SystemV)$' \
            | sort
        )

        local REGION=""
        if ! paged_select "Select region:" REGION REGIONS 20; then
          info "Back to main menu (timezone)."
          continue
        fi

        # Build cities under region (files; keep subpaths)
        local -a CITIES=()
        mapfile -t CITIES < <(
          find "$ZONEINFO_DIR/$REGION" -type f -printf '%P\n' 2>/dev/null | sort
        )

        local CITY=""
        if ! paged_select "Select location in $REGION:" CITY CITIES 20; then
          info "Back to main menu (timezone)."
          continue
        fi

        tz_choice="$REGION/$CITY"
        if is_valid_tz "$tz_choice"; then
          apply_tz_to_target "$tz_choice" || true
          return 0
        else
          warn "Invalid timezone selection: $tz_choice"
          continue
        fi
        ;;
      3)
        echo
        read -r -p "Enter timezone (IANA) (Enter=back to main menu): " tz_choice
        [[ -z "${tz_choice:-}" ]] && { info "Back to main menu (timezone)."; continue; }
        if is_valid_tz "$tz_choice"; then
          apply_tz_to_target "$tz_choice" || true
          return 0
        else
          warn "Invalid timezone: '$tz_choice'"
          continue
        fi
        ;;
      4)
        info "Skipping timezone configuration."
        return 0
        ;;
      *)
        warn "Invalid option."
        ;;
    esac
  done
}

info "Configuring timezone..."
timezone_menu

# Configuration summary before root password
CONFIGURED_TZ=$(cat /target/etc/timezone 2>/dev/null || echo "Not configured")
if [[ "${NET_CHOICE:-1}" == "2" ]]; then
  CONFIGURED_NET="Static (${STATIC_IP}/${STATIC_CIDR})"
else
  CONFIGURED_NET="DHCP"
fi

while true; do
  echo
  echo "========================================"
  echo "        Configuration Summary"
  echo "========================================"
  echo "  Hostname : $NEW_HOSTNAME"
  echo "  Network  : $CONFIGURED_NET"
  echo "  Timezone : $CONFIGURED_TZ"
  echo "========================================"
  echo

  read -r -p "Is this correct? (y/n): " SUMMARY_CONFIRM
  case "$SUMMARY_CONFIRM" in
    y|Y)
      break
      ;;
    n|N)
      info "Returning to hostname configuration..."
      # Reconfigure hostname
      read -r -p "Hostname (default: synex): " NEW_HOSTNAME
      NEW_HOSTNAME="${NEW_HOSTNAME:-synex}"
      [[ "$NEW_HOSTNAME" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$ ]] || { echo "[ERROR] Invalid hostname format"; continue; }
      echo "$NEW_HOSTNAME" > /target/etc/hostname
      cat > /target/etc/hosts <<EOF
127.0.0.1   localhost
127.0.1.1   $NEW_HOSTNAME

# The following lines are desirable for IPv6 capable hosts
::1         localhost ip6-localhost ip6-loopback
ff02::1     ip6-allnodes
ff02::2     ip6-allrouters
EOF
      info "Hostname configured: $NEW_HOSTNAME"

      # Reconfigure network
      if [[ -n "${NET_IFACE:-}" ]]; then
        echo
        echo "Detected interface: $NET_IFACE"
        echo
        echo "Network configuration:"
        echo "  1) DHCP (automatic)"
        echo "  2) Static IP"
        echo
        read -r -p "Select option [1-2] (default: 1): " NET_CHOICE
        NET_CHOICE="${NET_CHOICE:-1}"

        if [[ "$NET_CHOICE" == "2" ]]; then
          echo
          while true; do
            read -r -p "IP address (e.g., 192.168.1.100): " STATIC_IP
            [[ -n "$STATIC_IP" ]] || { echo "[ERROR] IP address cannot be empty."; continue; }
            is_ipv4 "$STATIC_IP" && break
            echo "[ERROR] Invalid IP address: $STATIC_IP"
          done

          while true; do
            read -r -p "Netmask or CIDR (e.g., 255.255.255.0 or 24): " STATIC_MASK_IN
            [[ -n "$STATIC_MASK_IN" ]] || { echo "[ERROR] Netmask/CIDR cannot be empty."; continue; }
            if is_cidr "$STATIC_MASK_IN"; then
              STATIC_CIDR="$STATIC_MASK_IN"
              STATIC_MASK_DOTTED="$(cidr_to_mask "$STATIC_CIDR")"
              break
            elif is_netmask_dotted "$STATIC_MASK_IN"; then
              STATIC_MASK_DOTTED="$STATIC_MASK_IN"
              STATIC_CIDR="$(mask_to_cidr "$STATIC_MASK_DOTTED")"
              break
            else
              echo "[ERROR] Invalid netmask/CIDR: $STATIC_MASK_IN"
            fi
          done

          GW_DEFAULT="$(suggest_gateway "$STATIC_IP" "$STATIC_MASK_DOTTED")"
          is_ipv4 "$GW_DEFAULT" || GW_DEFAULT="$(awk -F. '{print $1"."$2"."$3".1"}' <<<"$STATIC_IP")"
          while true; do
            read -r -p "Gateway (default: $GW_DEFAULT): " STATIC_GW
            STATIC_GW="${STATIC_GW:-$GW_DEFAULT}"
            [[ -n "$STATIC_GW" ]] || { echo "[ERROR] Gateway cannot be empty."; continue; }
            is_ipv4 "$STATIC_GW" && break
            echo "[ERROR] Invalid gateway: $STATIC_GW"
          done

          DNS_DEFAULT="$STATIC_GW"
          read -r -p "DNS servers (space-separated) (default: $DNS_DEFAULT): " STATIC_DNS
          STATIC_DNS="${STATIC_DNS:-$DNS_DEFAULT}"

          cat > /target/etc/network/interfaces <<EOF
# interfaces(5) file used by ifup(8) and ifdown(8)
source /etc/network/interfaces.d/*

auto lo
iface lo inet loopback

auto $NET_IFACE
iface $NET_IFACE inet static
    address ${STATIC_IP}/${STATIC_CIDR}
    gateway $STATIC_GW
EOF
          : > /target/etc/resolv.conf
          echo "# Generated by Synex Installer" >> /target/etc/resolv.conf
          for dns in $STATIC_DNS; do
            echo "nameserver $dns" >> /target/etc/resolv.conf
          done
          CONFIGURED_NET="Static (${STATIC_IP}/${STATIC_CIDR})"
          info "Network configured: $NET_IFACE (Static: ${STATIC_IP}/${STATIC_CIDR})"
        else
          cat > /target/etc/network/interfaces <<EOF
# interfaces(5) file used by ifup(8) and ifdown(8)
source /etc/network/interfaces.d/*

auto lo
iface lo inet loopback

auto $NET_IFACE
iface $NET_IFACE inet dhcp
EOF
          CONFIGURED_NET="DHCP"
          info "Network configured: $NET_IFACE (DHCP)"
        fi
      fi

      # Reconfigure timezone
      info "Configuring timezone..."
      timezone_menu
      CONFIGURED_TZ=$(cat /target/etc/timezone 2>/dev/null || echo "Not configured")
      ;;
    *)
      echo "[ERROR] Please answer y or n."
      ;;
  esac
done

# Root password prompt (installed system)
info "Setting root password for the installed system..."
ROOT_PASS1=""
ROOT_PASS2=""
while true; do
  echo
  read -rsp "Enter root password (installed system): " ROOT_PASS1; echo
  read -rsp "Retype root password: " ROOT_PASS2; echo

  [[ -n "$ROOT_PASS1" ]] || { echo "[ERROR] Password cannot be empty."; continue; }
  [[ "$ROOT_PASS1" == "$ROOT_PASS2" ]] || { echo "[ERROR] Passwords do not match. Try again."; continue; }
  break
done

# Optional: create additional user
echo
read -r -p "Create an additional user? (y/n): " CREATE_USER
NEW_USER=""
NEW_USER_PASS=""
NEW_USER_HOME=""

if [[ "$CREATE_USER" =~ ^[yY] ]]; then
  while true; do
    read -r -p "Username: " NEW_USER
    # Validate username: lowercase, alphanumeric, start with letter
    if [[ "$NEW_USER" =~ ^[a-z][a-z0-9_-]{0,31}$ ]]; then
      NEW_USER_HOME="/home/$NEW_USER"
      break
    else
      echo "[ERROR] Invalid username. Use lowercase letters, numbers, _ or -"
      echo "        Must start with a letter and be max 32 characters."
    fi
  done

  while true; do
    read -rsp "Password for $NEW_USER: " NEW_USER_PASS; echo
    read -rsp "Retype password: " NEW_USER_PASS2; echo
    [[ -n "$NEW_USER_PASS" ]] || { echo "[ERROR] Password cannot be empty."; continue; }
    [[ "$NEW_USER_PASS" == "$NEW_USER_PASS2" ]] || { echo "[ERROR] Passwords do not match."; continue; }
    break
  done
  info "User '$NEW_USER' will be created with sudo access"
fi

# ============================================================
# Chroot: post-install tasks (FS-specific)
# ============================================================

if [[ "$FS_TYPE" == "zfs" ]]; then
  # Generate fstab for /boot and /boot/efi (ZFS mounts root via zpool, but boot partitions need fstab)
  info "Generating /etc/fstab for boot partitions..."

  BOOT_UUID=$(blkid -s UUID -o value "$BOOT_PART")

  cat > /target/etc/fstab <<EOF
# /etc/fstab: static file system information.
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# ZFS root is mounted automatically by zfs-mount.service
UUID=${BOOT_UUID}  /boot  ext4  defaults  0  2
EOF

  if [[ $UEFI -eq 1 ]]; then
    EFI_UUID=$(blkid -s UUID -o value "$EFI_PART")
    echo "UUID=${EFI_UUID}  /boot/efi  vfat  umask=0077  0  1" >> /target/etc/fstab
  fi

  # ZFS chroot
  info "Running post-install tasks in chroot (ZFS)..."
  chroot /target /bin/bash -euo pipefail <<CHROOT
set -euo pipefail
export LC_ALL=C

# Remove cryptsetup and mdadm (not needed for ZFS root; avoids initramfs cryptsetup noise)
apt-get -y --purge remove cryptsetup cryptsetup-initramfs mdadm || true

printf 'root:%s\n' "$ROOT_PASS1" | chpasswd

# Create additional user if requested
if [[ -n "$NEW_USER" ]]; then
  useradd -m -d "$NEW_USER_HOME" -s /bin/bash "$NEW_USER"
  printf '%s:%s\n' "$NEW_USER" "$NEW_USER_PASS" | chpasswd
  usermod -aG sudo "$NEW_USER"
fi

# --- APT: force clean sources.list (remove live-media entries) ---
cat > /etc/apt/sources.list <<'EOF'
deb http://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware
#deb-src http://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware
deb http://security.debian.org/ trixie-security main contrib non-free non-free-firmware
#deb-src http://security.debian.org/ trixie-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware
#deb-src http://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware
EOF

# Apply locale + keyboard from files copied from live
if command -v locale-gen >/dev/null 2>&1; then
  locale-gen "$LIVE_LANG" >/dev/null 2>&1 || true
  locale-gen >/dev/null 2>&1 || true
  update-locale LANG="$LIVE_LANG" >/dev/null 2>&1 || true
fi

# Apply console keyboard (if console-setup is present)
if dpkg -s console-setup >/dev/null 2>&1; then
  dpkg-reconfigure -f noninteractive keyboard-configuration >/dev/null 2>&1 || true
  dpkg-reconfigure -f noninteractive console-setup >/dev/null 2>&1 || true
fi

# Regenerate SSH host keys (avoid using live system keys)
if [ -d /etc/ssh ]; then
  rm -f /etc/ssh/ssh_host_*
  ssh-keygen -A >/dev/null 2>&1 || true
fi

# Remove live-only components (installed system must not behave like live)
apt-get -y --purge remove live-boot live-config live-config-systemd || true

# Also remove installer-only packages from the installed target
apt-get -y --purge remove user-setup synex-installer synex-chroot || true

apt-get -y --purge autoremove || true

# ZFS hostid (if available)
if command -v zgenhostid >/dev/null 2>&1; then
  zgenhostid -f || true
fi

# bootfs + cachefile
zpool set bootfs="${BOOTFS_DS}" "${POOL_NAME}" || true
mkdir -p /etc/zfs
zpool set cachefile=/etc/zfs/zpool.cache "${POOL_NAME}" || true

# Enable ZFS services (Debian)
systemctl enable zfs-import-cache.service zfs-mount.service zfs.target zfs-import.target >/dev/null 2>&1 || true

# initramfs + grub with ZPOOL_VDEV_NAME_PATH=1
# Force correct root=ZFS parameter in GRUB (required without compatibility=grub2)
if [[ -f /etc/default/grub ]]; then
  sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"root=ZFS=${BOOTFS_DS} quiet\"|" /etc/default/grub
fi
update-initramfs -u -k all
env ZPOOL_VDEV_NAME_PATH=1 update-grub

if [[ -d /sys/firmware/efi/efivars ]]; then
  env ZPOOL_VDEV_NAME_PATH=1 grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Synex --no-nvram --removable --recheck
  mkdir -p /boot/efi/EFI/BOOT
  cp -f /boot/efi/EFI/Synex/grubx64.efi /boot/efi/EFI/BOOT/BOOTX64.EFI 2>/dev/null || true
else
  env ZPOOL_VDEV_NAME_PATH=1 grub-install --target=i386-pc --recheck "${DISK}"
fi

env ZPOOL_VDEV_NAME_PATH=1 update-grub
sync

# ------------------------------------------------------------
# Phase 2: Boot redundancy (UEFI) - replicate /boot + EFI + GRUB
# ------------------------------------------------------------
if [[ -d /sys/firmware/efi/efivars ]]; then
  if command -v synex-boot-redundancy >/dev/null 2>&1; then
    # NOTE: --reformat is safe here because target disks are fresh from installer,
    # and we want deterministic boot/efi content everywhere.
    synex-boot-redundancy sync --reformat || echo "[WARN] synex-boot-redundancy failed (ignored)"
  fi
fi
CHROOT

elif [[ "$FS_TYPE" == "simple" ]]; then
  # Simple FS (ext4/XFS) chroot
  info "Running post-install tasks in chroot ($SIMPLE_FS_TYPE)..."

# Generate fstab
  cat > /target/etc/fstab <<EOF
# /etc/fstab: static file system information.
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
EOF

  if [[ "$LVM_ENABLED" -eq 1 || "$LUKS_ENABLED" -eq 1 ]]; then
    # LVM fstab entries (with or without LUKS, with or without RAID)
    for i in "${!LVM_LV_NAMES[@]}"; do
      lv_name="${LVM_LV_NAMES[$i]}"
      mp="${LVM_LV_MP[$i]}"
      dev="/dev/$VG_NAME/lv-$lv_name"
      pass=2
      [[ "$mp" == "/" ]] && pass=1
      echo "$dev  $mp  $SIMPLE_FS_TYPE  defaults  0  $pass" >> /target/etc/fstab
    done

    # Swap (if exists)
    if [[ -n "$LVM_SWAP_DEV" ]]; then
      echo "$LVM_SWAP_DEV  none  swap  sw  0  0" >> /target/etc/fstab
    fi

  else
    # Plain ext4/XFS fstab entries (use UUIDs) - no LVM, no RAID
    for i in "${!SIMPLE_PARTS_MP[@]}"; do
      mp="${SIMPLE_PARTS_MP[$i]}"
      dev="${SIMPLE_PARTS_DEV[$i]}"
      uuid=$(blkid -s UUID -o value "$dev")
      pass=2
      [[ "$mp" == "/" ]] && pass=1
      echo "UUID=${uuid}  ${mp}  ${SIMPLE_FS_TYPE}  defaults  0  ${pass}" >> /target/etc/fstab
    done

    # Swap (if exists)
    if [[ "$SWAP_SIZE" != "0" ]]; then
      swap_uuid=$(blkid -s UUID -o value "$SWAP_PART")
      echo "UUID=${swap_uuid}  none  swap  sw  0  0" >> /target/etc/fstab
    fi
  fi

  # Add /boot (common for both)
  boot_uuid=$(blkid -s UUID -o value "$BOOT_PART")
  echo "UUID=${boot_uuid}  /boot  ext4  defaults  0  2" >> /target/etc/fstab

  # Add EFI (if UEFI)
  if [[ $UEFI -eq 1 ]]; then
    efi_uuid=$(blkid -s UUID -o value "$EFI_PART")
    echo "UUID=${efi_uuid}  /boot/efi  vfat  umask=0077  0  1" >> /target/etc/fstab
  fi

  # Generate /etc/crypttab for LUKS
  if [[ "$LUKS_ENABLED" -eq 1 ]]; then
    luks_uuid=$(blkid -s UUID -o value "$LUKS_PART")
    info "Generating /etc/crypttab..."
    cat > /target/etc/crypttab <<EOF
# <target name> <source device> <key file> <options>
$LUKS_MAPPER UUID=$luks_uuid none luks,discard
EOF
    # Also create crypttab.initramfs for initramfs-tools
    cp /target/etc/crypttab /target/etc/crypttab.initramfs
  fi

  # Save mdadm configuration for RAID
  if [[ "$RAID_ENABLED" -eq 1 ]]; then
    info "Saving RAID configuration..."
    mkdir -p /target/etc/mdadm
    mdadm --detail --scan 2>/dev/null | grep -v "INACTIVE-ARRAY" > /target/etc/mdadm/mdadm.conf || true
    # Also update initramfs config to include mdadm
    echo "INITRDSTART='auto'" >> /target/etc/default/mdadm 2>/dev/null || true
  fi

  # Configure GRUB and initramfs for LUKS
  if [[ "$LUKS_ENABLED" -eq 1 ]]; then
    info "Configuring GRUB for LUKS encryption..."
    luks_uuid=$(blkid -s UUID -o value "$LUKS_PART")

    # Ensure cryptsetup-initramfs is installed
    if ! chroot /target dpkg -s cryptsetup-initramfs >/dev/null 2>&1; then
      die "cryptsetup-initramfs not installed. Please include it in the ISO."
    fi

    # Configure /etc/default/grub
    if [[ -f /target/etc/default/grub ]]; then
      # Enable GRUB_ENABLE_CRYPTODISK
      if grep -q "^GRUB_ENABLE_CRYPTODISK" /target/etc/default/grub; then
        sed -i 's/^GRUB_ENABLE_CRYPTODISK=.*/GRUB_ENABLE_CRYPTODISK=y/' /target/etc/default/grub
      else
        echo 'GRUB_ENABLE_CRYPTODISK=y' >> /target/etc/default/grub
      fi

      # Add cryptdevice to GRUB_CMDLINE_LINUX_DEFAULT
      current_cmdline=$(grep "^GRUB_CMDLINE_LINUX_DEFAULT=" /target/etc/default/grub | cut -d'"' -f2)
      new_cmdline="cryptdevice=UUID=${luks_uuid}:${LUKS_MAPPER} ${current_cmdline}"
      sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"${new_cmdline}\"|" /target/etc/default/grub
    fi

    info "LUKS GRUB configuration complete"
  fi

  chroot /target /bin/bash -euo pipefail <<CHROOT
set -euo pipefail
export LC_ALL=C

printf 'root:%s\n' "$ROOT_PASS1" | chpasswd

# Create additional user if requested
if [[ -n "$NEW_USER" ]]; then
  useradd -m -d "$NEW_USER_HOME" -s /bin/bash "$NEW_USER"
  printf '%s:%s\n' "$NEW_USER" "$NEW_USER_PASS" | chpasswd
  usermod -aG sudo "$NEW_USER"
fi

# --- APT: force clean sources.list ---
cat > /etc/apt/sources.list <<'EOF'
deb http://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware
#deb-src http://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware
deb http://security.debian.org/ trixie-security main contrib non-free non-free-firmware
#deb-src http://security.debian.org/ trixie-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware
#deb-src http://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware
EOF

# Apply locale + keyboard
if command -v locale-gen >/dev/null 2>&1; then
  locale-gen "$LIVE_LANG" >/dev/null 2>&1 || true
  locale-gen >/dev/null 2>&1 || true
  update-locale LANG="$LIVE_LANG" >/dev/null 2>&1 || true
fi

if dpkg -s console-setup >/dev/null 2>&1; then
  dpkg-reconfigure -f noninteractive keyboard-configuration >/dev/null 2>&1 || true
  dpkg-reconfigure -f noninteractive console-setup >/dev/null 2>&1 || true
fi

# Regenerate SSH host keys
if [ -d /etc/ssh ]; then
  rm -f /etc/ssh/ssh_host_*
  ssh-keygen -A >/dev/null 2>&1 || true
fi

# Remove live-only components
apt-get -y --purge remove live-boot live-config live-config-systemd || true
apt-get -y --purge remove user-setup synex-installer synex-chroot synex-boot-redundancy || true
apt-get -y --purge remove zfsutils-linux zfs-dkms zfs-initramfs linux-headers-amd64 || true
rm -rf /var/lib/dkms
apt-get -y --purge autoremove || true

# initramfs + grub
update-initramfs -u -k all
update-grub

if [[ -d /sys/firmware/efi/efivars ]]; then
  grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Synex --no-nvram --removable --recheck
  mkdir -p /boot/efi/EFI/BOOT
  cp -f /boot/efi/EFI/Synex/grubx64.efi /boot/efi/EFI/BOOT/BOOTX64.EFI 2>/dev/null || true
else
  grub-install --target=i386-pc --recheck "\${DISK}"
fi
CHROOT

# Install GRUB on additional EFI partitions for RAID redundancy
if [[ "$RAID_ENABLED" -eq 1 && "$RAID_LEVEL" != "raid0" && ${#EFI_PARTS[@]} -gt 1 && $UEFI -eq 1 ]]; then
  info "Installing GRUB on additional EFI partitions for boot redundancy..."
  for efi_p in "${EFI_PARTS[@]:1}"; do
    info "  Installing GRUB on $efi_p..."
    umount /target/boot/efi 2>/dev/null || true
    mount "$efi_p" /target/boot/efi
    chroot /target grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Synex --no-nvram --removable --recheck
    mkdir -p /target/boot/efi/EFI/BOOT
    cp -f /target/boot/efi/EFI/Synex/grubx64.efi /target/boot/efi/EFI/BOOT/BOOTX64.EFI 2>/dev/null || true
  done
  # Remount first EFI partition
  umount /target/boot/efi 2>/dev/null || true
  mount "$EFI_PART" /target/boot/efi
fi

else
  # BTRFS chroot
  info "Running post-install tasks in chroot (BTRFS)..."

  # Generate fstab for BTRFS
  ROOT_UUID=$(blkid -s UUID -o value "$ROOT_PART")
  BOOT_UUID=$(blkid -s UUID -o value "$BOOT_PART")

  cat > /target/etc/fstab <<EOF
# /etc/fstab: static file system information.
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
EOF

  # Add subvolume entries
  for i in "${!BTRFS_SUBVOLS_NAME[@]}"; do
    sv="${BTRFS_SUBVOLS_NAME[$i]}"
    mp="${BTRFS_SUBVOLS_MP[$i]}"
    if [[ "$mp" == "/" ]]; then
      echo "UUID=${ROOT_UUID}  /  btrfs  subvol=${sv},${BTRFS_MOUNT_OPTS}  0  1" >> /target/etc/fstab
    else
      echo "UUID=${ROOT_UUID}  ${mp}  btrfs  subvol=${sv},${BTRFS_MOUNT_OPTS}  0  2" >> /target/etc/fstab
    fi
  done

  # Add /boot
  echo "UUID=${BOOT_UUID}  /boot  ext4  defaults  0  2" >> /target/etc/fstab

  # Add EFI if UEFI
  if [[ $UEFI -eq 1 ]]; then
    EFI_UUID=$(blkid -s UUID -o value "$EFI_PART")
    echo "UUID=${EFI_UUID}  /boot/efi  vfat  umask=0077  0  1" >> /target/etc/fstab
  fi

# Generate /etc/crypttab for LUKS (BTRFS)
  if [[ "$LUKS_ENABLED" -eq 1 ]]; then
    luks_uuid=$(blkid -s UUID -o value "$LUKS_PART")
    info "Generating /etc/crypttab..."
    cat > /target/etc/crypttab <<EOF
# <target name> <source device> <key file> <options>
$LUKS_MAPPER UUID=$luks_uuid none luks,discard
EOF
    # Also create crypttab.initramfs for initramfs-tools
    cp /target/etc/crypttab /target/etc/crypttab.initramfs
  fi

  # Configure GRUB and initramfs for LUKS (BTRFS)
  if [[ "$LUKS_ENABLED" -eq 1 ]]; then
    info "Configuring GRUB for LUKS encryption..."
    luks_uuid=$(blkid -s UUID -o value "$LUKS_PART")

    # Ensure cryptsetup-initramfs is installed
    if ! chroot /target dpkg -s cryptsetup-initramfs >/dev/null 2>&1; then
      die "cryptsetup-initramfs not installed. Please include it in the ISO."
    fi

    # Configure /etc/default/grub
    if [[ -f /target/etc/default/grub ]]; then
      # Enable GRUB_ENABLE_CRYPTODISK
      if grep -q "^GRUB_ENABLE_CRYPTODISK" /target/etc/default/grub; then
        sed -i 's/^GRUB_ENABLE_CRYPTODISK=.*/GRUB_ENABLE_CRYPTODISK=y/' /target/etc/default/grub
      else
        echo 'GRUB_ENABLE_CRYPTODISK=y' >> /target/etc/default/grub
      fi

      # Add cryptdevice to GRUB_CMDLINE_LINUX_DEFAULT
      current_cmdline=$(grep "^GRUB_CMDLINE_LINUX_DEFAULT=" /target/etc/default/grub | cut -d'"' -f2)
      new_cmdline="cryptdevice=UUID=${luks_uuid}:${LUKS_MAPPER} ${current_cmdline}"
      sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"${new_cmdline}\"|" /target/etc/default/grub
    fi

    info "LUKS GRUB configuration complete"
  fi

  chroot /target /bin/bash -euo pipefail <<CHROOT
set -euo pipefail
export LC_ALL=C

printf 'root:%s\n' "$ROOT_PASS1" | chpasswd

# Create additional user if requested
if [[ -n "$NEW_USER" ]]; then
  useradd -m -d "$NEW_USER_HOME" -s /bin/bash "$NEW_USER"
  printf '%s:%s\n' "$NEW_USER" "$NEW_USER_PASS" | chpasswd
  usermod -aG sudo "$NEW_USER"
fi

# --- APT: force clean sources.list (remove live-media entries) ---
cat > /etc/apt/sources.list <<'EOF'
deb http://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware
#deb-src http://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware
deb http://security.debian.org/ trixie-security main contrib non-free non-free-firmware
#deb-src http://security.debian.org/ trixie-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware
#deb-src http://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware
EOF

# Apply locale + keyboard from files copied from live
if command -v locale-gen >/dev/null 2>&1; then
  locale-gen "$LIVE_LANG" >/dev/null 2>&1 || true
  locale-gen >/dev/null 2>&1 || true
  update-locale LANG="$LIVE_LANG" >/dev/null 2>&1 || true
fi

# Apply console keyboard (if console-setup is present)
if dpkg -s console-setup >/dev/null 2>&1; then
  dpkg-reconfigure -f noninteractive keyboard-configuration >/dev/null 2>&1 || true
  dpkg-reconfigure -f noninteractive console-setup >/dev/null 2>&1 || true
fi

# Regenerate SSH host keys (avoid using live system keys)
if [ -d /etc/ssh ]; then
  rm -f /etc/ssh/ssh_host_*
  ssh-keygen -A >/dev/null 2>&1 || true
fi

# Remove live-only components (installed system must not behave like live)
apt-get -y --purge remove live-boot live-config live-config-systemd || true

# Also remove installer-only packages from the installed target
apt-get -y --purge remove user-setup synex-installer synex-chroot synex-boot-redundancy || true
apt-get -y --purge remove zfsutils-linux zfs-dkms zfs-initramfs linux-headers-amd64 || true
rm -rf /var/lib/dkms
apt-get -y --purge autoremove || true

# Configure GRUB for BTRFS
sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="quiet rootflags=subvol=${ROOT_SUBVOL}"/' /etc/default/grub 2>/dev/null || true

# initramfs + grub
update-initramfs -u -k all
update-grub

if [[ -d /sys/firmware/efi/efivars ]]; then
  grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Synex --no-nvram --removable --recheck
  mkdir -p /boot/efi/EFI/BOOT
  cp -f /boot/efi/EFI/Synex/grubx64.efi /boot/efi/EFI/BOOT/BOOTX64.EFI 2>/dev/null || true
else
  grub-install --target=i386-pc --recheck "${DISK}"
fi

update-grub
sync
CHROOT

fi

# ============================================================
# Final cleanup
# ============================================================

if [[ "$FS_TYPE" == "zfs" ]]; then
  # Unmount everything before export/import
  info "Unmounting /target binds and mounts to clean altroot..."
  zfs unmount -a || true
  zfs unmount -f "${POOL_NAME}/ROOT/synex/var-log" 2>/dev/null || true
  umount -lf /target/var/log 2>/dev/null || true

  for p in /target/dev/pts /target/dev /target/proc /target/sys /target/run; do
    mountpoint -q "$p" && umount -lf "$p" || true
  done

  mountpoint -q /target/boot/efi && umount -lf /target/boot/efi || true
  mountpoint -q /target/boot && umount -lf /target/boot || true
  mountpoint -q /target && umount -lf /target || true

  # Clean altroot (export/import without -R)
  info "Cleaning altroot (export/import without -R)..."
  zpool export "$POOL_NAME"
  zpool import -N "$POOL_NAME"
  zpool export "$POOL_NAME"

elif [[ "$FS_TYPE" == "simple" ]]; then
  # Simple FS cleanup
  info "Unmounting /target..."

  for p in /target/dev/pts /target/dev /target/proc /target/sys /target/run; do
    mountpoint -q "$p" && umount -lf "$p" || true
  done

  mountpoint -q /target/boot/efi && umount -lf /target/boot/efi || true
  mountpoint -q /target/boot && umount -lf /target/boot || true

  if [[ "$LVM_ENABLED" -eq 1 || "$LUKS_ENABLED" -eq 1 ]]; then
    # LUKS + LVM cleanup: unmount LVM volumes in reverse depth order
    declare -a _lvm_umount_order=()
    for i in "${!LVM_LV_MP[@]}"; do
      mp="${LVM_LV_MP[$i]}"
      [[ "$mp" == "/" ]] && continue
      depth=$(( $(tr -cd '/' <<<"$mp" | wc -c) ))
      _lvm_umount_order+=( "${depth}|${i}" )
    done

    mapfile -t _lvm_umount_sorted < <(printf '%s\n' "${_lvm_umount_order[@]}" | sort -t'|' -k1,1nr)

    for entry in "${_lvm_umount_sorted[@]}"; do
      i="${entry##*|}"
      mp="${LVM_LV_MP[$i]}"
      mountpoint -q "/target${mp}" && umount -lf "/target${mp}" || true
    done

    # Unmount root
    mountpoint -q /target && umount -lf /target || true

    # Deactivate swap
    if [[ -n "$LVM_SWAP_DEV" ]]; then
      swapoff "$LVM_SWAP_DEV" 2>/dev/null || true
    fi

    # Deactivate LVM volume group
    info "Deactivating LVM volume group..."
    vgchange -an "$VG_NAME" 2>/dev/null || true

    # Close LUKS container (only if LUKS enabled)
    if [[ "$LUKS_ENABLED" -eq 1 ]]; then
      info "Closing LUKS container..."
      cryptsetup close "$LUKS_MAPPER" 2>/dev/null || true
    fi

  else
    # Plain ext4/XFS cleanup
    for (( i=${#SIMPLE_PARTS_MP[@]}-1 ; i>=0 ; i-- )); do
      mp="${SIMPLE_PARTS_MP[$i]}"
      [[ "$mp" == "/" ]] && continue
      mountpoint -q "/target${mp}" && umount -lf "/target${mp}" || true
    done

    mountpoint -q /target && umount -lf /target || true
  fi

else
  # BTRFS cleanup
  info "Unmounting /target..."

  for p in /target/dev/pts /target/dev /target/proc /target/sys /target/run; do
    mountpoint -q "$p" && umount -lf "$p" || true
  done

  mountpoint -q /target/boot/efi && umount -lf /target/boot/efi || true
  mountpoint -q /target/boot && umount -lf /target/boot || true

  # Unmount subvolumes in reverse order (deepest first)
  for (( i=${#BTRFS_SUBVOLS_MP[@]}-1 ; i>=0 ; i-- )); do
    mp="${BTRFS_SUBVOLS_MP[$i]}"
    [[ "$mp" == "/" ]] && continue
    mountpoint -q "/target${mp}" && umount -lf "/target${mp}" || true
  done

  mountpoint -q /target && umount -lf /target || true

  # Close LUKS container if enabled
  if [[ "$LUKS_ENABLED" -eq 1 ]]; then
    info "Closing LUKS container..."
    cryptsetup close "$LUKS_MAPPER" 2>/dev/null || true
  fi
fi

info "INSTALLATION COMPLETED. You can reboot now."
echo "Log: $LOG"
