#!/usr/bin/env bash

# install-stormux: Interactive Arch Linux installer for Stormux
# Supports UEFI/BIOS, multiple partition layouts, and accessibility-first configuration

set -Eeuo pipefail

# Global variables
logFile="/tmp/install-stormux.log"
mountPoint="/mnt"
bootMode=""  # Will be "uefi" or "bios"
targetDisk=""
homeDisk=""
partitionLayout=""  # "single", "separate_home", "separate_disk", "manual_mnt"
useExistingMount=false  # true when using manually mounted filesystems at /mnt
hostname=""
rootPassword=""
declare -a userNames=()
declare -a userPasswords=()
declare -a userIsAdmin=()
desktopEnvironment=""  # "none", "i3", "mate"
hasDesktop=false  # true if a desktop environment is selected
timezone=""
enableSsh="no"  # "yes" or "no"
installLinuxGameManager="no"  # "yes" or "no"
installAudiogameManager="no"  # "yes" or "no"
autoLoginUser=""  # User to auto-login for desktop environments
minHomePartitionMiB=1024
errorCount=0
warningCount=0
currentStep="initialization"
cleanupOnError=false


#
# Logging functions
#

log() {
    echo "$*" | tee -a "$logFile"
}

log_error() {
    errorCount=$((errorCount + 1))
    echo "ERROR: $*" | tee -a "$logFile" >&2
}

log_warning() {
    warningCount=$((warningCount + 1))
    echo "WARNING: $*" | tee -a "$logFile" >&2
}

log_info() {
    echo "$*" | tee -a "$logFile"
}

handle_unexpected_failure() {
    local exitCode="$1"

    if [[ "$exitCode" -eq 0 ]]; then
        return 0
    fi

    log_error "Installation aborted during step: $currentStep (exit code $exitCode)"

    if [[ "$cleanupOnError" == true ]]; then
        cleanup_and_unmount
    fi

    exit "$exitCode"
}

#
# Audio feedback functions
#

play_success_sound() {
    # Play a pleasant sound when installation completes successfully
    play -qnV0 synth 3 pluck D3 pluck A3 pluck D4 pluck F4 pluck A4 delay 0 .1 .2 .3 .4 remix - chorus 0.9 0.9 38 0.75 0.3 0.5 -t 2>/dev/null || true
}

#
# Pre-flight checks
#

check_root() {
    log_info "Checking for root privileges..."
    if [[ $EUID -ne 0 ]]; then
        log_error "This script must be run as root"
        exit 1
    fi
    log_info "Root check passed"
}

detect_boot_mode() {
    if [[ -d /sys/firmware/efi ]]; then
        bootMode="uefi"
        log_info "Detected UEFI boot mode"
    else
        bootMode="bios"
        log_info "Detected BIOS boot mode"
    fi
}

check_internet() {
    log_info "Checking internet connectivity..."
    if ping -c 1 -W 5 archlinux.org >/dev/null 2>&1; then
        log_info "Internet connection verified"
        return 0
    else
        log_error "No internet connection detected"
        log_error "Please configure network (use 'nmtui' for NetworkManager) and try again"
        return 1
    fi
}

check_required_tools() {
    log_info "Checking for required tools..."
    local tools=(parted mkfs.vfat mkfs.ext4 pacstrap arch-chroot genfstab lsblk blkid findmnt mountpoint)
    local missing=()

    for tool in "${tools[@]}"; do
        if ! command -v "$tool" >/dev/null 2>&1; then
            missing+=("$tool")
        fi
    done

    if [[ ${#missing[@]} -gt 0 ]]; then
        log_error "Missing required tools: ${missing[*]}"
        return 1
    fi

    log_info "All required tools present"
    return 0
}

preflight_checks() {
    log_info "=== Stormux Installer - Pre-flight Checks ==="

    check_root
    detect_boot_mode
    check_required_tools

    if ! check_internet; then
        return 1
    fi

    log_info "All pre-flight checks passed"
    return 0
}

#
# Disk selection
#

list_available_disks() {
    # List disks excluding loop devices and the disk backing the live root filesystem.
    local rootSource rootDiskName
    rootSource=$(findmnt -n -o SOURCE --target / 2>/dev/null || true)

    if [[ "$rootSource" == /dev/* ]]; then
        rootDiskName=$(lsblk -no PKNAME "$rootSource" 2>/dev/null | head -n 1 || true)

        if [[ -z "$rootDiskName" ]]; then
            rootDiskName=$(basename "$rootSource")
            rootDiskName=$(echo "$rootDiskName" | sed -E 's/p?[0-9]+$//')
        fi
    fi

    if [[ -n "${rootDiskName:-}" ]]; then
        lsblk -dno NAME,SIZE,TYPE | awk -v excludedDisk="$rootDiskName" '$1 != excludedDisk && $3 == "disk"'
    else
        lsblk -dno NAME,SIZE,TYPE | awk '$3 == "disk"'
    fi
}

select_disk() {
    local diskVar="$1"
    local prompt="$2"

    echo "$prompt"

    mapfile -t disks < <(list_available_disks | awk '{print $1}')

    if [[ ${#disks[@]} -eq 0 ]]; then
        log_error "No suitable disks found for installation"
        return 1
    fi

    # Display disk information
    log "Available disks:"
    lsblk -dno NAME,SIZE,TYPE,MODEL | grep -E "^($(IFS='|'; echo "${disks[*]}")).*disk" || true

    PS3="Enter disk number: "
    select diskChoice in "${disks[@]}" "Cancel"; do
        if [[ "$diskChoice" == "Cancel" ]]; then
            log_info "Disk selection cancelled by user"
            return 1
        elif [[ -n "$diskChoice" ]]; then
            eval "$diskVar=\"/dev/$diskChoice\""
            log_info "Selected disk: /dev/$diskChoice"
            return 0
        fi
    done
}

get_disk_size_mib() {
    local disk="$1"
    local diskSizeBytes

    diskSizeBytes=$(lsblk -bdno SIZE "$disk" 2>/dev/null | head -n 1 || true)
    if [[ -z "$diskSizeBytes" || ! "$diskSizeBytes" =~ ^[0-9]+$ ]]; then
        log_error "Could not determine disk size for $disk"
        return 1
    fi

    echo $((diskSizeBytes / 1024 / 1024))
}

validate_home_disk_size() {
    local disk="$1"
    local diskSizeMiB

    diskSizeMiB=$(get_disk_size_mib "$disk") || return 1

    if [[ "$diskSizeMiB" -lt "$minHomePartitionMiB" ]]; then
        log_warning "Selected home disk $disk is too small (${diskSizeMiB}MiB)"
        log_warning "Separate home disk requires at least ${minHomePartitionMiB}MiB"
        return 1
    fi

    return 0
}

select_separate_home_disk() {
    while true; do
        if ! select_disk homeDisk "Select disk for /home partition:"; then
            return 1
        fi

        if [[ "$homeDisk" == "$targetDisk" ]]; then
            log_warning "Home disk must be different from target disk in separate home disk layout"
            echo "Please choose a different disk."
            continue
        fi

        if ! validate_home_disk_size "$homeDisk"; then
            echo "Please choose a different disk for /home."
            continue
        fi

        return 0
    done
}

select_install_target() {
    echo "Select installation target:"

    mapfile -t disks < <(list_available_disks | awk '{print $1}')

    if [[ ${#disks[@]} -gt 0 ]]; then
        # Display disk information
        log "Available disks:"
        lsblk -dno NAME,SIZE,TYPE,MODEL | grep -E "^($(IFS='|'; echo "${disks[*]}")).*disk" || true
    else
        log_warning "No suitable installation disks detected"
    fi

    local manualOption="Use existing /mnt (already mounted root/home/boot)"
    PS3="Enter target number: "
    select targetChoice in "${disks[@]}" "$manualOption" "Cancel"; do
        if [[ "$targetChoice" == "Cancel" ]]; then
            log_info "Target selection cancelled by user"
            return 1
        elif [[ "$targetChoice" == "$manualOption" ]]; then
            useExistingMount=true
            partitionLayout="manual_mnt"
            log_info "Selected existing mount mode at $mountPoint"
            return 0
        elif [[ -n "$targetChoice" ]]; then
            targetDisk="/dev/$targetChoice"
            useExistingMount=false
            log_info "Selected disk: $targetDisk"
            return 0
        fi
    done
}

confirm_disk_destruction() {
    local disk="$1"
    log ""
    log "WARNING: ALL DATA ON $disk WILL BE DESTROYED!"
    log ""

    # Show current partition layout
    log "Current partition layout:"
    lsblk "$disk" || true

    echo "Type 'YES' (in capital letters) to confirm destruction of $disk:"
    read -r confirmation

    if [[ "$confirmation" == "YES" ]]; then
        log_info "User confirmed destruction of $disk"
        return 0
    else
        log_info "Disk destruction not confirmed"
        return 1
    fi
}

#
# Partition layout selection
#

select_partition_layout() {
    log ""
    log "=== Partition Layout Selection ==="
    log ""
    log "Choose your partition layout:"

    local layouts=(
        "Single partition (root only, /home in root partition)"
        "Separate home partition (root + /home on same disk)"
        "Separate home disk (root on one disk, /home on another)"
        "Cancel"
    )

    PS3="Enter layout number: "
    select layout in "${layouts[@]}"; do
        case "$layout" in
            "Single partition"*)
                partitionLayout="single"
                log_info "Selected partition layout: single"
                return 0
                ;;
            "Separate home partition"*)
                partitionLayout="separate_home"
                log_info "Selected partition layout: separate_home"
                return 0
                ;;
            "Separate home disk"*)
                partitionLayout="separate_disk"
                log_info "Selected partition layout: separate_disk"
                return 0
                ;;
            "Cancel")
                return 1
                ;;
        esac
    done
}

show_partition_plan() {
    log ""
    log "=== Planned Disk Layout ==="
    log "Boot mode: $bootMode"
    log "Target disk: $targetDisk"

    case "$partitionLayout" in
        single)
            if [[ "$bootMode" == "uefi" ]]; then
                log "  ${targetDisk}1 -> EFI (FAT32) mounted at /boot"
                log "  ${targetDisk}2 -> root (ext4) mounted at /"
            else
                log "  ${targetDisk}1 -> root (ext4, boot flag) mounted at /"
            fi
            log "  /home will be inside root filesystem"
            ;;
        separate_home)
            if [[ "$bootMode" == "uefi" ]]; then
                log "  ${targetDisk}1 -> EFI (FAT32) mounted at /boot"
                log "  ${targetDisk}2 -> root (ext4) mounted at /"
                log "  ${targetDisk}3 -> home (ext4) mounted at /home"
            else
                log "  ${targetDisk}1 -> root (ext4, boot flag) mounted at /"
                log "  ${targetDisk}2 -> home (ext4) mounted at /home"
            fi
            ;;
        separate_disk)
            if [[ "$bootMode" == "uefi" ]]; then
                log "  ${targetDisk}1 -> EFI (FAT32) mounted at /boot"
                log "  ${targetDisk}2 -> root (ext4) mounted at /"
            else
                log "  ${targetDisk}1 -> root (ext4, boot flag) mounted at /"
            fi
            log "Home disk: $homeDisk"
            log "  ${homeDisk}1 -> home (ext4) mounted at /home"
            ;;
    esac

    if [[ "$partitionLayout" == "separate_disk" ]]; then
        log "WARNING: ALL DATA on $targetDisk and $homeDisk will be destroyed."
    else
        log "WARNING: ALL DATA on $targetDisk will be destroyed."
    fi
}

#
# Partitioning functions
#

partition_disk_uefi_single() {
    local disk="$1"
    log_info "Creating UEFI single partition layout on $disk"

    # Wipe existing partition table
    wipefs -af "$disk"

    # Create GPT partition table
    parted -s "$disk" mklabel gpt

    # Create EFI partition (1GB)
    parted -s "$disk" mkpart primary fat32 1MiB 1025MiB
    parted -s "$disk" set 1 esp on

    # Create root partition (rest of disk)
    parted -s "$disk" mkpart primary ext4 1025MiB 100%

    log_info "Partition table created successfully"
}

partition_disk_uefi_separate_home() {
    local disk="$1"
    log_info "Creating UEFI separate home partition layout on $disk"

    # Get disk size in MiB for calculating root partition size
    local diskSizeMiB
    diskSizeMiB=$(lsblk -dno SIZE -b "$disk" | awk '{print int($1/1024/1024)}')

    # Calculate root partition size (30GiB or 40% of disk, whichever is larger)
    local rootSizeMiB=$((30 * 1024))
    local fortyPercentMiB=$((diskSizeMiB * 40 / 100))
    if [[ $fortyPercentMiB -gt $rootSizeMiB ]]; then
        rootSizeMiB=$fortyPercentMiB
    fi

    # Ensure space for EFI (1GiB) and a minimal home partition (1GiB)
    local efiEndMiB=1025
    local minHomeMiB=1024
    local maxRootMiB=$((diskSizeMiB - efiEndMiB - minHomeMiB))
    if [[ $maxRootMiB -lt 1024 ]]; then
        log_error "Disk too small for separate /home partition layout"
        return 1
    fi
    if [[ $rootSizeMiB -gt $maxRootMiB ]]; then
        rootSizeMiB=$maxRootMiB
    fi

    # Wipe existing partition table
    wipefs -af "$disk"

    # Create GPT partition table
    parted -s "$disk" mklabel gpt

    # Create EFI partition (1GB)
    parted -s "$disk" mkpart primary fat32 1MiB 1025MiB
    parted -s "$disk" set 1 esp on

    # Create root partition
    local rootEndMiB=$((efiEndMiB + rootSizeMiB))
    parted -s "$disk" mkpart primary ext4 1025MiB "${rootEndMiB}MiB"

    # Create home partition (rest of disk)
    parted -s "$disk" mkpart primary ext4 "${rootEndMiB}MiB" 100%

    log_info "Partition table created successfully"
}

partition_disk_uefi_root_only() {
    local disk="$1"
    log_info "Creating UEFI root-only partition layout on $disk (home on separate disk)"

    # Wipe existing partition table
    wipefs -af "$disk"

    # Create GPT partition table
    parted -s "$disk" mklabel gpt

    # Create EFI partition (1GB)
    parted -s "$disk" mkpart primary fat32 1MiB 1025MiB
    parted -s "$disk" set 1 esp on

    # Create root partition (rest of disk)
    parted -s "$disk" mkpart primary ext4 1025MiB 100%

    log_info "Partition table created successfully"
}

partition_disk_uefi_home_only() {
    local disk="$1"
    log_info "Creating home partition on $disk"

    if ! validate_home_disk_size "$disk"; then
        return 1
    fi

    # Wipe existing partition table
    wipefs -af "$disk"

    # Create GPT partition table
    parted -s "$disk" mklabel gpt

    # Create single partition for home
    parted -s "$disk" mkpart primary ext4 1MiB 100%

    log_info "Home partition created successfully"
}

partition_disk_bios_single() {
    local disk="$1"
    log_info "Creating BIOS single partition layout on $disk"

    # Wipe existing partition table
    wipefs -af "$disk"

    # Create MBR partition table
    parted -s "$disk" mklabel msdos

    # Create root partition (entire disk)
    parted -s "$disk" mkpart primary ext4 1MiB 100%
    parted -s "$disk" set 1 boot on

    log_info "Partition table created successfully"
}

partition_disk_bios_separate_home() {
    local disk="$1"
    log_info "Creating BIOS separate home partition layout on $disk"

    # Get disk size in MiB
    local diskSizeMiB
    diskSizeMiB=$(lsblk -dno SIZE -b "$disk" | awk '{print int($1/1024/1024)}')

    # Calculate root partition size (30GiB or 40% of disk, whichever is larger)
    local rootSizeMiB=$((30 * 1024))
    local fortyPercentMiB=$((diskSizeMiB * 40 / 100))
    if [[ $fortyPercentMiB -gt $rootSizeMiB ]]; then
        rootSizeMiB=$fortyPercentMiB
    fi

    # Ensure space for a minimal home partition (1GiB)
    local minHomeMiB=1024
    local maxRootMiB=$((diskSizeMiB - 1 - minHomeMiB))
    if [[ $maxRootMiB -lt 1024 ]]; then
        log_error "Disk too small for separate /home partition layout"
        return 1
    fi
    if [[ $rootSizeMiB -gt $maxRootMiB ]]; then
        rootSizeMiB=$maxRootMiB
    fi

    # Wipe existing partition table
    wipefs -af "$disk"

    # Create MBR partition table
    parted -s "$disk" mklabel msdos

    # Create root partition
    local rootEndMiB=$((1 + rootSizeMiB))
    parted -s "$disk" mkpart primary ext4 1MiB "${rootEndMiB}MiB"
    parted -s "$disk" set 1 boot on

    # Create home partition (rest of disk)
    parted -s "$disk" mkpart primary ext4 "${rootEndMiB}MiB" 100%

    log_info "Partition table created successfully"
}

partition_disk_bios_root_only() {
    local disk="$1"
    log_info "Creating BIOS root-only partition layout on $disk"

    # Wipe existing partition table
    wipefs -af "$disk"

    # Create MBR partition table
    parted -s "$disk" mklabel msdos

    # Create root partition (entire disk)
    parted -s "$disk" mkpart primary ext4 1MiB 100%
    parted -s "$disk" set 1 boot on

    log_info "Partition table created successfully"
}

partition_disk_bios_home_only() {
    local disk="$1"
    log_info "Creating home partition on $disk (BIOS)"

    if ! validate_home_disk_size "$disk"; then
        return 1
    fi

    # Wipe existing partition table
    wipefs -af "$disk"

    # Create MBR partition table
    parted -s "$disk" mklabel msdos

    # Create single partition for home
    parted -s "$disk" mkpart primary ext4 1MiB 100%

    log_info "Home partition created successfully"
}

partition_disks() {
    log_info "=== Partitioning Disks ==="

    # Wait for kernel to update device nodes
    sleep 2
    partprobe "$targetDisk" 2>/dev/null || true
    sleep 1

    case "$partitionLayout" in
        single)
            if [[ "$bootMode" == "uefi" ]]; then
                partition_disk_uefi_single "$targetDisk" || return 1
            else
                partition_disk_bios_single "$targetDisk" || return 1
            fi
            ;;
        separate_home)
            if [[ "$bootMode" == "uefi" ]]; then
                partition_disk_uefi_separate_home "$targetDisk" || return 1
            else
                partition_disk_bios_separate_home "$targetDisk" || return 1
            fi
            ;;
        separate_disk)
            if [[ "$bootMode" == "uefi" ]]; then
                partition_disk_uefi_root_only "$targetDisk" || return 1
                partition_disk_uefi_home_only "$homeDisk" || return 1
            else
                partition_disk_bios_root_only "$targetDisk" || return 1
                partition_disk_bios_home_only "$homeDisk" || return 1
            fi
            ;;
    esac

    # Wait for kernel to re-read partition table
    sleep 2
    partprobe "$targetDisk" 2>/dev/null || true
    if [[ -n "$homeDisk" ]]; then
        partprobe "$homeDisk" 2>/dev/null || true
    fi
    sleep 2

    log_info "Partitioning complete"
}

#
# Filesystem creation and mounting
#

get_partition_device() {
    local disk="$1"
    local partNum="$2"

    # Handle different naming schemes (nvme0n1p1, mmcblk0p1, sda1)
    if [[ "$disk" =~ (nvme|mmcblk) ]]; then
        echo "${disk}p${partNum}"
    else
        echo "${disk}${partNum}"
    fi
}

get_home_partition_number() {
    case "$partitionLayout" in
        separate_home)
            if [[ "$bootMode" == "uefi" ]]; then
                echo 3
            else
                echo 2
            fi
            ;;
        separate_disk)
            echo 1
            ;;
        *)
            return 1
            ;;
    esac
}

create_filesystems() {
    log_info "=== Creating Filesystems ==="

    local rootPart
    local homePart
    local efiPart
    local homePartNum

    if [[ "$bootMode" == "uefi" ]]; then
        efiPart=$(get_partition_device "$targetDisk" 1)
        rootPart=$(get_partition_device "$targetDisk" 2)

        log_info "Creating EFI filesystem on $efiPart"
        mkfs.vfat -F32 "$efiPart"
    else
        rootPart=$(get_partition_device "$targetDisk" 1)
    fi

    log_info "Creating root filesystem on $rootPart"
    mkfs.ext4 -F "$rootPart"

    case "$partitionLayout" in
        separate_home)
            homePartNum=$(get_home_partition_number) || return 1
            homePart=$(get_partition_device "$targetDisk" "$homePartNum")
            log_info "Creating home filesystem on $homePart"
            mkfs.ext4 -F "$homePart"
            ;;
        separate_disk)
            homePartNum=$(get_home_partition_number) || return 1
            homePart=$(get_partition_device "$homeDisk" "$homePartNum")
            log_info "Creating home filesystem on $homePart"
            mkfs.ext4 -F "$homePart"
            ;;
    esac

    log_info "Filesystems created successfully"
}

mount_filesystems() {
    log_info "=== Mounting Filesystems ==="

    local rootPart
    local homePart
    local efiPart
    local homePartNum

    # Determine partition devices
    if [[ "$bootMode" == "uefi" ]]; then
        efiPart=$(get_partition_device "$targetDisk" 1)
        rootPart=$(get_partition_device "$targetDisk" 2)
    else
        rootPart=$(get_partition_device "$targetDisk" 1)
    fi

    # Mount root
    log_info "Mounting root partition $rootPart to $mountPoint"
    mkdir -p "$mountPoint"
    mount "$rootPart" "$mountPoint"

    # Mount EFI if UEFI
    if [[ "$bootMode" == "uefi" ]]; then
        log_info "Mounting EFI partition $efiPart to $mountPoint/boot"
        mkdir -p "$mountPoint/boot"
        mount "$efiPart" "$mountPoint/boot"
    fi

    # Mount home if separate
    case "$partitionLayout" in
        separate_home)
            homePartNum=$(get_home_partition_number) || return 1
            homePart=$(get_partition_device "$targetDisk" "$homePartNum")
            log_info "Mounting home partition $homePart to $mountPoint/home"
            mkdir -p "$mountPoint/home"
            mount "$homePart" "$mountPoint/home"
            ;;
        separate_disk)
            homePartNum=$(get_home_partition_number) || return 1
            homePart=$(get_partition_device "$homeDisk" "$homePartNum")
            log_info "Mounting home partition $homePart to $mountPoint/home"
            mkdir -p "$mountPoint/home"
            mount "$homePart" "$mountPoint/home"
            ;;
    esac

    log_info "Filesystems mounted successfully"
}

validate_existing_mountpoint() {
    log_info "=== Validating Existing Mountpoint ==="

    if [[ ! -d "$mountPoint" ]]; then
        log_error "Mountpoint does not exist: $mountPoint"
        return 1
    fi

    if ! mountpoint -q "$mountPoint"; then
        log_error "$mountPoint is not mounted"
        log_error "Mount root to $mountPoint before running this installer mode"
        return 1
    fi

    local rootSource
    rootSource=$(findmnt -n -o SOURCE --target "$mountPoint" 2>/dev/null || true)
    if [[ -z "$rootSource" ]]; then
        log_error "Could not determine mounted root source for $mountPoint"
        return 1
    fi
    if [[ "$rootSource" != /dev/* ]]; then
        log_error "Unsupported root source for manual install mode: $rootSource"
        log_error "Root at $mountPoint must be backed by a /dev/* block device"
        return 1
    fi

    if [[ ! -d "$mountPoint/home" ]]; then
        log_error "Required directory is missing: $mountPoint/home"
        log_error "Create or mount /home at $mountPoint/home before continuing"
        return 1
    fi

    if [[ "$bootMode" == "uefi" ]]; then
        if [[ ! -d "$mountPoint/boot" ]]; then
            log_error "Required directory is missing for UEFI: $mountPoint/boot"
            log_error "Mount the EFI system partition at $mountPoint/boot before continuing"
            return 1
        fi

        if ! mountpoint -q "$mountPoint/boot"; then
            log_error "$mountPoint/boot is not mounted"
            log_error "For UEFI installs, mount EFI at $mountPoint/boot before continuing"
            return 1
        fi

        local efiFsType
        efiFsType=$(findmnt -n -o FSTYPE --target "$mountPoint/boot" 2>/dev/null || true)
        if [[ "$efiFsType" != "vfat" && "$efiFsType" != "fat" && "$efiFsType" != "msdos" ]]; then
            log_error "Unexpected EFI filesystem type at $mountPoint/boot: ${efiFsType:-unknown}"
            log_error "UEFI boot partition must be FAT (vfat)"
            return 1
        fi
    fi

    if ! mountpoint -q "$mountPoint/home"; then
        log_warning "$mountPoint/home is not a separate mountpoint"
        log_warning "Continuing with /home as a directory inside root"
    fi

    local writeTestFile="$mountPoint/.stormux-write-test-$$"
    if ! touch "$writeTestFile" 2>/dev/null; then
        log_error "$mountPoint is not writable"
        return 1
    fi
    rm -f "$writeTestFile"

    log ""
    log "Manual mount summary (current mounts):"
    log "  $(findmnt -n -o SOURCE,FSTYPE,TARGET --target "$mountPoint" 2>/dev/null || echo "$mountPoint not mounted")"

    if mountpoint -q "$mountPoint/home"; then
        log "  $(findmnt -n -o SOURCE,FSTYPE,TARGET --target "$mountPoint/home" 2>/dev/null || echo "$mountPoint/home not mounted")"
    else
        log "  $mountPoint/home is a directory inside root (not a separate mount)"
    fi

    if [[ "$bootMode" == "uefi" ]]; then
        log "  $(findmnt -n -o SOURCE,FSTYPE,TARGET --target "$mountPoint/boot" 2>/dev/null || echo "$mountPoint/boot not mounted")"
    fi

    echo ""
    echo "Type 'YES' (in capital letters) to continue using existing mounts at $mountPoint:"
    read -r manualMountConfirmation
    if [[ "$manualMountConfirmation" != "YES" ]]; then
        log_info "Existing mount mode not confirmed"
        return 1
    fi

    log_info "Existing mountpoint validation passed"
    return 0
}

get_root_partition_device() {
    if [[ "$useExistingMount" == true ]]; then
        findmnt -n -o SOURCE --target "$mountPoint" 2>/dev/null || true
    else
        if [[ "$bootMode" == "uefi" ]]; then
            get_partition_device "$targetDisk" 2
        else
            get_partition_device "$targetDisk" 1
        fi
    fi
}

resolve_parent_disk_device() {
    local currentDevice="$1"
    local maxHops=20
    local hop=0

    while [[ "$hop" -lt "$maxHops" ]]; do
        local currentType parentName
        currentType=$(lsblk -no TYPE "$currentDevice" 2>/dev/null | head -n 1 || true)

        if [[ "$currentType" == "disk" ]]; then
            echo "$currentDevice"
            return 0
        fi

        parentName=$(lsblk -no PKNAME "$currentDevice" 2>/dev/null | head -n 1 || true)
        if [[ -z "$parentName" ]]; then
            return 1
        fi

        currentDevice="/dev/$parentName"
        hop=$((hop + 1))
    done

    return 1
}

get_bios_install_disk() {
    if [[ "$useExistingMount" == false ]]; then
        echo "$targetDisk"
        return 0
    fi

    local rootPart
    rootPart=$(get_root_partition_device)
    if [[ -z "$rootPart" ]]; then
        log_error "Could not determine root source from mounted $mountPoint"
        return 1
    fi

    if [[ "$rootPart" != /dev/* ]]; then
        log_error "Unsupported root source for BIOS bootloader installation: $rootPart"
        return 1
    fi

    local installDisk
    installDisk=$(resolve_parent_disk_device "$rootPart" || true)
    if [[ -z "$installDisk" ]]; then
        log_error "Could not determine BIOS install disk from root source: $rootPart"
        log_error "Set root on a block device that resolves to a physical disk (for example /dev/sdX or /dev/nvmeXnY)"
        return 1
    fi

    echo "$installDisk"
}

#
# System information gathering
#

gather_system_info() {
    log_info "=== System Configuration ==="

    # Hostname
    echo "Enter hostname for the new system:"
    read -r hostname
    log_info "Hostname set to: $hostname"

    # Root password
    while true; do
        echo ""
        echo "Enter root password:"
        read -rs rootPassword
        echo ""
        echo "Confirm root password:"
        read -rs rootPasswordConfirm
        echo ""

        if [[ "$rootPassword" == "$rootPasswordConfirm" ]]; then
            log_info "Root password set"
            break
        else
            echo "Passwords do not match. Please try again."
        fi
    done

    # User accounts (loop until empty username)
    log_info "=== User Account Setup ==="
    echo ""
    echo "Press Enter without typing a username when done adding users."

    local userCount=0
    while true; do
        echo ""
        echo "Enter username (or press Enter to finish):"
        read -r currentUser

        # If empty, break out of loop
        if [[ -z "$currentUser" ]]; then
            if [[ $userCount -eq 0 ]]; then
                echo "ERROR: You must create at least one user account."
                continue
            else
                log_info "Finished adding users. Total: $userCount"
                break
            fi
        fi

        # Check if username already exists in array
        local userExists=false
        for existingUser in "${userNames[@]}"; do
            if [[ "$existingUser" == "$currentUser" ]]; then
                echo "ERROR: Username '$currentUser' already added."
                userExists=true
                break
            fi
        done

        if [[ "$userExists" == true ]]; then
            continue
        fi

        # Get password for this user
        local currentPassword
        local currentPasswordConfirm
        while true; do
            echo ""
            echo "Enter password for $currentUser:"
            read -rs currentPassword
            echo ""
            echo "Confirm password for $currentUser:"
            read -rs currentPasswordConfirm
            echo ""

            if [[ "$currentPassword" == "$currentPasswordConfirm" ]]; then
                break
            else
                echo "Passwords do not match. Please try again."
            fi
        done

        # Ask if user should have root privileges (wheel group)
        local isAdmin
        echo ""
        echo "Should $currentUser have root privileges (sudo access)? [y/N]:"
        read -r isAdmin
        if [[ "$isAdmin" =~ ^[Yy]$ ]]; then
            isAdmin="yes"
            echo "$currentUser will have sudo access."
            log_info "User $currentUser will be added to wheel group"
        else
            isAdmin="no"
            echo "$currentUser will NOT have sudo access."
            log_info "User $currentUser will be a standard user"
        fi

        # Add to arrays
        userNames+=("$currentUser")
        userPasswords+=("$currentPassword")
        userIsAdmin+=("$isAdmin")

        userCount=$((userCount + 1))
        log_info "Added user: $currentUser"
    done

    echo "Users to be created: ${userNames[*]}"

    # Desktop environment
    echo "Select desktop environment:"
    local desktops=("Console only (Fenrir screen reader)" "i3 (tiling window manager)" "MATE (traditional desktop)")

    PS3="Enter desktop number: "
    select desktop in "${desktops[@]}"; do
        case "$desktop" in
            "Console only"*)
                desktopEnvironment="none"
                hasDesktop=false
                log_info "Desktop environment: none"
                break
                ;;
            "i3"*)
                desktopEnvironment="i3"
                hasDesktop=true
                log_info "Desktop environment: i3"
                break
                ;;
            "MATE"*)
                desktopEnvironment="mate"
                hasDesktop=true
                log_info "Desktop environment: mate"
                break
                ;;
        esac
    done

    # Auto-login user selection (only if desktop environment selected)
    if [[ "$hasDesktop" == true ]]; then
        echo ""
        echo "=== Auto-Login Configuration ==="
        if [[ ${#userNames[@]} -eq 1 ]]; then
            autoLoginUser="${userNames[0]}"
            echo "Auto-login user set to: $autoLoginUser"
            log_info "Auto-login user: $autoLoginUser"
        else
            echo "Select which user should automatically login to the graphical session:"
            PS3="Enter user number: "
            select selectedUser in "${userNames[@]}"; do
                if [[ -n "$selectedUser" ]]; then
                    autoLoginUser="$selectedUser"
                    echo "Auto-login user set to: $autoLoginUser"
                    log_info "Auto-login user: $autoLoginUser"
                    break
                fi
            done
        fi
    fi

    # Game manager installation (only if desktop environment selected)
    if [[ "$hasDesktop" == true ]]; then
        echo ""
        echo "=== Optional Game Managers ==="
        echo ""
        echo "Install linux-game-manager (native Linux games)? [y/N]:"
        read -r lgmChoice
        if [[ "$lgmChoice" =~ ^[Yy]$ ]]; then
            installLinuxGameManager="yes"
            log_info "Linux Game Manager will be installed"
        else
            installLinuxGameManager="no"
            log_info "Linux Game Manager will not be installed"
        fi

        echo ""
        echo "Install audiogame-manager (Windows games via Wine)? [y/N]:"
        read -r agmChoice
        if [[ "$agmChoice" =~ ^[Yy]$ ]]; then
            installAudiogameManager="yes"
            log_info "Audiogame Manager will be installed"
        else
            installAudiogameManager="no"
            log_info "Audiogame Manager will not be installed"
        fi
    fi

    # SSH configuration
    echo ""
    echo "Enable SSH server (sshd) on boot? [y/N]:"
    read -r sshChoice
    if [[ "$sshChoice" =~ ^[Yy]$ ]]; then
        enableSsh="yes"
        log_info "SSH server will be enabled"
    else
        enableSsh="no"
        log_info "SSH server will not be enabled"
    fi

    # Timezone detection

    # Try to get current timezone from timedatectl
    if command -v timedatectl >/dev/null 2>&1; then
        currentTimezone=$(timedatectl show --property=Timezone --value 2>/dev/null || true)
        if [[ -n "$currentTimezone" && "$currentTimezone" != "n/a" ]]; then
            echo ""
            echo "Detected timezone: $currentTimezone"
            echo "Press Enter to use this timezone, or type a new one (e.g., America/New_York):"
            read -r timezoneInput
            if [[ -n "$timezoneInput" ]]; then
                timezone="$timezoneInput"
            else
                timezone="$currentTimezone"
            fi
        else
            echo ""
            echo "Enter timezone (e.g., America/New_York):"
            read -r timezone
        fi
    else
        echo ""
        echo "Enter timezone (e.g., America/New_York):"
        read -r timezone
    fi

    log_info "Timezone set to: $timezone"

    echo ""
    echo "Configuration summary:"
    echo "  Hostname: $hostname"
    echo "  Users: ${userNames[*]}"
    echo "  Desktop: $desktopEnvironment"
    echo "  SSH enabled: $enableSsh"
    echo "  Timezone: $timezone"
    echo ""
    echo "Press Enter to continue with installation..."
    read -r
}

#
# Base system installation
#

install_base_system() {
    log_info "=== Installing Base System ==="

    # Copy pacman config with Stormux repo
    log_info "Configuring pacman with Stormux repository"
    log_info "Configuring package manager"

    local copyItems=(
        "/etc/udev/rules.d/99-brltty.rules"
        "/etc/pacman.conf"
        "/usr/local/bin/sas"
        "/usr/share/pacman/keyrings/stormux*"
        "/etc/RHVoice/dicts/English"
    )
    local copyItem sourcePath destPath destDir nullglobWasSet=false

    if shopt -q nullglob; then
        nullglobWasSet=true
    else
        shopt -s nullglob
    fi

    for copyItem in "${copyItems[@]}"; do
        for sourcePath in $copyItem; do
            if [[ -d "$sourcePath" ]]; then
                destPath="$mountPoint$sourcePath"
                mkdir -p "$destPath"
                cp -a "$sourcePath/." "$destPath/"
            elif [[ -e "$sourcePath" ]]; then
                destPath="$mountPoint$sourcePath"
                destDir="$(dirname "$destPath")"
                mkdir -p "$destDir"
                cp -a "$sourcePath" "$destPath"
            fi
        done
    done

    if ! $nullglobWasSet; then
        shopt -u nullglob
    fi

    # Define package groups
    local basePackages=(
        base base-devel linux linux-firmware
        networkmanager sudo dialog git ii rsync wget
        bash-completion cronie openssh
    )

    local audioPackages=(
        pipewire pipewire-alsa pipewire-pulse pipewire-jack
        wireplumber alsa-utils sox
        alsa-firmware sof-firmware
        bluez bluez-utils
    )

    local accessibilityPackages=(
        espeak-ng rhvoice-voice-bdl speech-dispatcher
        fenrir brltty
    )

    local utilityPackages=(
        vi vim nano screen magic-wormhole
        man man-pages
        xdg-user-dirs xdg-utils
        poppler socat parted
        realtime-privileges
    )

    # Stormux-specific packages (installed later in chroot after keyring setup)
    # Note: NOT local so it's available in configure_system()
    stormuxPackages=(
        yay w3m-git
    )

    # Combine all packages
    local allPackages=("${basePackages[@]}" "${audioPackages[@]}" "${accessibilityPackages[@]}" "${utilityPackages[@]}")

    # Add desktop-specific packages
    if [[ "$hasDesktop" == true ]]; then
        case "$desktopEnvironment" in
            *)
                allPackages+=(xlibre-xserver xlibre-input-libinput nodm-dgw brave-bin)
                ;;&
            i3)
                allPackages+=(i3-wm orca python-psutil lxterminal pluma)
                allPackages+=(discount jq libnotify xfce4-notifyd pamixer playerctl)
                allPackages+=(python-i3ipc python-wxpython sox yad)
                allPackages+=(lxsession magic-wormhole pcmanfm)
                allPackages+=(python-gobject python-pillow python-pytesseract scrot tesseract)
                allPackages+=(tesseract-data-eng udiskie xorg-setxkbmap xdotool)
                ;;
            mate)
                allPackages+=(mate mate-extra orca python-psutil)
                ;;
        esac
    fi

    # Add bootloader packages
    if [[ "$bootMode" == "bios" ]]; then
        allPackages+=(grub)
    fi

    log_info "Installing packages: ${allPackages[*]}"
    log_info "Installing packages (this may take several minutes)"

    # Run pacstrap
    if ! pacstrap "$mountPoint" "${allPackages[@]}"; then
        log_error "pacstrap failed"
        log_error "Package installation failed"
        return 1
    fi

    # Generate or preserve fstab
    if [[ "$useExistingMount" == true ]]; then
        if [[ -s "$mountPoint/etc/fstab" ]]; then
            log_info "Manual mount mode: preserving existing /etc/fstab"
        else
            log_warning "Manual mount mode: /etc/fstab not found, generating one"
            genfstab -U "$mountPoint" > "$mountPoint/etc/fstab"
        fi
    else
        log_info "Generating fstab"
        genfstab -U "$mountPoint" > "$mountPoint/etc/fstab"
    fi

    log_info "Base system installed"
    log_info "Base system installation complete"
}

#
# Audio configuration
#

install_audio_configs() {
    log_info "=== Configuring Audio for Accessibility ==="

    # System-wide wireplumber configs
    log_info "Installing wireplumber system configs"
    mkdir -p "$mountPoint/etc/wireplumber/main.lua.d"

    # Analog priority config
    cat > "$mountPoint/etc/wireplumber/main.lua.d/50-analog-priority.lua" <<'EOF'
-- Prioritize analog/USB audio devices over HDMI
rule = {
  matches = {
    {
      { "device.name", "matches", "alsa_card.*" },
    },
  },
  apply_properties = {
    ["device.priority"] = 1000,
  },
}

table.insert(alsa_monitor.rules, rule)
EOF

    # HDMI deprioritize config
    cat > "$mountPoint/etc/wireplumber/main.lua.d/51-hdmi-deprioritize.lua" <<'EOF'
-- Deprioritize HDMI audio devices
rule = {
  matches = {
    {
      { "device.name", "matches", "alsa_card.*hdmi.*" },
    },
    {
      { "device.name", "matches", "alsa_card.*HDMI.*" },
    },
  },
  apply_properties = {
    ["device.priority"] = 100,
  },
}

table.insert(alsa_monitor.rules, rule)
EOF

    # User skeleton pipewire configs
    log_info "Installing pipewire user configs to /etc/skel"

    # Fenrir console config
    mkdir -p "$mountPoint/etc/skel/.config/pipewire/pipewire-pulse.conf.d"
    cat > "$mountPoint/etc/skel/.config/pipewire/pipewire-pulse.conf.d/50-fenrir-console.conf" <<'EOF'
pulse.properties = {
    server.address = [
        "unix:native"
        "unix:/tmp/pulse.sock"
    ]
}

pulse.rules = [
    {
        matches = [
            {
                application.name = "~speech-dispatcher*"
            }
        ]
        actions = {
            update-props = {
                pulse.min.req = 1024/48000
                pulse.min.quantum = 1024/48000
            }
        }
    }
]
EOF

    # Fenrir no-suspend config
    mkdir -p "$mountPoint/etc/skel/.config/wireplumber/main.conf.d"
    cat > "$mountPoint/etc/skel/.config/wireplumber/main.conf.d/50-fenrir-no-suspend.conf" <<'EOF'
monitor.alsa.rules = [
  {
    matches = [
      {
        device.name = "~alsa_card.*"
      }
    ]
    actions = {
      update-props = {
        session.suspend-timeout-seconds = 0
      }
    }
  }
]
EOF

    # Fenrir bluetooth config
    mkdir -p "$mountPoint/etc/skel/.config/wireplumber/bluetooth.conf.d"
    cat > "$mountPoint/etc/skel/.config/wireplumber/bluetooth.conf.d/50-fenrir-bluez.conf" <<'EOF'
monitor.bluez.rules = [
  {
    matches = [
      {
        device.name = "~bluez_card.*"
      }
    ]
    actions = {
      update-props = {
        session.suspend-timeout-seconds = 0
      }
    }
  }
]
EOF

    # Root audio access
    log_info "Installing root pulse config"
    mkdir -p "$mountPoint/root/.config/pulse"
    cat > "$mountPoint/root/.config/pulse/client.conf" <<'EOF'
default-server = unix:/tmp/pulse.sock
autospawn = no
EOF

    log_info "Audio configuration installed"
}

#
# SSH login monitor installation (script + service)
#

install_ssh_login_monitor() {
    log_info "=== Installing SSH Login Monitor ==="

    local srcScript="/usr/share/fenrirscreenreader/scripts/ssh-login-monitor.sh"
    local srcService="/etc/systemd/system/ssh-login-monitor.service"

    if [[ ! -f "$srcScript" ]]; then
        log_error "Source script not found: $srcScript"
        return 1
    fi
    if [[ ! -f "$srcService" ]]; then
        log_error "Source service not found: $srcService"
        return 1
    fi

    mkdir -p "$mountPoint/usr/share/fenrirscreenreader/scripts"
    mkdir -p "$mountPoint/etc/systemd/system"

    cp "$srcScript" "$mountPoint/usr/share/fenrirscreenreader/scripts/ssh-login-monitor.sh"
    chmod 755 "$mountPoint/usr/share/fenrirscreenreader/scripts/ssh-login-monitor.sh"

    cp "$srcService" "$mountPoint/etc/systemd/system/ssh-login-monitor.service"
    chmod 644 "$mountPoint/etc/systemd/system/ssh-login-monitor.service"

    log_info "SSH login monitor installed to target system"
}

#
# System configuration in chroot
#

configure_system() {
    log_info "=== Configuring System ==="

    log_info "Entering chroot to configure system"

    # Build user creation commands
    local userCreationCommands=""
    for i in "${!userNames[@]}"; do
        local username="${userNames[$i]}"
        local password="${userPasswords[$i]}"
        local admin="${userIsAdmin[$i]}"
        local userGroups="realtime,audio,video,network,brlapi"

        # Add games group if game managers are installed
        if [[ "$installLinuxGameManager" == "yes" ]] || [[ "$installAudiogameManager" == "yes" ]]; then
            userGroups="${userGroups},games"
        fi

        userCreationCommands+="
# Create user: $username
"
        if [[ "$admin" == "yes" ]]; then
            userCreationCommands+="useradd -m -g users -G wheel,$userGroups -s /bin/bash $(printf %q "$username")
"
        else
            userCreationCommands+="useradd -m -g users -G $userGroups -s /bin/bash $(printf %q "$username")
"
        fi

        userCreationCommands+="echo $(printf %q "$username:$password") | chpasswd
mkdir -p /var/lib/systemd/linger
touch /var/lib/systemd/linger/$(printf %q "$username")
sudo -iu $(printf %q "$username") bash <<'USER_CONFIG_EOF'
git config --global init.defaultBranch master
xdg-user-dirs-update
USER_CONFIG_EOF
echo \"Created user: $username\"
"
    done

    # Build stormux packages installation command
    local stormuxPackagesCmd=""
    if [[ ${#stormuxPackages[@]} -gt 0 ]]; then
        stormuxPackagesCmd="
# Install Stormux-specific packages
echo \"Installing Stormux-specific packages: ${stormuxPackages[*]}\"
if ! pacman -Sy --noconfirm --needed ${stormuxPackages[*]}; then
    echo \"WARNING: Failed to install one or more Stormux-specific packages: ${stormuxPackages[*]}\"
fi
"
    fi

    # Build game manager packages installation command
    local gameManagerPackagesCmd=""
    if [[ "$installAudiogameManager" == "yes" ]]; then
        gameManagerPackagesCmd+="
# Install packages for audiogame-manager
echo \"Installing packages for audiogame-manager...\"
# Critical packages: wine, p7zip, curl, dialog, sox, cabextract, unzip, xz
# Optional packages: winetricks, wine_gecko, wine-mono, translate-shell, gawk, perl, xclip, xdotool
# Audio packages: gst-plugins for multimedia support
if ! pacman -S --noconfirm --needed wine winetricks wine_gecko wine-mono p7zip curl dialog sox cabextract unzip xz translate-shell gawk perl xclip xdotool gst-plugins-bad gst-plugins-good gst-plugins-ugly gst-libav; then
    echo \"WARNING: Failed to install one or more audiogame-manager dependencies\"
fi
"
    fi
    if [[ "$installLinuxGameManager" == "yes" ]]; then
        gameManagerPackagesCmd+="
# Install packages for linux-game-manager
echo \"Installing packages for linux-game-manager...\"
if ! pacman -S --noconfirm --needed p7zip curl dialog yad unzip; then
    echo \"WARNING: Failed to install one or more linux-game-manager dependencies\"
fi
"
    fi

    # Build pipewire configuration command for all users
    local pipewireConfigCmd=""
    for username in "${userNames[@]}"; do
        pipewireConfigCmd+="
if ! sudo -u $(printf %q "$username") /usr/share/fenrirscreenreader/tools/configure_pipewire.sh; then
    echo \"WARNING: Failed to configure PipeWire for user $(printf %q "$username")\"
fi
"
    done

    # Run configuration in chroot using heredoc (like pi4 script)
    if ! arch-chroot "$mountPoint" /bin/bash <<EOF 2>&1 | tee -a "$logFile"
set -euo pipefail

# Set timezone
ln -sf /usr/share/zoneinfo/${timezone} /etc/localtime
hwclock --systohc

# Set locale
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf

# Set hostname
echo "${hostname}" > /etc/hostname

# Configure hosts file
cat > /etc/hosts <<HOSTS_EOF
127.0.0.1   localhost
::1         localhost
127.0.1.1   ${hostname}.localdomain ${hostname}
HOSTS_EOF

# Set console keymap
echo "KEYMAP=us" > /etc/vconsole.conf

# Configure environment variables for accessibility
cat > /etc/environment <<ENV_EOF
export ACCESSIBILITY_ENABLED=1
export GTK_MODULES=gail:atk-bridge
export GNOME_ACCESSIBILITY=1
export QT_ACCESSIBILITY=1
export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1
export EDITOR=nano
export VISUAL=nano
ENV_EOF

# Suppress git default-branch warning for root-run git commands
git config --global init.defaultBranch master

# Note: realtime group is created by realtime-privileges package

# Create users (commands built dynamically before chroot)
$userCreationCommands

# Set root password
echo "root:${rootPassword}" | chpasswd

# Configure sudo
echo '%wheel ALL=(ALL) ALL' > /etc/sudoers.d/wheel
chmod 440 /etc/sudoers.d/wheel

# Disable systemd-networkd in favor of NetworkManager
if ! systemctl disable systemd-networkd.service systemd-networkd.socket; then
    echo "WARNING: Could not disable systemd-networkd services (may already be disabled)"
fi

# Enable system services
systemctl enable NetworkManager.service
systemctl enable brltty.path
systemctl enable fenrirscreenreader.service
systemctl enable cronie.service
systemctl enable ssh-login-monitor.service

# Enable bluetooth if present
if ! systemctl enable bluetooth.service; then
    echo "WARNING: Could not enable bluetooth.service"
fi

# Enable SSH if requested
if [[ "${enableSsh}" == "yes" ]]; then
    systemctl enable sshd.service
    echo "SSH server enabled"
fi

# Setup desktop environment configurations
if [[ "${desktopEnvironment}" == "i3" ]]; then
    firstUser="${userNames[0]}"

    # Create git directory for better organization
    mkdir -p /home/\$firstUser/git
    chown \$firstUser:users /home/\$firstUser/git

# Clone I38 to ~/git/I38
echo "Cloning I38 accessibility configuration..."
if ! sudo -u \$firstUser git clone https://git.stormux.org/storm/I38 /home/\$firstUser/git/I38; then
    echo "WARNING: Failed to clone I38 repository"
fi

    # Run I38 setup to generate accessible i3 configuration
    if [[ -d /home/\$firstUser/git/I38 ]]; then
        echo "Configuring I38 for accessibility..."
        cd /home/\$firstUser/git/I38 || exit 1

        # Ensure xdotool is available for I38 setup
        if ! command -v xdotool >/dev/null 2>&1; then
            echo "Installing xdotool for I38..."
            if ! pacman -Sy --noconfirm --needed xdotool; then
                echo "WARNING: Failed to install xdotool for I38 setup"
            fi
        fi

        # Run I38 setup scripts as the user
        # -x generates xinitrc and xprofile
        # Main script generates i3 config with accessibility features
        if ! sudo -u \$firstUser ./i38.sh -x; then
            echo "WARNING: I38 xinit/xprofile setup reported an error"
        fi
        if ! sudo -u \$firstUser ./i38.sh; then
            echo "WARNING: I38 main setup reported an error"
        fi

        cd - > /dev/null || exit 1
    fi
elif [[ "${desktopEnvironment}" == "mate" ]]; then
    firstUser="${userNames[0]}"

    # Create .xinitrc for MATE
    cat > /home/\$firstUser/.xinitrc <<'XINITRC_MATE_EOF'
#!/bin/sh
#
# ~/.xinitrc
#
# Executed by startx (run your window manager from here)

[[ -f ~/.Xresources ]] && xrdb -merge -I\$HOME ~/.Xresources

if [ -d /etc/X11/xinit/xinitrc.d ]; then
  for f in /etc/X11/xinit/xinitrc.d/*; do
    [ -x "\$f" ] && . "\$f"
  done
  unset f
fi

[ -f /etc/xprofile ] && . /etc/xprofile
[ -f ~/.xprofile ] && . ~/.xprofile

exec dbus-run-session -- mate-session
XINITRC_MATE_EOF
    chmod 755 /home/\$firstUser/.xinitrc
    chown \$firstUser:users /home/\$firstUser/.xinitrc

    # Create .xprofile for MATE with accessibility variables
    cat > /home/\$firstUser/.xprofile <<'XPROFILE_MATE_EOF'
# Accessibility variables
export ACCESSIBILITY_ENABLED=1
export CHROME_FLAGS="--force-renderer-accessibility"
export GTK_MODULES=gail:atk-bridge
export GNOME_ACCESSIBILITY=1
export QT_ACCESSIBILITY=1
export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1
export SAL_USE_VCLPLUGIN=gtk3

# Enable Orca screen reader
if ! gsettings set org.gnome.desktop.a11y.applications screen-reader-enabled true; then
    echo "WARNING: Could not set GNOME screen-reader-enabled flag"
fi
if ! gsettings set org.mate.interface accessibility true; then
    echo "WARNING: Could not set MATE accessibility flag"
fi
if ! gsettings set org.mate.applications-at-visual startup true; then
    echo "WARNING: Could not set MATE startup applications accessibility flag"
fi
XPROFILE_MATE_EOF
    chmod 755 /home/\$firstUser/.xprofile
    chown \$firstUser:users /home/\$firstUser/.xprofile

    # Configure speech-dispatcher for MATE
    if [[ ! -d /home/\$firstUser/.config/speech-dispatcher ]]; then
        if ! sudo -u \$firstUser spd-conf -n; then
            echo "WARNING: Failed to initialize speech-dispatcher configuration for \$firstUser"
        fi
    fi
fi

# Initialize pacman keyring
pacman-key --init
pacman-key --populate archlinux

# Import Stormux key if present
if [[ -f /usr/share/pacman/keyrings/stormux.gpg ]]; then
    if ! pacman-key --add /usr/share/pacman/keyrings/stormux.gpg; then
        echo "WARNING: Could not add Stormux signing key to pacman keyring"
    fi
    if ! pacman-key --lsign-key 52ADA49000F1FF0456F8AEEFB4CDE1CD56EF8E82; then
        echo "WARNING: Could not locally sign Stormux pacman key"
    fi
fi

# Install Stormux-specific packages (built dynamically before chroot)
$stormuxPackagesCmd

# Install game manager packages (built dynamically before chroot)
$gameManagerPackagesCmd

# Enable pipewire globally for all users (creates symlinks in /etc/systemd/user/)
systemctl --global enable pipewire.service pipewire-pulse.service wireplumber.service

# Configure pipewire for Fenrir screen reader (run as root first)
if [[ -x /usr/share/fenrirscreenreader/tools/configure_pipewire.sh ]]; then
    if ! /usr/share/fenrirscreenreader/tools/configure_pipewire.sh; then
        echo "WARNING: Failed to configure PipeWire for root/Fenrir"
    fi
fi

# Configure pipewire for each user (built dynamically before chroot)
$pipewireConfigCmd

# Configure nodm for automatic login (only after nodm package is installed)
if [[ "${desktopEnvironment}" == "i3" ]] || [[ "${desktopEnvironment}" == "mate" ]]; then
    if [[ -f /etc/nodm.conf ]]; then
        sed -i "s/{user}/${autoLoginUser}/g" /etc/nodm.conf
        systemctl enable nodm.service
        echo "Display manager (nodm) configured for ${autoLoginUser}"
    else
        echo "Warning: /etc/nodm.conf not found, skipping nodm configuration"
    fi
fi

# Create system-wide accessibility configuration
cat > /etc/profile.d/stormux-accessibility.sh <<'PROFILE_EOF'
#!/bin/sh
# Stormux accessibility environment variables
# Available to all users and sessions

# Accessibility support
export ACCESSIBILITY_ENABLED=1
export GTK_MODULES=gail:atk-bridge:canberra-gtk-module
export GNOME_ACCESSIBILITY=1
export QT_ACCESSIBILITY=1
export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1

# Default editor (users can override in their own shell config)
export EDITOR=nano
export VISUAL=nano

# Dialog accessibility options
export DIALOGOPTS='--no-lines --visit-items'
PROFILE_EOF
chmod 755 /etc/profile.d/stormux-accessibility.sh

echo "System configuration complete"
EOF
    then
        log_error "System configuration failed"
        return 1
    fi

    log_info "System configuration complete"
}

#
# Bootloader installation
#

install_bootloader() {
    log_info "=== Installing Bootloader ==="

    if [[ "$bootMode" == "uefi" ]]; then
        log_info "Installing systemd-boot for UEFI"
        log_info "Installing systemd-boot"

        # Install systemd-boot
        arch-chroot "$mountPoint" bootctl install

        # Create loader config
        cat > "$mountPoint/boot/loader/loader.conf" <<EOF
default arch.conf
timeout 3
console-mode max
editor no
EOF

        # Get root partition UUID
        local rootPart
        rootPart=$(get_root_partition_device)
        if [[ -z "$rootPart" ]]; then
            log_error "Could not determine root partition device"
            return 1
        fi

        local rootUUID
        rootUUID=$(blkid -s UUID -o value "$rootPart")
        if [[ -z "$rootUUID" ]]; then
            log_error "Could not determine root partition UUID for $rootPart"
            return 1
        fi

        # Create boot entry
        cat > "$mountPoint/boot/loader/entries/arch.conf" <<EOF
title   Stormux
linux   /vmlinuz-linux
initrd  /initramfs-linux.img
options root=UUID=${rootUUID} rw
EOF

        log_info "systemd-boot installed successfully"
        echo "Bootloader installed: systemd-boot"

    else
        log_info "Installing GRUB for BIOS"
        log_info "Installing GRUB"

        local grubTargetDisk
        grubTargetDisk=$(get_bios_install_disk) || return 1

        # Install GRUB to disk
        arch-chroot "$mountPoint" grub-install --target=i386-pc "$grubTargetDisk"

        # Generate GRUB config
        arch-chroot "$mountPoint" grub-mkconfig -o /boot/grub/grub.cfg

        log_info "GRUB installed successfully"
        echo "Bootloader installed: GRUB"
    fi

}

#
# Post-installation tasks
#

install_game_managers() {
    # Only run if at least one game manager is selected
    if [[ "$installLinuxGameManager" == "no" && "$installAudiogameManager" == "no" ]]; then
        return 0
    fi

    log_info "=== Installing Game Managers ==="

    # Create games group if it doesn't exist
    log_info "Creating games group in chroot"
    arch-chroot "$mountPoint" groupadd -f games

    # Install linux-game-manager
    if [[ "$installLinuxGameManager" == "yes" ]]; then
        log_info "Installing linux-game-manager to /opt"
        log_info "Installing linux-game-manager"

        # Clone repository
        git clone https://git.stormux.org/storm/linux-game-manager "$mountPoint/opt/linux-game-manager"

        # Configure git repository for shared group access
        arch-chroot "$mountPoint" git -C /opt/linux-game-manager config core.sharedRepository group
        # Add safe.directory configuration both locally and globally for all users
        arch-chroot "$mountPoint" git -C /opt/linux-game-manager config safe.directory /opt/linux-game-manager
        arch-chroot "$mountPoint" git config --global --add safe.directory /opt/linux-game-manager

        # Set ownership to root:games with group-writable permissions
        chown -R root:games "$mountPoint/opt/linux-game-manager"
        chmod -R 775 "$mountPoint/opt/linux-game-manager"
        # Set setgid bit so new files inherit games group
        find "$mountPoint/opt/linux-game-manager" -type d -exec chmod g+s {} \;

        # Create launcher script
        cat > "$mountPoint/usr/local/bin/linux-game-manager" <<'EOF'
#!/usr/bin/env bash
cd /opt/linux-game-manager || exit 1

# Set umask for group-writable files
umask 002

# Configure safe.directory if not already set
git config --global --get-all safe.directory | grep -q "^/opt/linux-game-manager$" || \
    git config --global --add safe.directory /opt/linux-game-manager

# Try to update - only members of games group can write
git pull --quiet 2>/dev/null || true

exec ./linux-game-manager.sh "$@"
EOF
        chmod 755 "$mountPoint/usr/local/bin/linux-game-manager"

        log_info "linux-game-manager installed successfully"
        echo "linux-game-manager installed to /opt/linux-game-manager"
    fi

    # Install audiogame-manager
    if [[ "$installAudiogameManager" == "yes" ]]; then
        log_info "Installing audiogame-manager to /opt"
        log_info "Installing audiogame-manager"

        # Clone repository
        git clone https://git.stormux.org/storm/audiogame-manager "$mountPoint/opt/audiogame-manager"

        # Configure git repository for shared group access
        arch-chroot "$mountPoint" git -C /opt/audiogame-manager config core.sharedRepository group
        # Add safe.directory configuration both locally and globally for all users
        arch-chroot "$mountPoint" git -C /opt/audiogame-manager config safe.directory /opt/audiogame-manager
        arch-chroot "$mountPoint" git config --global --add safe.directory /opt/audiogame-manager

        # Set ownership to root:games with group-writable permissions
        chown -R root:games "$mountPoint/opt/audiogame-manager"
        chmod -R 775 "$mountPoint/opt/audiogame-manager"
        # Set setgid bit so new files inherit games group
        find "$mountPoint/opt/audiogame-manager" -type d -exec chmod g+s {} \;

        # Create launcher script
        cat > "$mountPoint/usr/local/bin/audiogame-manager" <<'EOF'
#!/usr/bin/env bash
cd /opt/audiogame-manager || exit 1

# Set umask for group-writable files
umask 002

# Configure safe.directory if not already set
git config --global --get-all safe.directory | grep -q "^/opt/audiogame-manager$" || \
    git config --global --add safe.directory /opt/audiogame-manager

# Try to update - only members of games group can write
git pull --quiet 2>/dev/null || true

exec ./audiogame-manager.sh "$@"
EOF
        chmod 755 "$mountPoint/usr/local/bin/audiogame-manager"

        log_info "audiogame-manager installed successfully"
        echo "audiogame-manager installed to /opt/audiogame-manager"
    fi

    log_info "Game managers installed"
    log_info "Game manager installation complete"
}

#
# Cleanup and finalization
#

cleanup_and_unmount() {
    log_info "=== Finalizing Installation ==="

    log_info "Syncing filesystems"
    log_info "Syncing filesystems"
    sync

    log_info "Unmounting filesystems"
    log_info "Unmounting filesystems"

    # Unmount in reverse order
    umount -R "$mountPoint" 2>/dev/null || true

    log_info "Installation cleanup complete"
    log_info "Cleanup complete"
}

#
# Main installation flow
#

echo "╔════════════════════════════════════════════╗"
echo "║     Stormux Installer for Arch Linux      ║"
echo "║   Accessibility-First System Installation ║"
echo "╚════════════════════════════════════════════╝"

log_info "=== Stormux Installer Started ==="
log_info "Installation log: $logFile"

# Pre-flight checks
currentStep="pre-flight checks"
if ! preflight_checks; then
    log_error "Pre-flight checks failed"
    exit 1
fi

# Disk selection
log_info "=== Disk Selection ==="
currentStep="disk selection"
if ! select_install_target; then
    log_error "Target selection cancelled"
    exit 1
fi

if [[ "$useExistingMount" == false ]]; then
    # Partition layout selection
    currentStep="partition layout selection"
    if ! select_partition_layout; then
        log_error "Partition layout selection cancelled"
        exit 1
    fi

    # If separate disk layout, select home disk
    if [[ "$partitionLayout" == "separate_disk" ]]; then
        currentStep="home disk selection"
        if ! select_separate_home_disk; then
            log_error "Home disk selection cancelled"
            exit 1
        fi
    fi

    currentStep="partition plan summary"
    show_partition_plan

    currentStep="target disk confirmation"
    if ! confirm_disk_destruction "$targetDisk"; then
        log_error "Disk destruction not confirmed"
        echo "Installation cancelled."
        exit 1
    fi

    if [[ "$partitionLayout" == "separate_disk" ]]; then
        currentStep="home disk confirmation"
        if ! confirm_disk_destruction "$homeDisk"; then
            log_error "Home disk destruction not confirmed"
            echo "Installation cancelled."
            exit 1
        fi
    fi
else
    currentStep="existing mount validation"
    if ! validate_existing_mountpoint; then
        log_error "Existing mountpoint validation failed"
        exit 1
    fi
fi

# Gather system information
currentStep="system configuration prompts"
if ! gather_system_info; then
    log_error "System information gathering failed"
    exit 1
fi

trap 'handle_unexpected_failure "$?"' ERR

if [[ "$useExistingMount" == false ]]; then
    # Partition disks
    currentStep="disk partitioning"
    partition_disks

    # Create filesystems
    currentStep="filesystem creation"
    create_filesystems

    # Mount filesystems
    cleanupOnError=true
    currentStep="filesystem mounting"
    mount_filesystems
else
    cleanupOnError=true
    log_info "Skipping partitioning, filesystem creation, and mounting (using existing $mountPoint)"
fi

# Install base system
currentStep="base system installation"
install_base_system

# Install audio configurations
currentStep="audio configuration"
install_audio_configs

# Install SSH login monitor files (script + service)
currentStep="ssh login monitor installation"
install_ssh_login_monitor

# Configure system
currentStep="chroot system configuration"
configure_system

# Install bootloader
currentStep="bootloader installation"
install_bootloader

# Install game managers
currentStep="game manager installation"
install_game_managers

# Cleanup and unmount
currentStep="cleanup"
cleanup_and_unmount
cleanupOnError=false

summaryWarningCount=$(grep -c '^WARNING:' "$logFile" 2>/dev/null || true)
summaryErrorCount=$(grep -c '^ERROR:' "$logFile" 2>/dev/null || true)

log ""
log "=== Installation Summary ==="
log "  Errors: ${summaryErrorCount:-0}"
log "  Warnings: ${summaryWarningCount:-0}"
log "  Log file: $logFile"
log ""

if [[ "$errorCount" -gt 0 ]]; then
    log_warning "Installation completed with ${summaryErrorCount:-$errorCount} error(s)."
    log_warning "Review the installation log before rebooting: $logFile"
    finalExitCode=1
else
    # Success message
    log_info "=== Stormux Installer Completed Successfully ==="
    log ""
    log "╔════════════════════════════════════════════╗"
    log "║     Installation Complete Successfully!    ║"
    log "╚════════════════════════════════════════════╝"
    log ""
    log "Next steps:"
    log "  1. Remove the installation media"
    log "  2. Reboot your system"
    log "  3. Log in with one of your user accounts: ${userNames[*]}"

    if [[ "$desktopEnvironment" == "i3" ]]; then
        log "  4. Your i3 desktop is configured with I38 for accessibility"
        log "     - I38 source is available in ~/git/I38 for customization"
        log "     - Press Alt+Shift+F1 for I38 help after login"
    fi

    log ""
    log "Installation log saved to: $logFile"
    log ""

    # Play success sound
    play_success_sound
    finalExitCode=0
fi

read -rp "Press Enter to exit..."
exit "$finalExitCode"
