#!/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 managing
      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 requires root access"
sudo echo thank you

declare -A SELECTIONS                                                               # Store versions to be deleted
SRV="$BTRFS/@srv"                                                                   # Components directory
COMPONENTS=("admin" "control" "curriculum" "desktop" "help" "recovery" "snapshots") # Components to manage
ANSWER=""                                                                           # Dialog answer placeholder
LOCKFILE="/tmp/tl-comp-manage.lock"                                                 # Lockfile

if [ -e "$LOCKFILE" ]; then
  err "Another instance is already running. Exiting."
  exit 1
fi

cleanup() {
  rm -f "$LOCKFILE"
}

# Helper function for displaying dialog menus
# USAGE: menu "Title" --yesno "Message" 10 60
#        menu "Title" --checklist "Message" 20 40 6 "Option 1" "Description 1" "Option 2" "Description 2"
menu() {
  ANSWER="$(
    dialog \
      --clear --no-collapse --output-fd 1 --colors \
      --backtitle "Manage components hosted in $SRV" --title "$@"
  )"
}

# Deletes all selected components in SELECTIONS
apply_selections() {
  local pre_disk_usage post_disk_usage options

  pre_disk_usage=$(sudo df -h "$BTRFS" --output=used -h | tail -n1)

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

    if ! menu "Summary of Selections" --yesno \
      "\Zb\Z1 Warning!!!\Zn You have selected to delete these \n\n       \Zb\Z2 $options\n \Zn\n       \Zb\Z1 This is irreversible. Proceed?" 20 60; then
      return
    fi
  else
    menu "\Z1Nothing selected" --pause "" 7 20 3
    return
  fi

  for component in "${!SELECTIONS[@]}"; do
    for version in ${SELECTIONS["$component"]}; do
      ver="$SRV/$component/$version"
      [ -z "$ver" ] && return

      # If the component is snapshot, delete the subvolumes first
      if [ -d "$ver".d/@root ] || [ -d "$ver".d/@guest ]; then
        run sudo btrfs subvol delete "$ver".d/@{root,guest} || continue
      fi
      run sudo rm -rf "$ver".*
    done
  done

  run sudo sync
  post_disk_usage="$(sudo df -h "$BTRFS" --output=used -h | tail -n1)"

  menu "Components deleted successfully!" \
    --pause "Initial Disk Usage: $pre_disk_usage \n\n Final Disk Usage:   $post_disk_usage" 10 60 5

  SELECTIONS=()
}

purge_components() {
  if ! menu "Purge Components" --yesno \
    "\ZbDelete all temporary files?" 6 60; then
    return
  fi

  # Incomplete unpacks
  for dir in $(sudo find "$SRV"/snapshots -maxdepth 1 -type d -name 'tmp-*'); do
    if [ -d "$dir"/@root ] || [ -d "$dir"/@guest ]; then
      run sudo btrfs subvol delete "$dir"/@{root,guest} || :
    fi
    run sudo rm -rf "$dir" || :
  done

  # aria2 downloads
  run find "$SRV"/desktop "$SRV"/curriculum "$SRV"/recovery "$SRV"/admin \
    -type f -name '*.aria2' -print | while read -r tmp_file; do

    file="${tmp_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
}

quit_program() {
  if ! menu "Quit" --yesno "quit?" 6 60; then
    return
  fi
  exit 0
}

# Lists a component and its versions as options and save them to SELECTIONS
sub_menu() {
  local component="$1"
  local version_name usage is_selected
  local -a options=() all_versions=()
  declare -A version_usages

  # Store initial state as a simple string to restore on cancel
  local initial_selections="${SELECTIONS[$component]}"
  # Use a temporary variable for selections within the loop
  local current_selections="${SELECTIONS[$component]}"

  # Gather all available versions and their sizes for this 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)$//')")"
    all_versions+=("$version_name")
    usage="$(sudo du -sxh "$version" | awk '{print $1}')"
    version_usages["$version_name"]="$usage"
  done

  if [ ${#all_versions[@]} -eq 0 ]; then
    menu "Selected" --msgbox "\Zb\Z1404:\Zn No component found" 6 30
    return
  fi

  while true; do
    options=()
    # Add special options first
    options+=("SELECT_ALL" "(Select All)" "off")
    options+=("DESELECT_ALL" "(Deselect All)" "off")

    for version_name in "${all_versions[@]}"; do
      is_selected="off"
      # Word splitting is intentional here
      # shellcheck disable=SC2086
      for sel in $current_selections; do
        if [ "$sel" = "$version_name" ]; then
          is_selected="on"
          break
        fi
      done
      options+=("$version_name" "${version_usages[$version_name]}" "$is_selected")
    done

    if ! ANSWER="$(
      dialog \
        --clear --no-collapse --output-fd 1 --colors \
        --backtitle "Manage components hosted in $SRV" --title "Versions Menu" \
        --checklist "Select versions, an action, then OK to refresh." \
        20 60 10 "${options[@]}"
    )"; then
      # User pressed Cancel or ESC, restore initial state
      SELECTIONS["$component"]="$initial_selections"
      break
    fi

    # Check for specified action
    local action_taken=false
    if [[ "$ANSWER" == *"SELECT_ALL"* ]]; then
      current_selections="$(printf '%s ' "${all_versions[@]}")"
      action_taken=true
    fi

    # Separate check for DESELECT_ALL to allow selecting all then deselecting all in one go
    if [[ "$ANSWER" == *"DESELECT_ALL"* ]]; then
      current_selections=""
      action_taken=true
    fi

    # If no action was taken, it's a final selection.
    if ! $action_taken; then
      # Filter out our action tags from the final answer
      ANSWER="${ANSWER//SELECT_ALL/}"
      ANSWER="${ANSWER//DESELECT_ALL/}"
      SELECTIONS["$component"]="$ANSWER"
      break
    fi
  done

  ANSWER=""
}

# The main menu: Loops over components check if it exists and display them as options
# Then run sub_menu with the selected component
main_menu() {
  touch "$LOCKFILE" || {
    err "Failed to create lock file. Exiting."
    exit 1
  }
  local disk_usage version options=() latest usage
  disk_usage=$(sudo df -h "$BTRFS" --output=size,used,avail,pcent \
    | tail -n1 | awk '{printf "Total: %s | Available: %s | Used: %s", $1, $3, $4}')

  while true; do
    options=() # Resetting here to avoid multiple lists
    for component in "${COMPONENTS[@]}"; do
      [ -d "$SRV/$component" ] || continue
      version="$(tl-comp-latest "$component" 2>/dev/null)"
      version="${version:-None}"
      latest="Latest: \Zb\Z4 $(printf "%-10s" "$version")\Zn"
      usage="Disk: \Zb\Z4 $(sudo du -sxh "$(readlink -f "$SRV/$component")" \
        2>/dev/null | awk '{printf "%-5s", $1}')\Zn"
      options+=("$component" "$usage  $latest")
    done

    options+=(" " "") # A dummy separator
    options+=("Apply" "\Z1Delete all selected components")
    options+=("Purge" "Temporary files/incomplete downloads")
    options+=("Quit" "Exit without changes")

    menu "Select component or an option" \
      --menu "\Zb\Z4Disk Usage\Zn → $disk_usage" 21 65 10 "${options[@]}" || :

    [ -z "$ANSWER" ] && return

    case "$ANSWER" in
      " ") ;;
      Apply) apply_selections ;;
      Purge) purge_components ;;
      Quit) quit_program ;;
      *) sub_menu "$ANSWER" ;;
    esac
    ANSWER=""
  done
}

cleanup
[[ "$0" = "${BASH_SOURCE[0]}" ]] && main_menu
