#!/usr/bin/env bash
# vim:et:ts=2:sts=2:sw=2

# Get absolute repository root (especially when symlinked)
ROOT="$(realpath "$(dirname "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")")")"

# Load accompanying bash library
source "$ROOT/lib/lib.bash"

BTRFS="${1:-"/var/btrfs"}"

if [ -n "$HELP" ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
  say "
  USAGE:
    $(g "${BASH_SOURCE##*/}")

  DESCRIPTION:
    $(g "${BASH_SOURCE##*/}") Provides a TUI listing and purging
      components hosted in $(g /srv) in a TechLit system

    OPTIONS:
      -h, --help      Show this help message and exit
  "
  exit 1
fi

# Exit now unless run as admin
assert-is-admin

say "This script will need root access via $(c sudo)"
sudo echo thank you

# Components to manage
COMPONENTS=("admin" "control" "curriculum" "desktop" "help" "recovery" "snapshots")
declare -A SELECTIONS

assert_comp_exist() {
  [ -d "/srv/$1" ] && return 0 || return 1
}

dialog_apply() {
  local initial final options=""

  if [ ${#SELECTIONS[@]} -gt 0 ]; then
    for comp in "${!SELECTIONS[@]}"; do
      options+="\n$comp: ${SELECTIONS["$comp"]}\n"
    done

    if ! dialog --clear --no-collapse --output-fd 1 --colors \
      --yesno "$(printf "\Zb\Z1Warning!!!\Zn You have selected to delete these
      $options \n
      This is irreversible. Proceed?")" 20 60; then
      return
    fi
  else
    dialog --clear --no-collapse --output-fd 1 \
      --backtitle "Summary of Selections" --title "\Zb\Z5Nothing Selected\Zn" \
      --colors --msgbox "\Z1 ϟϟϟϟϟϟϟϟϟ " 5 20
    return
  fi

  initial=$(sudo df -h "$BTRFS" --output=used -h | tail -n1)
  for component in "${!SELECTIONS[@]}"; do
    for version in ${SELECTIONS["$component"]}; do
      ver="/srv/$component/$version"
      if [ -d "$ver".d/@root ]; then
        run sudo btrfs subvol delete "$ver".d/@{root,guest} || :
        run sudo rm -rf "$ver".d
      else
        say "Deleting $ver"
        run sudo rm -rf "$ver".*
      fi
    done
  done
  final=$(sudo df -h "$BTRFS" --output=used -h | tail -n1)
  dialog --clear --no-collapse --output-fd 1 --msgbox "Components deleted successfully!\n
        Initial Disk Usage: $initial\n
        Final Disk Usage:   $final" 10 60
  SELECTIONS=()
}

dialog_update() {
  local usb mountpoint components selected rsync_log
  mountpoint="$(mktemp -d)"
  rsync_log="$(mktemp)"

  usb="$(
    dialog --clear --no-collapse --output-fd 1 \
      --inputbox "Enter the USB path (e.g. /dev/sdb):" 8 40
  )" || :

  if [ ! -b "$usb"4 ]; then
    dialog --msgbox "Invalid USB path. Please try again." 6 40
    return
  fi

  cleanup() { sudo umount -q "$mountpoint" && rm -rf "$mountpoint"; }
  if ! sudo mount "$usb"4 "$mountpoint"; then
    dialog --msgbox "Failed to mount USB drive." 6 40
    return
  fi

  for component in $(ls -d "$mountpoint"/*/ 2>/dev/null); do
    comp=$(basename "$component")
    components+=("$comp")
  done

  if [ ${#components[@]} -eq 0 ]; then
    dialog --msgbox "No components found on the USB drive." 6 40
    cleanup
    return
  fi

  local options=() component latest
  for component in "${components[@]}"; do
    latest="(COMP_DIR=$mountpoint tl-comp-sync $component)"
    options+=("$component" "$latest" "off")
  done

  selected="$(dialog \
    --clear --no-collapse --output-fd 1 \
    --backtitle "Manage Components" --title "Components Menu" \
    --checklist "Select components to sync:" 20 40 6 "${options[@]}")" || :

  if [ -z "$selected" ]; then
    dialog --msgbox "No components selected." 6 40
    cleanup
    return
  fi

  : >"$rsync_log"
  for component in $selected; do
    (
      echo "Syncing $component ..."
      rsync -a --progress "$mountpoint/$component"/* "/srv/$component/" &>>"$rsync_log" || :
      echo "Component $component synced!" &>>"$rsync_log"
      tl-comp-sync "$component"
    )
  done

  dialog --tailbox "$rsync_log" 20 70
  rm "$rsync_log"
  cleanup
}

dialog_wipe() {
  if ! dialog --clear --no-collapse --output-fd 1 --colors \
    --yesno "\ZbDelete all temporary files?" 6 60; then
    return
  fi

  # Incomplete unpacks
  run sudo find /srv/snapshots -maxdepth 1 -type d -name 'tmp-*' -exec sudo rm -rf {} + || :

  # Downloaded using aria2
  run find /srv \( -path /srv/snapshots -o -path /srv/secure -o -path /srv/public \) -prune -o \
    -type f -name '*.aria2' -print | while read -r aria2_file; do
    file="${aria2_file%.aria2}"
    run rm -f "$file"*
  done || :

  # incomplete rsync downloads
  for comp in "${COMPONENTS[@]}"; do
    [ -d "/srv/$comp/.rsync" ] || continue
    run sudo rm -rf /srv/"$comp"/.rsync/*
  done
}

dialog_versions_menu() {
  local component="$1"
  local options=() version_name usage answer
  local selected_versions=("${SELECTIONS["$component"]}")

  for version in /srv/"$component"/*.{tar.gz,iso,d}; do
    [ -r "$version" ] || continue
    version_name="$(basename "$(echo "$version" | sed -E 's/\.(tar\.gz|iso|d)$//')")"
    usage="$(sudo du -sxh "$version" | awk '{print $1}')"

    if [[ " ${selected_versions[*]} " == *" $version_name "* ]]; then
      options+=("$version_name" "$usage" on)
    else
      options+=("$version_name" "$usage" off)
    fi
  done

  if [ ${#options[@]} -eq 0 ]; then
    dialog --colors --msgbox "\Zb\Z1404:\Zn No component found" 6 30
    dialog_main_menu
    return
  fi

  answer="$(dialog \
    --clear --no-collapse --output-fd 1 \
    --backtitle "Manage Versions of $component" --title "Versions Menu" \
    --checklist "Select versions to delete:" 20 40 6 "${options[@]}")" || :

  if [ -n "$answer" ]; then
    SELECTIONS["$component"]="$answer"
  fi

  dialog_main_menu
}

dialog_quit() {
  if ! dialog --yesno "Quit?" 6 60; then
    return
  fi
  clear
  exit 0
}

dialog_main_menu() {
  local disk_usage
  while true; do
    local answer options=() usage
    for component in "${COMPONENTS[@]}"; do
      if assert_comp_exist "$component"; then
        usage=$(sudo du -sxh "$(readlink -f "/srv/$component")" 2>/dev/null | awk '{print $1}')
        options+=("$component" "$usage")
      fi
    done

    disk_usage="$(sudo df -h "$BTRFS" --output=source,size,used,avail,pcent -h | tail -n1)"
    options+=("Sync" "Update components from USB")
    options+=("Apply" "Delete all selections")
    options+=("Wipe" "Delete Temporary/incomplete files")
    options+=("Quit" "Exit without changes")
    answer=$(dialog --colors \
      --clear --no-collapse --output-fd 1 \
      --backtitle "Manage Components" --title "Components management" \
      --menu "\Zb\Z4DISK: \Zn$disk_usage" 18 55 20 "${options[@]}")

    case "$answer" in
      "Sync") dialog_update ;;
      "Apply") dialog_apply ;;
      "Wipe") dialog_wipe ;;
      Quit) dialog_quit ;;
      *) dialog_versions_menu "$answer" ;;
    esac
  done
}

[[ "$0" = "${BASH_SOURCE[0]}" ]] && dialog_main_menu
