#!/usr/bin/bash
# SPDX-License-Identifier: GPL-3.0-or-later
set -euo pipefail

boot_dir=/boot
modules_root=/usr/lib/modules
installed_marker=/var/lib/devario/systemd-boot-installed
legacy_marker=/var/lib/devario/limine-installed
install_mode=false
check_only=false
case "${1:-}" in
  --install) install_mode=true; shift ;;
  --check) check_only=true; shift ;;
  '') ;;
  *) echo "Usage: ${0##*/} [--install|--check]" >&2; exit 64 ;;
esac
(( $# == 0 )) || exit 64
fail() { echo "devario-systemd-boot: $*" >&2; exit 1; }
note() { echo "devario-systemd-boot: $*"; }

# Assembly of the live image must never deploy a target bootloader.
if [[ "$install_mode" == false && "$check_only" == false \
  && ! -e "$installed_marker" && ! -e "$legacy_marker" ]]; then
  note 'target installation marker is absent; skipping live-image transaction'
  exit 0
fi
[[ -d /sys/firmware/efi ]] || fail 'UEFI is required. Reboot the installer in UEFI mode.'
if [[ -r /sys/firmware/efi/fw_platform_size ]]; then
  [[ "$(cat /sys/firmware/efi/fw_platform_size)" == 64 ]] \
    || fail 'Devario installation requires 64-bit UEFI firmware.'
fi
for tool in bootctl findmnt install chmod mktemp mv rm; do
  command -v "$tool" >/dev/null || fail "required command is unavailable: $tool"
done
[[ "$(findmnt -nro TARGET --mountpoint "$boot_dir")" == "$boot_dir" ]] \
  || fail "$boot_dir must be a mounted EFI System Partition."
[[ "$(findmnt -nro FSTYPE --mountpoint "$boot_dir")" == vfat ]] \
  || fail "$boot_dir must be a FAT EFI System Partition."
# Keep bootctl's partition-type validation enabled, including inside Calamares.
unset SYSTEMD_RELAX_ESP_CHECKS SYSTEMD_RELAX_XBOOTLDR_CHECKS
[[ "$(bootctl --esp-path="$boot_dir" --print-esp-path)" == "$boot_dir" ]] \
  || fail "$boot_dir is not a valid EFI System Partition."
[[ -s /usr/lib/systemd/boot/efi/systemd-bootx64.efi \
  || -s /usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed ]] \
  || fail 'the systemd-boot x86-64 EFI executable is missing'
[[ "$check_only" == false ]] || exit 0

helper_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
source "$helper_dir/kernel.sh"
devario_kernel_discover "$modules_root"
for kernel_id in "${DEVARIO_KERNEL_IDS[@]}"; do
  for file in "vmlinuz-$kernel_id" "initramfs-$kernel_id.img" "initramfs-$kernel_id-fallback.img"; do
    [[ -s "$boot_dir/$file" ]] || fail "$boot_dir/$file is missing or empty"
  done
done
kernel_cmdline="$("$helper_dir/kernel-command-line")"
[[ -n "$kernel_cmdline" && "$kernel_cmdline" != *$'\n'* && "$kernel_cmdline" != *$'\r'* ]] \
  || fail 'invalid generated kernel command line'
install -d -m 0755 "$boot_dir/loader/entries"
staging="$(mktemp -d "$boot_dir/loader/.devario-entries.XXXXXX")"
trap 'rm -rf -- "$staging"' EXIT
declare -a entries=() obsolete=()
declare -A active_entries=()
write_entry() {
  local filename="$1" title="$2" kernel="$3" initrd="$4" order="$5"
  printf 'title %s\nsort-key %s\nlinux %s\ninitrd %s\noptions %s\n' \
    "$title" "$order" "$kernel" "$initrd" "$kernel_cmdline" > "$staging/$filename"
  chmod 0644 "$staging/$filename"
  entries+=("$filename")
  active_entries[$filename]=1
}
default_entry=
for kernel_id in "${DEVARIO_KERNEL_IDS[@]}"; do
  case "$kernel_id" in
    linux-devario) entry=devario; title='Devario Linux' ;;
    linux-devario-lts) entry=devario-lts; title='Devario Linux LTS' ;;
    *) entry="devario-kernel-$kernel_id"; title="Devario Linux ($kernel_id)" ;;
  esac
  if [[ -z "$default_entry" || "$kernel_id" == linux-devario ]]; then
    default_entry="$entry.conf"
  fi
  write_entry "$entry.conf" "$title" "/vmlinuz-$kernel_id" "/initramfs-$kernel_id.img" "$entry-01"
  write_entry "$entry-fallback.conf" "$title (fallback initramfs)" \
    "/vmlinuz-$kernel_id" "/initramfs-$kernel_id-fallback.img" "$entry-02"
  recovery_dir="$boot_dir/devario-recovery/$kernel_id"
  if [[ -s "$recovery_dir/vmlinuz-$kernel_id" && -s "$recovery_dir/initramfs-$kernel_id.img" ]]; then
    write_entry "$entry-recovery.conf" "$title (previous kernel and initramfs)" \
      "/devario-recovery/$kernel_id/vmlinuz-$kernel_id" \
      "/devario-recovery/$kernel_id/initramfs-$kernel_id.img" "$entry-03"
  fi
done
# Only prune entries we previously generated, including the pre-manifest names.
manifest="$boot_dir/loader/devario-entries.list"
previous_entries=(devario.conf devario-fallback.conf devario-recovery.conf)
if [[ -f "$manifest" ]]; then
  while IFS= read -r file || [[ -n "$file" ]]; do
    [[ "$file" =~ ^devario(-[a-zA-Z0-9._+-]+)?\.conf$ ]] || fail 'invalid managed entry manifest'
    previous_entries+=("$file")
  done < "$manifest"
fi
for file in "${previous_entries[@]}"; do
  [[ -n "${active_entries[$file]:-}" ]] || obsolete+=("$file")
done
printf '%s\n' "${entries[@]}" > "$staging/devario-entries.list"
# Record this before bootctl, which may create its own default loader.conf.
if [[ ! -e "$boot_dir/loader/loader.conf" ]]; then
  printf 'default %s\ntimeout 5\neditor no\n' "$default_entry" > "$staging/loader.conf"
elif (( ${#obsolete[@]} )); then
  # Preserve user preferences, except an exact default pointing at an entry
  # being removed. Wildcards, saved defaults and other operating systems survive.
  awk -v removed="${obsolete[*]}" -v replacement="$default_entry" '
    BEGIN { n = split(removed, names, " "); for (i = 1; i <= n; i++) stale[names[i]] = 1 }
    $1 == "default" && $2 in stale { $2 = replacement }
    { print }
  ' "$boot_dir/loader/loader.conf" > "$staging/loader.conf"
fi

# Explicit installation also migrates existing UEFI Limine installations. Updates
# preserve firmware boot order. An unwritable NVRAM still permits fallback boot.
if [[ "$install_mode" == true || ! -e "$installed_marker" ]]; then
  if ! bootctl --esp-path="$boot_dir" --variables=yes install; then
    note 'firmware entry creation failed; installing the standard UEFI fallback'
    bootctl --esp-path="$boot_dir" --variables=no install
  fi
else
  # An equal or newer loader is a successful no-op during kernel updates.
  # Keep the ESP/source preflight above and deployment checks below strict.
  bootctl --esp-path="$boot_dir" --variables=no --graceful update
fi
# Recent bootctl versions may treat a chroot failure as graceful; check deployment.
for file in EFI/systemd/systemd-bootx64.efi EFI/BOOT/BOOTX64.EFI; do
  [[ -s "$boot_dir/$file" ]] || fail "systemd-boot deployment did not create $file"
done
# Leave the administrator's loader preferences and other operating systems alone.
if [[ -f "$staging/loader.conf" ]]; then
  chmod 0644 "$staging/loader.conf"
  mv -f -- "$staging/loader.conf" "$boot_dir/loader/loader.conf"
fi
for file in "${entries[@]}"; do
  mv -f -- "$staging/$file" "$boot_dir/loader/entries/$file"
done
for file in "${obsolete[@]}"; do
  rm -f -- "$boot_dir/loader/entries/$file"
done
chmod 0644 "$staging/devario-entries.list"
mv -f -- "$staging/devario-entries.list" "$manifest"
install -Dm0644 /dev/null "$installed_marker"
rm -f -- "$legacy_marker"
note 'systemd-boot and Devario boot entries are up to date'
