#!/bin/bash
# das-server-install - console installer for Das OS Server.
#
# Usage: das-server-install [--config FILE]
#
# Asks its questions with dialog and installs the live image on a disk:
# GPT with an EFI or BIOS boot partition and Btrfs with the same subvolumes
# as the desktop installer, so snapshots and rollback work the same way.
# With --config it asks nothing and takes the answers from FILE (see
# /usr/share/examples/das-server-installer/install.conf).
set -Eeuo pipefail

log=/tmp/das-server-install.log
target=/mnt/das-target
source_root=/run/das-installer/root
libexec=/usr/libexec/das/installer

# Answers; a config file sets the same variables
DISK=""
HOST_NAME=dasos-server
USER_NAME=""
USER_PASSWORD=""
SSH_KEY=""
SSH_PASSWORDS=yes
TIMEZONE=Europe/Kyiv
KEYMAP=us
LOCALE=en_US.UTF-8
NETWORK=dhcpcd
ERASE_DISK=no

lang=en
[[ ${LANG:-} == uk* ]] && lang=uk

# t KEY: the message in the installer's language
t() {
  local key=$1
  if [[ $lang == uk ]]; then
    case $key in
      title) echo "Встановлення Das OS Server" ;;
      lang) echo "Мова встановлення:" ;;
      disk) echo "Диск для встановлення. Усі дані на ньому буде знищено." ;;
      nodisk) echo "Не знайдено дисків для встановлення." ;;
      host) echo "Ім'я сервера (латинські літери, цифри, дефіс):" ;;
      badhost) echo "Неправильне ім'я сервера." ;;
      user) echo "Ім'я користувача-адміністратора (вхід через sudo, root вимкнено):" ;;
      baduser) echo "Неправильне ім'я: малі латинські літери, цифри, _ та -, не root." ;;
      pass) echo "Пароль користувача:" ;;
      pass2) echo "Ще раз той самий пароль:" ;;
      badpass) echo "Паролі порожні або не збігаються." ;;
      key) echo "Публічний ключ SSH для входу (вставте рядок ssh-ed25519 ... або залиште порожнім):" ;;
      badkey) echo "Це не схоже на публічний ключ SSH." ;;
      nopass) echo "Заборонити вхід по SSH за паролем (лише за ключем)?" ;;
      tz) echo "Часовий пояс (наприклад, Europe/Kyiv, UTC):" ;;
      badtz) echo "Немає такого часового поясу." ;;
      keymap) echo "Розкладка клавіатури в консолі:" ;;
      locale) echo "Мова системи:" ;;
      net) echo "Мережа:" ;;
      net_dhcpcd) echo "dhcpcd: DHCP на всіх інтерфейсах (просто)" ;;
      net_nm) echo "NetworkManager: налаштування через nmtui (Wi-Fi, статичні адреси)" ;;
      summary) echo "Перевірте налаштування:" ;;
      erase) echo "УСІ ДАНІ НА ДИСКУ %s БУДЕ ЗНИЩЕНО. Продовжити?" ;;
      cancel) echo "Встановлення скасовано." ;;
      s_source) echo "Підготовка образу системи..." ;;
      s_disk) echo "Розмітка диска %s..." ;;
      s_copy) echo "Копіювання системи (кілька хвилин)..." ;;
      s_config) echo "Налаштування системи..." ;;
      s_post) echo "Локалі, знімки, initramfs (кілька хвилин)..." ;;
      s_boot) echo "Встановлення завантажувача..." ;;
      finished) echo "Das OS Server встановлено. Вийміть інсталяційний носій і перезавантажте сервер.\n\nВхід: %s, далі sudo. Служби: dsv. Користувачі: duser. Порти: dfw. Налаштування: dsys. Оновлення: das-update. Профіль розробника: dprofile install dev. Запрошення терміналу: dprompt. Банер при вході: dbanner." ;;
      reboot) echo "Перезавантажити зараз?" ;;
      failed) echo "Помилка встановлення. Журнал: %s" ;;
      root) echo "Інсталятор треба запускати від root (sudo das-server-install)." ;;
      yes) echo "так" ;;
      no) echo "ні" ;;
    esac
  else
    case $key in
      title) echo "Das OS Server installation" ;;
      lang) echo "Installation language:" ;;
      disk) echo "Disk to install to. All data on it will be erased." ;;
      nodisk) echo "No disks to install to were found." ;;
      host) echo "Server name (Latin letters, digits, hyphen):" ;;
      badhost) echo "Invalid server name." ;;
      user) echo "Administrator user name (uses sudo, root login is disabled):" ;;
      baduser) echo "Invalid name: lowercase Latin letters, digits, _ and -, not root." ;;
      pass) echo "User password:" ;;
      pass2) echo "The same password again:" ;;
      badpass) echo "The passwords are empty or do not match." ;;
      key) echo "SSH public key to log in with (paste the ssh-ed25519 ... line, or leave empty):" ;;
      badkey) echo "This does not look like an SSH public key." ;;
      nopass) echo "Disable SSH password login (keys only)?" ;;
      tz) echo "Time zone (for example Europe/Kyiv, UTC):" ;;
      badtz) echo "No such time zone." ;;
      keymap) echo "Console keyboard layout:" ;;
      locale) echo "System language:" ;;
      net) echo "Network:" ;;
      net_dhcpcd) echo "dhcpcd: DHCP on all interfaces (simple)" ;;
      net_nm) echo "NetworkManager: set up with nmtui (Wi-Fi, static addresses)" ;;
      summary) echo "Check the settings:" ;;
      erase) echo "ALL DATA ON %s WILL BE ERASED. Continue?" ;;
      cancel) echo "Installation cancelled." ;;
      s_source) echo "Preparing the system image..." ;;
      s_disk) echo "Partitioning %s..." ;;
      s_copy) echo "Copying the system (a few minutes)..." ;;
      s_config) echo "Configuring the system..." ;;
      s_post) echo "Locales, snapshots, initramfs (a few minutes)..." ;;
      s_boot) echo "Installing the boot loader..." ;;
      finished) echo "Das OS Server is installed. Remove the installation medium and reboot.\n\nLog in as %s, then use sudo. Services: dsv. Users: duser. Ports: dfw. Settings: dsys. Updates: das-update. Developer profile: dprofile install dev. Terminal prompt: dprompt. Login banner: dbanner." ;;
      reboot) echo "Reboot now?" ;;
      failed) echo "Installation failed. Log: %s" ;;
      root) echo "The installer must run as root (sudo das-server-install)." ;;
      yes) echo "yes" ;;
      no) echo "no" ;;
    esac
  fi
}

interactive=1
dialog_ui() {
  local labels=()
  if [[ $lang == uk ]]; then
    labels=(--ok-label "Гаразд" --cancel-label "Скасувати" --yes-label "Так" --no-label "Ні")
  fi
  dialog --backtitle "Das OS Server" --title "$(t title)" "${labels[@]}" "$@" 3>&1 1>&2 2>&3
}

# Shows a step in the dialog, or prints it when installing from a config file
step() {
  if [[ -n $interactive ]]; then
    dialog --backtitle "Das OS Server" --title "$(t title)" --infobox "$1" 5 70
    echo "==> $1" >>"$log"
  else
    echo "==> $1" | tee -a "$log"
  fi
}

fail() {
  trap - ERR
  local msg
  # shellcheck disable=SC2059
  msg=$(printf "$(t failed)" "$log")
  if [[ -n $interactive ]]; then
    dialog --backtitle "Das OS Server" --title "$(t title)" --msgbox "$msg\n\n$(tail -n 12 "$log" | sed 's/\\/\\\\/g')" 22 76 || true
    clear
  fi
  echo "das-server-install: $msg" >&2
  exit 1
}

cancelled() {
  [[ -n $interactive ]] && clear
  t cancel
  exit 1
}

# --- Questions -------------------------------------------------------------

# Disks that can be installed to: not read-only, not the live medium
list_disks() {
  local live="" dev
  if dev=$(blkid -L VOID_LIVE 2>/dev/null); then
    live=$(lsblk -no PKNAME "$dev" 2>/dev/null | head -n 1)
    [[ -n $live ]] && live=/dev/$live || live=$dev
  fi
  lsblk -dpno NAME,TYPE,RO,SIZE,MODEL | while read -r name type ro size model; do
    [[ $type == disk && $ro == 0 && $name != "$live" ]] || continue
    [[ $name == /dev/zram* || $name == /dev/loop* || $name == /dev/fd* ]] && continue
    printf '%s\t%s %s\n' "$name" "$size" "${model:-}"
  done
}

ask_language() {
  local choice
  # The default console font shows Cyrillic as Latin look-alikes, so load one
  # with Cyrillic before the first "Українська". sudo runs us on its own pty
  # (tty says /dev/pts/N), so name the console; serial and ssh have TERM other
  # than linux and no font to set.
  [[ $TERM == linux ]] && { setfont -C /dev/tty0 cyr-sun16 2>/dev/null || true; }
  choice=$(dialog --backtitle "Das OS Server" --title "Das OS Server" \
    --default-item "$lang" --menu "Language / Мова:" 10 50 2 \
    en "English" uk "Українська" 3>&1 1>&2 2>&3) || cancelled
  lang=$choice
  if [[ $lang == uk ]]; then
    LOCALE=uk_UA.UTF-8
  fi
}

ask_disk() {
  local items=() name desc
  while IFS=$'\t' read -r name desc; do
    items+=("$name" "$desc")
  done < <(list_disks)
  if [[ ${#items[@]} -eq 0 ]]; then
    dialog_ui --msgbox "$(t nodisk)" 7 60 || true
    cancelled
  fi
  DISK=$(dialog_ui --menu "$(t disk)" 15 70 6 "${items[@]}") || cancelled
}

valid_host() {
  [[ $1 =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$ ]]
}

valid_user() {
  [[ $1 =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] || return 1
  case $1 in root | live | nobody | daemon | bin | sys) return 1 ;; esac
}

valid_key() {
  [[ -z $1 || $1 =~ ^(ssh-(ed25519|rsa|dss)|ecdsa-sha2-[a-z0-9]+|sk-[a-z0-9@.-]+)\ [A-Za-z0-9+/=]+ ]]
}

ask_host() {
  while :; do
    HOST_NAME=$(dialog_ui --inputbox "$(t host)" 8 60 "$HOST_NAME") || cancelled
    valid_host "$HOST_NAME" && return
    dialog_ui --msgbox "$(t badhost)" 6 50 || true
  done
}

ask_user() {
  local p1 p2
  while :; do
    USER_NAME=$(dialog_ui --inputbox "$(t user)" 9 60 "$USER_NAME") || cancelled
    valid_user "$USER_NAME" && break
    dialog_ui --msgbox "$(t baduser)" 7 60 || true
  done
  while :; do
    p1=$(dialog_ui --insecure --passwordbox "$(t pass)" 8 60) || cancelled
    p2=$(dialog_ui --insecure --passwordbox "$(t pass2)" 8 60) || cancelled
    if [[ -n $p1 && $p1 == "$p2" ]]; then
      USER_PASSWORD=$p1
      return
    fi
    dialog_ui --msgbox "$(t badpass)" 6 50 || true
  done
}

ask_ssh() {
  while :; do
    SSH_KEY=$(dialog_ui --inputbox "$(t key)" 10 76 "$SSH_KEY") || cancelled
    valid_key "$SSH_KEY" && break
    dialog_ui --msgbox "$(t badkey)" 6 50 || true
  done
  SSH_PASSWORDS=yes
  if [[ -n $SSH_KEY ]] && dialog_ui --yesno "$(t nopass)" 7 60; then
    SSH_PASSWORDS=no
  fi
}

ask_system() {
  while :; do
    TIMEZONE=$(dialog_ui --inputbox "$(t tz)" 8 60 "$TIMEZONE") || cancelled
    [[ -f /usr/share/zoneinfo/$TIMEZONE ]] && break
    dialog_ui --msgbox "$(t badtz)" 6 50 || true
  done
  KEYMAP=$(dialog_ui --default-item "$KEYMAP" --menu "$(t keymap)" 15 50 7 \
    us "English (US)" ua-utf "Українська" uk "English (UK)" de-latin1 "Deutsch" \
    fr-latin1 "Français" pl2 "Polski") || cancelled
  LOCALE=$(dialog_ui --default-item "$LOCALE" --menu "$(t locale)" 10 50 2 \
    en_US.UTF-8 "English" uk_UA.UTF-8 "Українська") || cancelled
  NETWORK=$(dialog_ui --default-item "$NETWORK" --menu "$(t net)" 10 76 2 \
    dhcpcd "$(t net_dhcpcd)" NetworkManager "$(t net_nm)") || cancelled
}

confirm() {
  local key pw msg
  key=$(t no)
  pw=$(t yes)
  [[ -n $SSH_KEY ]] && key=$(t yes)
  [[ $SSH_PASSWORDS == no ]] && pw=$(t no)
  dialog_ui --no-collapse --msgbox "$(t summary)

  Disk:          $DISK
  Host:          $HOST_NAME
  User:          $USER_NAME
  SSH key:       $key
  SSH passwords: $pw
  Time zone:     $TIMEZONE
  Keyboard:      $KEYMAP
  Language:      $LOCALE
  Network:       $NETWORK" 18 60 || cancelled
  # shellcheck disable=SC2059
  msg=$(printf "$(t erase)" "$DISK")
  dialog_ui --defaultno --yesno "$msg" 7 60 || cancelled
  ERASE_DISK=yes
}

# --- Installation ----------------------------------------------------------

# part N: the device of partition N on $DISK
part() {
  lsblk -lnpo NAME,TYPE "$DISK" | awk '$2 == "part" { print $1 }' | sed -n "${1}p"
}

in_target() {
  chroot "$target" "$@"
}

# Undo mounts from an earlier attempt or a failure
unmount_target() {
  if mountpoint -q "$target"; then
    umount -R "$target" || umount -Rl "$target"
  fi
}

uefi() {
  [[ -d /sys/firmware/efi ]]
}

serial_console() {
  grep -q 'console=ttyS0' /proc/cmdline
}

partition() {
  local efi root
  unmount_target
  wipefs -a "$DISK"
  sgdisk --zap-all "$DISK"
  if uefi; then
    sgdisk -n 1:0:+512M -t 1:ef00 -c 1:EFI -n 2:0:0 -t 2:8300 -c 2:dasos "$DISK"
  else
    # GRUB on BIOS keeps its core image in a small partition on GPT
    sgdisk -n 1:0:+1M -t 1:ef02 -c 1:bios -n 2:0:0 -t 2:8300 -c 2:dasos "$DISK"
  fi
  partprobe "$DISK" 2>/dev/null || true
  udevadm settle
  efi=$(part 1)
  root=$(part 2)
  [[ -b $root ]] || return 1

  uefi && mkfs.vfat -F 32 -n EFI "$efi"
  mkfs.btrfs -f -L dasos "$root"

  # The same subvolumes as the Calamares configuration (mount.conf)
  mkdir -p "$target"
  mount "$root" "$target"
  for sv in @ @home @snapshots @var_log @var_cache_xbps; do
    btrfs subvolume create "$target/$sv"
  done
  umount "$target"

  local opts=noatime,compress=zstd:1
  mount -o "$opts,subvol=@" "$root" "$target"
  mkdir -p "$target"/{home,.snapshots,var/log,var/cache/xbps}
  mount -o "$opts,subvol=@home" "$root" "$target/home"
  mount -o "$opts,subvol=@snapshots" "$root" "$target/.snapshots"
  mount -o "$opts,subvol=@var_log" "$root" "$target/var/log"
  mount -o "$opts,subvol=@var_cache_xbps" "$root" "$target/var/cache/xbps"
  if uefi; then
    mkdir -p "$target/boot/efi"
    mount -o umask=0077 "$efi" "$target/boot/efi"
  fi
}

copy_system() {
  # No --sparse: GRUB can't read kernels with Btrfs holes (see postinstall)
  rsync -aHAX --numeric-ids "$source_root/" "$target/"
}

write_fstab() {
  local root_uuid efi_uuid opts=noatime,compress=zstd:1
  root_uuid=$(blkid -s UUID -o value "$(part 2)")
  {
    echo "# <file system> <dir> <type> <options> <dump> <pass>"
    echo "UUID=$root_uuid / btrfs $opts,subvol=@ 0 0"
    echo "UUID=$root_uuid /home btrfs $opts,subvol=@home 0 0"
    echo "UUID=$root_uuid /.snapshots btrfs $opts,subvol=@snapshots 0 0"
    echo "UUID=$root_uuid /var/log btrfs $opts,subvol=@var_log 0 0"
    echo "UUID=$root_uuid /var/cache/xbps btrfs $opts,subvol=@var_cache_xbps 0 0"
    if uefi; then
      efi_uuid=$(blkid -s UUID -o value "$(part 1)")
      echo "UUID=$efi_uuid /boot/efi vfat defaults,umask=0077 0 2"
    fi
  } >"$target/etc/fstab"
}

mount_chroot() {
  mount -t proc proc "$target/proc"
  mount -t sysfs sys "$target/sys"
  mount --rbind /dev "$target/dev"
  mount -t tmpfs tmpfs "$target/run"
  if uefi; then
    mount -t efivarfs efivarfs "$target/sys/firmware/efi/efivars" 2>/dev/null || true
  fi
}

# set_rc VAR VALUE: sets VAR in /etc/rc.conf, uncommenting Void's example line
set_rc() {
  local rc=$target/etc/rc.conf
  if grep -q "^#\?$1=" "$rc"; then
    sed -i "s|^#\?$1=.*|$1=\"$2\"|" "$rc"
  else
    echo "$1=\"$2\"" >>"$rc"
  fi
}

enable_service() {
  ln -sfn "/etc/sv/$1" "$target/etc/runit/runsvdir/default/$1"
}

disable_service() {
  rm -f "$target/etc/runit/runsvdir/default/$1"
}

configure() {
  local home

  # The live image's /etc/issue tells how to log in to the live system: keep
  # its first line, with the Das OS version
  printf '%s\n\n' "$(head -n1 /etc/issue)" >"$target/etc/issue"
  echo "$HOST_NAME" >"$target/etc/hostname"
  if ! grep -q "[[:space:]]$HOST_NAME\$" "$target/etc/hosts"; then
    printf '127.0.1.1\t%s\n' "$HOST_NAME" >>"$target/etc/hosts"
  fi
  echo "LANG=$LOCALE" >"$target/etc/locale.conf"
  ln -sfn "/usr/share/zoneinfo/$TIMEZONE" "$target/etc/localtime"
  set_rc KEYMAP "$KEYMAP"
  set_rc HARDWARECLOCK UTC
  [[ $LOCALE == uk* || $KEYMAP == ua* ]] && set_rc FONT cyr-sun16

  # The administrator: sudo through wheel, root has no password
  in_target useradd -m -s /bin/bash -G wheel,docker,socklog "$USER_NAME"
  # -c: Void's PAM stack for chpasswd only has pam_permit for passwords, so
  # without it nothing is written (Void's own installer does the same)
  printf '%s:%s\n' "$USER_NAME" "$USER_PASSWORD" | in_target chpasswd -c SHA512
  in_target passwd -l root >/dev/null
  echo "%wheel ALL=(ALL:ALL) ALL" >"$target/etc/sudoers.d/10-wheel"
  chmod 440 "$target/etc/sudoers.d/10-wheel"

  if [[ -n $SSH_KEY ]]; then
    home=$target/home/$USER_NAME
    install -d -m 700 "$home/.ssh"
    echo "$SSH_KEY" >"$home/.ssh/authorized_keys"
    chmod 600 "$home/.ssh/authorized_keys"
    in_target chown -R "$USER_NAME:$USER_NAME" "/home/$USER_NAME/.ssh"
  fi
  if [[ $SSH_PASSWORDS == no ]]; then
    printf '%s\n' "# Written by das-server-install: SSH keys only" \
      "PasswordAuthentication no" "KbdInteractiveAuthentication no" \
      >"$target/etc/ssh/sshd_config.d/40-das-keys-only.conf"
  fi

  for sv in sshd chronyd nftables fail2ban docker socklog-unix nanoklogd; do
    enable_service "$sv"
  done
  if [[ $NETWORK == NetworkManager ]]; then
    disable_service dhcpcd
    enable_service dbus
    enable_service NetworkManager
  else
    enable_service dhcpcd
  fi
  serial_console && enable_service agetty-ttyS0
  return 0
}

install_bootloader() {
  local grub=$target/etc/default/grub cmdline="loglevel=4"
  serial_console && cmdline+=" console=tty0 console=ttyS0,115200"
  sed -i -e '/^GRUB_DISTRIBUTOR=/d' -e '/^GRUB_CMDLINE_LINUX_DEFAULT=/d' -e '/^GRUB_TIMEOUT=/d' \
    -e '/^GRUB_TERMINAL/d' -e '/^GRUB_SERIAL_COMMAND=/d' -e '/^GRUB_DISABLE_OS_PROBER=/d' "$grub"
  {
    echo 'GRUB_DISTRIBUTOR="Das OS"'
    echo "GRUB_CMDLINE_LINUX_DEFAULT=\"$cmdline\""
    echo 'GRUB_TIMEOUT=5'
    echo 'GRUB_DISABLE_OS_PROBER=true'
    if serial_console; then
      echo 'GRUB_TERMINAL="console serial"'
      echo 'GRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200"'
    fi
  } >>"$grub"

  if uefi; then
    in_target grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=dasos
    # Also at the fallback path, for firmware that forgets boot entries
    in_target grub-install --target=x86_64-efi --efi-directory=/boot/efi --removable --no-nvram
  else
    in_target grub-install --target=i386-pc "$DISK"
  fi
}

finish() {
  # The first snapshot, also shown in the boot menu (like Calamares' shellprocess@snapshot)
  in_target snapper --no-dbus -c root create -d "Fresh install" -c number --userdata important=yes || true
  in_target grub-mkconfig -o /boot/grub/grub.cfg
  # The installer is not needed on the installed system
  in_target xbps-remove -y das-server-installer das-install-common || true
  sync
}

# Any failing command stops the installation with the log (set -E: also
# inside functions; "f || fail" would switch set -e off within f).
install_system() {
  : >"$log"
  trap fail ERR
  step "$(t s_source)"
  "$libexec/mount-source" >>"$log" 2>&1
  # shellcheck disable=SC2059
  step "$(printf "$(t s_disk)" "$DISK")"
  partition >>"$log" 2>&1
  step "$(t s_copy)"
  copy_system >>"$log" 2>&1
  step "$(t s_config)"
  write_fstab >>"$log" 2>&1
  mount_chroot >>"$log" 2>&1
  configure >>"$log" 2>&1
  step "$(t s_post)"
  in_target "$libexec/postinstall" >>"$log" 2>&1
  step "$(t s_boot)"
  install_bootloader >>"$log" 2>&1
  finish >>"$log" 2>&1
  unmount_target >>"$log" 2>&1
  trap - ERR
}

load_config() {
  local file=$1
  [[ -r $file ]] || {
    echo "das-server-install: cannot read $file" >&2
    exit 1
  }
  # shellcheck source=/dev/null
  . "$file"
  interactive=""
  local bad=""
  [[ -b $DISK ]] || bad+=" DISK"
  valid_host "$HOST_NAME" || bad+=" HOST_NAME"
  valid_user "$USER_NAME" || bad+=" USER_NAME"
  [[ -n $USER_PASSWORD ]] || bad+=" USER_PASSWORD"
  valid_key "$SSH_KEY" || bad+=" SSH_KEY"
  [[ $SSH_PASSWORDS == yes || ( $SSH_PASSWORDS == no && -n $SSH_KEY ) ]] || bad+=" SSH_PASSWORDS"
  [[ -f /usr/share/zoneinfo/$TIMEZONE ]] || bad+=" TIMEZONE"
  [[ $NETWORK == dhcpcd || $NETWORK == NetworkManager ]] || bad+=" NETWORK"
  [[ $ERASE_DISK == yes ]] || bad+=" ERASE_DISK"
  if [[ -n $bad ]]; then
    echo "das-server-install: invalid or missing in $file:$bad" >&2
    exit 1
  fi
}

main() {
  if [[ $EUID -ne 0 ]]; then
    exec sudo --preserve-env=LANG "$0" "$@"
  fi
  case ${1:-} in
    --config)
      load_config "${2:?--config needs a file}"
      ;;
    -h | --help)
      sed -n '2,11s/^# \{0,1\}//p' "$0"
      exit 0
      ;;
    "") ;;
    *)
      echo "das-server-install: unknown option $1" >&2
      exit 1
      ;;
  esac

  if [[ -n $interactive ]]; then
    ask_language
    ask_disk
    ask_host
    ask_user
    ask_ssh
    ask_system
    confirm
  fi
  install_system

  if [[ -n $interactive ]]; then
    local msg
    # shellcheck disable=SC2059
    msg=$(printf "$(t finished)" "$USER_NAME")
    if dialog_ui --yesno "$msg\n\n$(t reboot)" 12 70; then
      reboot
    fi
    clear
  else
    echo "==> done, log: $log"
  fi
}

main "$@"
