#!/bin/bash

# Rely on Omarchy for styling and error handling
source "$OMARCHY_INSTALL/helpers/all.sh"

# Ensure tzupdate is available for guessing timezone
command -v tzupdate >/dev/null || sudo pacman -Sy --noconfirm tzupdate

abort() {
  gum style "${1:-Aborted installation}"
  echo
  gum style "You can retry later by running: ./.automated_script.sh"
  exit 1
}

step() {
  clear_logo
  echo
  gum style "$1"
  echo
}

notice() {
  clear_logo
  echo
  gum spin --spinner "pulse" --title "$1" -- sleep "${2:-2}"
  echo
}

# STEP 1: KEYBOARD LAYOUT

keyboard_form() {
  step "Let's setup your machine..."
  keyboards=$'Azerbaijani|azerty
Belarusian|by
Belgian|be-latin1
Bosnian|ba
Bulgarian|bg-cp1251
Croatian|croat
Czech|cz
Danish|dk-latin1
Dutch|nl
English (UK)|uk
English (US)|us
English (US, Dvorak)|dvorak
English (US, Colemak)|colemak
Estonian|et
Finnish|fi
French|fr
French (Canada)|cf
French (Switzerland)|fr_CH
Georgian|ge
German|de
German (Switzerland)|de_CH-latin1
Greek|gr
Hebrew|il
Hungarian|hu
Icelandic|is-latin1
Irish|ie
Italian|it
Japanese|jp106
Kazakh|kazakh
Khmer (Cambodia)|khmer
Kyrgyz|kyrgyz
Lao|la-latin1
Latvian|lv
Lithuanian|lt
Macedonian|mk-utf
Norwegian|no-latin1
Polish|pl
Portuguese|pt-latin1
Portuguese (Brazil)|br-abnt2
Romanian|ro
Russian|ru
Serbian|sr-latin
Slovak|sk-qwertz
Slovenian|slovene
Spanish|es
Spanish (Latin American)|la-latin1
Swedish|sv-latin1
Tajik|tj_alt-UTF8
Turkish|trq
Ukrainian|ua'
  choice=$(printf '%s\n' "$keyboards" | cut -d'|' -f1 | gum choose --height 10 --selected "English (US)" --header "Select keyboard layout") || abort
  keyboard=$(printf '%s\n' "$keyboards" | awk -F'|' -v c="$choice" '$1==c{print $2; exit}')

  # Only attempt to load keyboard layout if we're on a real console
  # loadkeys only works on Linux virtual consoles (tty), not in terminal emulators
  if [[ $(tty 2>/dev/null) == "/dev/tty"* ]]; then
    loadkeys "$keyboard" 2>/dev/null
  fi
}

keyboard_form

# STEP 2: USER

user_form() {
  step "Let's setup your user account..."

  while true; do
    username=$(gum input --placeholder "Alphanumeric without spaces (like dhh)" --prompt.foreground="#845DF9" --prompt "Username> ") || abort

    if [[ "$username" =~ ^[a-z_][a-z0-9_-]*[$]?$ ]]; then
      break
    else
      notice "Username must be alphanumeric with no spaces" 1
    fi
  done

  while true; do
    password=$(gum input --placeholder "Used for user + root, and disk encryption when enabled" --prompt.foreground="#845DF9" --password --prompt "Password> ") || abort
    password_confirmation=$(gum input --placeholder "Must match the password you just typed" --prompt.foreground="#845DF9" --password --prompt "Confirm> ") || abort

    if [[ -n "$password" && "$password" == "$password_confirmation" ]]; then
      break
    elif [[ -z "$password" ]]; then
      notice "Your password can't be blank!" 1
    else
      notice "Passwords didn't match!" 1
    fi
  done

  # Hash the password using yescrypt
  password_hash=$(printf '%s' "$password" | openssl passwd -6 -stdin)

  full_name=$(gum input --placeholder "Used for git authentication (hit return to skip)" --prompt.foreground="#845DF9" --prompt "Full name> ")
  email_address=$(gum input --placeholder "Used for git authentication (hit return to skip)" --prompt.foreground="#845DF9" --prompt "Email address> ")

  while true; do
    hostname=$(gum input --placeholder "Letters, digits, and dashes (or return for 'omarchy')" --prompt.foreground="#845DF9" --prompt "Hostname> ")

    if [[ "$hostname" =~ ^[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?$ ]]; then
      break
    elif [[ -z $hostname ]]; then
      hostname="omarchy"
      break
    else
      notice "Hostname must be 1-63 letters, digits, or dashes, and cannot start or end with a dash" 1
    fi
  done

  # Pick timezone
  geo_guessed_timezone=$(tzupdate -p 2>/dev/null)

  if [[ -n $geo_guessed_timezone ]]; then
    timezone=$(timedatectl list-timezones | gum choose --height 10 --selected "$geo_guessed_timezone" --header "Timezone") || abort
  else
    timezone=$(timedatectl list-timezones | gum filter --height 10 --header "Timezone") || abort
  fi
}

user_form

while true; do
  # Add manual padding since gum table -p doesn't respect padding
  echo -e "Field,Value
Username,$username
Password,$(printf "%${#password}s" | tr ' ' '*')
Full name,${full_name:-[Skipped]}
Email address,${email_address:-[Skipped]}
Hostname,$hostname
Timezone,$timezone
Keyboard,$keyboard" |
    gum table -s "," -p | sed "s/^/${PADDING_LEFT_SPACES}/"

  echo
  if gum confirm --negative "No, change it" "Does this look right?"; then
    break
  else
    keyboard_form
    user_form
  fi
done

# STEP 3: DISK

get_disk_info() {
  local device="$1"
  local size vendor model label

  # Get basic disk information
  size=$(lsblk -dno SIZE "$device" 2>/dev/null)
  vendor=$(lsblk -dno VENDOR "$device" 2>/dev/null | sed 's/ *$//')
  model=$(lsblk -dno MODEL "$device" 2>/dev/null | sed 's/ *$//')

  # Combine vendor and model, avoiding duplication
  label=""
  if [[ -n $vendor && -n $model ]]; then
    if [[ $model == *$vendor* ]]; then
      label="$model"
    else
      label="$vendor $model"
    fi
  elif [[ -n $model ]]; then
    label="$model"
  elif [[ -n $vendor ]]; then
    label="$vendor"
  fi

  # Format display string
  local display="$device"
  [[ -n $size ]] && display="$display ($size)"
  [[ -n $label ]] && display="$display - $label"

  # Append compact partition summary
  local part_summary
  part_summary=$(lsblk -nro TYPE,NAME,FSTYPE,MOUNTPOINT "$device" 2>/dev/null | \
    awk '$1=="part" { printf "%s%s%s", s, ($3==""?"unknown":$3), ($4==""?"":"("$4")"); s=", " }')
  [[ -n $part_summary ]] && display+=" [$part_summary]"

  echo "$display"
}

get_root_disk() {
  local device="$1"
  local parent

  [[ -n $device ]] || return 1

  # /run/archiso/bootmnt usually resolves to the boot partition, but the
  # installer picker works with whole disks. Walk back to the parent disk so
  # the install media itself never shows up as a wipe target.
  device=$(readlink -f "$device" 2>/dev/null || printf "%s\n" "$device")

  while true; do
    parent=$(lsblk -dno PKNAME "$device" 2>/dev/null | tail -n1)
    [[ -n $parent ]] || break
    device="/dev/$parent"
  done

  if [[ $(lsblk -dno TYPE "$device" 2>/dev/null) == "disk" ]]; then
    printf "%s\n" "$device"
  fi
}

# Compute partition device path, handling NVMe/mmcblk's pN naming.
partition_path() {
  local _disk="$1" _num="$2"
  if [[ "$_disk" == *nvme* || "$_disk" == *mmcblk* ]]; then
    echo "${_disk}p${_num}"
  else
    echo "${_disk}${_num}"
  fi
}

# BitLocker writes the "-FVE-FS-" signature at offset 3 of the partition.
detect_bitlocker() {
  local p sig
  for p in $(lsblk -lnpo NAME,TYPE "$disk" | awk '$2=="part"{print $1}'); do
    sig=$(dd if="$p" bs=1 skip=3 count=8 status=none 2>/dev/null)
    if [[ "$sig" == "-FVE-FS-" ]]; then
      echo "$p"
      return 0
    fi
  done
  return 1
}

# Look for an existing Windows ESP (FAT partition containing EFI/Microsoft) on $disk.
detect_windows_esp() {
  local p tmp_mp
  for p in $(blkid -t TYPE=vfat -o device 2>/dev/null); do
    [[ "$p" == "$disk"* ]] || continue
    tmp_mp=$(mktemp -d)
    if mount -o ro "$p" "$tmp_mp" 2>/dev/null; then
      if [[ -d "$tmp_mp/EFI/Microsoft" ]]; then
        umount "$tmp_mp"; rmdir "$tmp_mp"
        echo "$p"
        return 0
      fi
      umount "$tmp_mp"
    fi
    rmdir "$tmp_mp" 2>/dev/null || true
  done
  return 1
}

to_gb() {
  awk -v bytes="$1" 'BEGIN {printf "%.1fGB", bytes/1024/1024/1024}'
}

run_partition_install() {
  local dry=false
  [[ "${1:-}" == "dry" ]] && dry=true

  step "Checking for BitLocker on $disk"
  local bl_part
  bl_part=$(detect_bitlocker || true)
  if [[ -n "$bl_part" ]]; then
    gum style --foreground 1 "BitLocker signature detected on $bl_part."
    gum style "Suspend or disable BitLocker in Windows before installing alongside it."
    abort "Aborted: BitLocker is active on this disk."
  fi

  step "Looking for an existing Windows ESP on $disk"
  local shared_esp
  shared_esp=$(detect_windows_esp || true)

  if [[ -n "$shared_esp" ]]; then
    gum style "Found Windows ESP at $shared_esp — will install alongside."
    local tmp_mp esp_free_mib
    tmp_mp=$(mktemp -d)
    mount -o ro "$shared_esp" "$tmp_mp"
    esp_free_mib=$(df -BM --output=avail "$tmp_mp" | tail -1 | tr -dc '0-9')
    umount "$tmp_mp"; rmdir "$tmp_mp"
    if (( esp_free_mib < 100 )); then
      abort "Windows ESP $shared_esp has only ${esp_free_mib}MiB free — need at least 100MiB for Omarchy."
    fi
    gum style "Windows ESP has ${esp_free_mib}MiB free."
  else
    gum style "No Windows ESP detected on $disk — a new EFI partition will be created in free space."
  fi

  step "Analyzing free space on $disk"
  partprobe "$disk" 2>/dev/null || true
  sleep 1
  parted --script "$disk" unit B print free 2>/dev/null || lsblk -b "$disk"
  echo

  local FREE_SPACE_INFO
  FREE_SPACE_INFO=$(parted -m "$disk" unit B print free 2>/dev/null | \
    awk -F: '
      $NF ~ /free/ {
        start=$2; end=$3; size=$4;
        gsub(/B/, "", start);
        gsub(/B/, "", end);
        gsub(/B/, "", size);
        if (size+0 > max_size+0) {
          max_size=size; max_start=start; max_end=end;
        }
      }
      END {
        if (max_size+0 > 0) printf "%s %s %s\n", max_start, max_end, max_size;
      }')

  if [[ -z "$FREE_SPACE_INFO" ]]; then
    gum style --foreground 1 "No usable free space detected on $disk."
    gum style "Partition install uses unallocated free space, not a pre-created partition."
    gum style "Open the partition tool, delete/shrink partitions until the target area says Free space, then leave it unallocated."
    gum confirm --affirmative "Back" --negative "Back" "Return to installation mode?" >/dev/null 2>&1 || true
    return 1
  fi

  local FREE_START_B FREE_END_B FREE_SIZE_B
  FREE_START_B=$(echo "$FREE_SPACE_INFO" | awk '{print $1}')
  FREE_END_B=$(echo "$FREE_SPACE_INFO"   | awk '{print $2}')
  FREE_SIZE_B=$(echo "$FREE_SPACE_INFO"  | awk '{print $3}')

  local mib=$((1024 * 1024)) gib=$((1024 * 1024 * 1024))
  local ALIGN=$mib
  local EFI_SIZE_B=$((2 * gib))
  local MIN_TOTAL_B=$((32 * gib))    # 32 GiB minimum for the install

  if (( FREE_SIZE_B < MIN_TOTAL_B )); then
    gum style --foreground 1 "Free space ($(to_gb $FREE_SIZE_B)) is below the 32GB minimum for Omarchy."
    gum style "Partition install uses unallocated free space, not a pre-created partition."
    gum style "Open the partition tool, delete/shrink partitions until the target area says Free space, then leave it unallocated."
    gum confirm --affirmative "Back" --negative "Back" "Return to installation mode?" >/dev/null 2>&1 || true
    return 1
  fi

  local EFI_START_B=0 EFI_END_B=0 ROOT_START_B ROOT_END_B
  if [[ -z "$shared_esp" ]]; then
    EFI_START_B=$(( (FREE_START_B + ALIGN - 1) / ALIGN * ALIGN ))
    EFI_END_B=$((EFI_START_B + EFI_SIZE_B))
    ROOT_START_B=$(( (EFI_END_B + 1 + ALIGN - 1) / ALIGN * ALIGN ))
  else
    ROOT_START_B=$(( (FREE_START_B + ALIGN - 1) / ALIGN * ALIGN ))
  fi
  ROOT_END_B=$((FREE_END_B / ALIGN * ALIGN))

  if (( ROOT_END_B <= ROOT_START_B )); then
    gum style --foreground 1 "Not enough aligned free space for partitions after alignment."
    gum confirm --affirmative "Back" --negative "Back" "Return to installation mode?" >/dev/null 2>&1 || true
    return 1
  fi

  step "Proposed layout on $disk"
  gum style "Free region: $(to_gb $FREE_START_B) — $(to_gb $FREE_END_B)  ($(to_gb $FREE_SIZE_B))"
  if [[ -z "$shared_esp" ]]; then
    gum style "  New EFI partition:  $(to_gb $EFI_START_B) — $(to_gb $EFI_END_B) (2GB FAT32)"
  else
    gum style "  Shared ESP:        $shared_esp (Windows, mounted at /efi)"
  fi
  gum style "  New root (Btrfs):  $(to_gb $ROOT_START_B) — $(to_gb $ROOT_END_B) ($(to_gb $((ROOT_END_B - ROOT_START_B))))"
  echo

  gum confirm --affirmative "Yes, partition" --negative "Cancel" \
    "Create Omarchy partitions in the free space on $disk?" || return 1

  echo
  if gum confirm \
    --affirmative "Yes, encrypt" \
    --negative "No, leave unencrypted" \
    "Encrypt the Omarchy root partition with LUKS2?"; then
    encrypt_installation=true
  else
    encrypt_installation=false
  fi

  if [[ "$encrypt_installation" == "true" && -n "$shared_esp" ]]; then
    abort "Encrypted install on a shared Windows ESP is not yet supported. Please choose unencrypted, or use Full Install."
  fi

  local esp_mount_in_target
  if [[ "$encrypt_installation" == "true" ]]; then
    esp_mount_in_target=/boot
  else
    esp_mount_in_target=/efi
  fi

  # Detect T2 Mac and set appropriate kernel
  if lspci -nn 2>/dev/null | grep -q "106b:180[12]"; then
    kernel_choice="linux-t2"
  else
    kernel_choice="linux"
  fi

  local last_part efi_part_num root_part_num
  last_part=$(lsblk -n -o PARTN "$disk" 2>/dev/null | grep -E '^[0-9]+$' | sort -n | tail -1)
  if [[ -z "$shared_esp" ]]; then
    efi_part_num=$(( ${last_part:-0} + 1 ))
    root_part_num=$(( efi_part_num + 1 ))
  else
    efi_part_num=0   # not created by us
    root_part_num=$(( ${last_part:-0} + 1 ))
  fi

  local efi_dev root_partition_device
  if [[ -n "$shared_esp" ]]; then
    efi_dev="$shared_esp"
  else
    efi_dev=$(partition_path "$disk" "$efi_part_num")
  fi
  root_partition_device=$(partition_path "$disk" "$root_part_num")

  if $dry; then
    gum style "[dry] would create root partition at $root_partition_device"
    [[ -z "$shared_esp" ]] && gum style "[dry] would create EFI partition at $efi_dev"
    gum style "[dry] encrypted=$encrypt_installation kernel=$kernel_choice"
  else
    step "Creating partitions on $disk"
    if [[ -z "$shared_esp" ]]; then
      parted --script "$disk" mkpart primary fat32 "${EFI_START_B}B" "${EFI_END_B}B"
      parted --script "$disk" set "$efi_part_num" esp on
      parted --script "$disk" name "$efi_part_num" "OMARCHY_EFI"
    fi
    parted --script "$disk" mkpart primary btrfs "${ROOT_START_B}B" "${ROOT_END_B}B"
    parted --script "$disk" name "$root_part_num" "OMARCHY_ROOT"
    partprobe "$disk"
    sync
    sleep 2

    local i
    for i in 1 2 3 4 5; do
      if [[ -b "$root_partition_device" ]] && { [[ -n "$shared_esp" ]] || [[ -b "$efi_dev" ]]; }; then
        break
      fi
      sleep 1
    done

    local root_mapper
    if [[ "$encrypt_installation" == "true" ]]; then
      step "Setting up LUKS2 on $root_partition_device"
      printf "%s" "$password" | cryptsetup luksFormat --type luks2 --batch-mode "$root_partition_device" -
      printf "%s" "$password" | cryptsetup open "$root_partition_device" omarchy_root -
      root_mapper="/dev/mapper/omarchy_root"
    else
      wipefs -af "$root_partition_device"
      root_mapper="$root_partition_device"
    fi

    step "Creating Btrfs filesystem and subvolumes"
    mkfs.btrfs -f -L OMARCHY "$root_mapper"
    for i in 1 2 3 4 5; do
      [[ -b "$root_mapper" ]] && break
      sleep 1
    done

    mkdir -p /mnt/btrfs-root
    mount "$root_mapper" /mnt/btrfs-root
    btrfs subvolume create /mnt/btrfs-root/@
    btrfs subvolume create /mnt/btrfs-root/@home
    btrfs subvolume create /mnt/btrfs-root/@log
    btrfs subvolume create /mnt/btrfs-root/@pkg
    umount /mnt/btrfs-root
    rmdir /mnt/btrfs-root

    mount -o noatime,compress=zstd,subvol=@ "$root_mapper" /mnt
    mkdir -p /mnt/home /mnt/var/log /mnt/var/cache/pacman/pkg /mnt"$esp_mount_in_target"
    mount -o noatime,compress=zstd,subvol=@home "$root_mapper" /mnt/home
    mount -o noatime,compress=zstd,subvol=@log  "$root_mapper" /mnt/var/log
    mount -o noatime,compress=zstd,subvol=@pkg  "$root_mapper" /mnt/var/cache/pacman/pkg

    if [[ -z "$shared_esp" ]]; then
      mkfs.fat -F32 -n OMARCHY_EFI "$efi_dev"
    fi
    mount "$efi_dev" /mnt"$esp_mount_in_target"
  fi

  clear

  echo "$full_name" >user_full_name.txt
  echo "$email_address" >user_email_address.txt
  printf '%s\n' "$encrypt_installation" >user_encrypt_installation.txt

  local password_escaped password_hash_escaped username_escaped
  password_escaped=$(echo -n "$password" | jq -Rsa)
  password_hash_escaped=$(echo -n "$password_hash" | jq -Rsa)
  username_escaped=$(echo -n "$username" | jq -Rsa)

  local credentials_encryption_line=""
  if [[ "$encrypt_installation" == "true" ]]; then
    credentials_encryption_line="    \"encryption_password\": $password_escaped,"
  fi

  cat <<-_EOF_ >user_credentials.json
{
$credentials_encryption_line
    "root_enc_password": $password_hash_escaped,
    "users": [
        {
            "enc_password": $password_hash_escaped,
            "groups": [],
            "sudo": true,
            "username": $username_escaped
        }
    ]
}
_EOF_

  cat <<-_EOF_ >user_configuration.json
{
    "app_config": null,
    "archinstall-language": "English",
    "auth_config": {},
    "audio_config": { "audio": "pipewire" },
    "bootloader": "No bootloader",
    "custom_commands": [],
    "disk_config": {
        "config_type": "pre_mounted_config",
        "mountpoint": "/mnt"
    },
    "hostname": "$hostname",
    "kernels": [ "$kernel_choice" ],
    "network_config": { "type": "iso" },
    "ntp": true,
    "parallel_downloads": 8,
    "script": null,
    "services": [],
    "swap": true,
    "timezone": "$timezone",
    "locale_config": {
        "kb_layout": "$keyboard",
        "sys_enc": "UTF-8",
        "sys_lang": "en_US.UTF-8"
    },
    "mirror_config": {
        "custom_repositories": [],
        "custom_servers": [
            {"url": "https://mirror.omarchy.org/\$repo/os/\$arch"},
            {"url": "https://mirror.rackspace.com/archlinux/\$repo/os/\$arch"},
            {"url": "https://geo.mirror.pkgbuild.com/\$repo/os/\$arch"}
        ],
        "mirror_regions": {},
        "optional_repositories": []
    },
    "packages": [
        "base-devel",
        "git",
        "omarchy-keyring",
        "omarchy",
        "omarchy-installer"
    ],
    "profile_config": {
        "gfx_driver": null,
        "greeter": null,
        "profile": {}
    },
    "version": "3.0.9"
}
_EOF_

  local luks_uuid_json="null" luks_uuid
  if [[ "$encrypt_installation" == "true" ]]; then
    if $dry; then
      luks_uuid="00000000-0000-0000-0000-000000000000"
    else
      luks_uuid=$(blkid -s UUID -o value "$root_partition_device")
    fi
    luks_uuid_json="\"$luks_uuid\""
  fi

  cat >/root/protected_install.json <<JSON
{
  "esp_mount": "$esp_mount_in_target",
  "esp_path": "/EFI/Omarchy",
  "luks_uuid": $luks_uuid_json,
  "root_device": "$root_partition_device",
  "kernel": "$kernel_choice"
}
JSON

  if $dry; then
    echo -e "User Configuration:"
    cat user_configuration.json
    echo -e "\n\nUser Credentials:"
    cat user_credentials.json
    echo -e "\n\nUser Full Name:"
    cat user_full_name.txt
    echo -e "\nUser Email Address:"
    cat user_email_address.txt
    echo -e "\nDisk Encryption:"
    cat user_encrypt_installation.txt
    echo -e "\nProtected Install Intent:"
    cat /root/protected_install.json
    rm -f user_configuration.json user_credentials.json user_full_name.txt user_email_address.txt user_encrypt_installation.txt /root/protected_install.json
  fi
}

disk_form() {
  step "Let's select where to install Omarchy..."

  # Don't offer the install media as an option (Arch ISO mounts it here)
  local boot_source
  local exclude_disk
  boot_source=$(findmnt -no SOURCE /run/archiso/bootmnt 2>/dev/null || true)
  exclude_disk=$(get_root_disk "$boot_source")

  # List all installable disks, excluding the boot device if present
  local available_disks
  available_disks=$(
    lsblk -dpno NAME,TYPE |
      awk '$2=="disk"{print $1}' |
      grep -E '/dev/(sd|hd|vd|nvme|mmcblk|xv)' |
      { if [[ -n "$exclude_disk" ]]; then grep -Fvx "$exclude_disk"; else cat; fi; }
  )

  # Get available disks and format them with info
  local disk_options=""
  while IFS= read -r device; do
    if [[ -n "$device" ]]; then
      disk_info=$(get_disk_info "$device")
      disk_options="$disk_options$disk_info"$'\n'
    fi
  done <<<"$available_disks"

  selected_display=$(echo "$disk_options" | gum choose --header "Select install disk") || abort
  disk=$(echo "$selected_display" | awk '{print $1}')
}

disk_form

# STEP 4: INSTALL MODE

open_partition_tool() {
  step "Partition tool for $disk"
  gum style "Create unallocated free space for Omarchy, then write changes and quit."
  gum style --foreground 8 "Do not create an Omarchy partition here — leave the target area as Free space."
  gum style --foreground 8 "Tip: free-space install needs at least 32GB unallocated, plus 2GB more if no ESP already exists."
  echo
  gum confirm --affirmative "Open cfdisk" --negative "Back" "Open partition tool for $disk?" || return 0

  clear
  cfdisk "$disk" || true
  partprobe "$disk" 2>/dev/null || true
  sync
  sleep 1
}

install_mode_form() {
  step "Installation mode"
  install_mode=$(gum choose --header "How should Omarchy be installed on $disk?" \
    "Full disk install" \
    "Free space install (alongside existing data)" \
    "Open partition tool") || abort
}

while true; do
  install_mode_form

  case "$install_mode" in
    "Full disk install")
      break
      ;;
    "Free space install (alongside existing data)")
      if run_partition_install "$@"; then
        exit 0
      fi
      ;;
    "Open partition tool")
      open_partition_tool
      ;;
  esac
done

confirm_disk_overwrite() {
  local mode="encrypted"
  local affirmative confirm_status

  while true; do
    clear_logo
    echo
    gum style "Everything will be overwritten. There is no recovery possible."

    if [[ $mode == "encrypted" ]]; then
      gum style --foreground 8 "Press Ctrl+C for unencrypted install."
      affirmative="Yes, install"
    else
      affirmative="Yes, install without encryption"
    fi

    echo
    gum confirm --affirmative "$affirmative" --negative "No, change it" "Confirm overwriting ${disk}"
    confirm_status=$?

    case $confirm_status in
      0)
        [[ $mode == "encrypted" ]] && encrypt_installation=true || encrypt_installation=false
        return 0
        ;;
      1)
        return 1
        ;;
      130)
        [[ $mode == "encrypted" ]] && mode="unencrypted" || mode="encrypted"
        ;;
      *)
        abort
        ;;
    esac
  done
}

while ! confirm_disk_overwrite; do
  disk_form
done

clear

# Save user full name and email address, so the autostart can
# set them as OMARCHY_USER_NAME and OMARCHY_USER_EMAIL
echo "$full_name" >user_full_name.txt
echo "$email_address" >user_email_address.txt

# Escape username and password for safe inclusion
password_escaped=$(echo -n "$password" | jq -Rsa)
password_hash_escaped=$(echo -n "$password_hash" | jq -Rsa)
username_escaped=$(echo -n "$username" | jq -Rsa)

if [[ $encrypt_installation == true ]]; then
  credentials_encryption_line="    \"encryption_password\": $password_escaped,"
else
  credentials_encryption_line=""
fi

cat <<-_EOF_ >user_credentials.json
{
$credentials_encryption_line
    "root_enc_password": $password_hash_escaped,
    "users": [
        {
            "enc_password": $password_hash_escaped,
            "groups": [],
            "sudo": true,
            "username": $username_escaped
        }
    ]
}
_EOF_

printf '%s\n' "$encrypt_installation" >user_encrypt_installation.txt

# Setup partition layout
disk_size=$(lsblk -bdno SIZE "$disk")
mib=$((1024 * 1024))
gib=$((mib * 1024))
disk_size_in_mib=$((disk_size / mib * mib)) # Rounds to nearest MiB

gpt_backup_reserve=$((mib))
boot_partition_start=$((mib))
boot_partition_size=$((2 * gib))

main_partition_start=$((boot_partition_size + boot_partition_start))
main_partition_size=$((disk_size_in_mib - main_partition_start - gpt_backup_reserve))

# Detect T2 Mac and set appropriate kernel
if lspci -nn 2>/dev/null | grep -q "106b:180[12]"; then
  kernel_choice="linux-t2"
else
  kernel_choice="linux"
fi

if [[ $encrypt_installation == true ]]; then
  disk_encryption_config=$(cat <<-_EOF_
,
        "disk_encryption": {
            "encryption_type": "luks",
            "lvm_volumes": [],
            "iter_time": 2000,
            "partitions": [ "8c2c2b92-1070-455d-b76a-56263bab24aa" ],
            "encryption_password": $password_escaped
        }
_EOF_
)
else
  disk_encryption_config=""
fi

cat <<-_EOF_ >user_configuration.json
{
    "app_config": null,
    "archinstall-language": "English",
    "auth_config": {},
    "audio_config": { "audio": "pipewire" },
    "bootloader_config": { "bootloader": "Limine", "uki": false, "removable": false },
    "custom_commands": [],
    "disk_config": {
        "btrfs_options": { 
          "snapshot_config": {
            "type": "Snapper"
          }
        },
        "config_type": "default_layout",
        "device_modifications": [
            {
                "device": "$disk",
                "partitions": [
                    {
                        "btrfs": [],
                        "dev_path": null,
                        "flags": [ "boot", "esp" ],
                        "fs_type": "fat32",
                        "mount_options": [],
                        "mountpoint": "/boot",
                        "obj_id": "ea21d3f2-82bb-49cc-ab5d-6f81ae94e18d",
                        "size": {
                            "sector_size": { "unit": "B", "value": 512 },
                            "unit": "B",
                            "value": $boot_partition_size
                        },
                        "start": {
                            "sector_size": { "unit": "B", "value": 512 },
                            "unit": "B",
                            "value": $boot_partition_start
                        },
                        "status": "create",
                        "type": "primary"
                    },
                    {
                        "btrfs": [
                            { "mountpoint": "/", "name": "@" },
                            { "mountpoint": "/home", "name": "@home" },
                            { "mountpoint": "/var/log", "name": "@log" },
                            { "mountpoint": "/var/cache/pacman/pkg", "name": "@pkg" }
                        ],
                        "dev_path": null,
                        "flags": [],
                        "fs_type": "btrfs",
                        "mount_options": [ "compress=zstd" ],
                        "mountpoint": null,
                        "obj_id": "8c2c2b92-1070-455d-b76a-56263bab24aa",
                        "size": {
                            "sector_size": { "unit": "B", "value": 512 },
                            "unit": "B",
                            "value": $main_partition_size
                        },
                        "start": {
                            "sector_size": { "unit": "B", "value": 512 },
                            "unit": "B",
                            "value": $main_partition_start
                        },
                        "status": "create",
                        "type": "primary"
                    }
                ],
                "wipe": true
            }
        ]$disk_encryption_config
    },
    "hostname": "$hostname",
    "kernels": [ "$kernel_choice" ],
    "network_config": { "type": "iso" },
    "ntp": true,
    "parallel_downloads": 8,
    "script": null,
    "services": [],
    "swap": true,
    "timezone": "$timezone",
    "locale_config": {
        "kb_layout": "$keyboard",
        "sys_enc": "UTF-8",
        "sys_lang": "en_US.UTF-8"
    },
    "mirror_config": {
        "custom_repositories": [],
        "custom_servers": [
            {"url": "https://mirror.omarchy.org/\$repo/os/\$arch"},
            {"url": "https://mirror.rackspace.com/archlinux/\$repo/os/\$arch"},
            {"url": "https://geo.mirror.pkgbuild.com/\$repo/os/\$arch"}
        ],
        "mirror_regions": {},
        "optional_repositories": []
    },
    "packages": [
        "base-devel",
        "git",
        "omarchy-keyring",
        "omarchy",
        "omarchy-installer"
    ],
    "profile_config": {
        "gfx_driver": null,
        "greeter": null,
        "profile": {}
    },
    "version": "3.0.9"
}
_EOF_

if [[ $1 == "dry" ]]; then
  echo -e "User Configuration:"
  cat user_configuration.json

  echo -e "\n\nUser Credentials:"
  cat user_credentials.json

  echo -e "\n\nUser Full Name:"
  cat user_full_name.txt

  echo -e "\nUser Email Address:"
  cat user_email_address.txt

  echo -e "\nDisk Encryption:"
  cat user_encrypt_installation.txt

  rm user_configuration.json user_credentials.json user_full_name.txt user_email_address.txt user_encrypt_installation.txt
fi
