#!/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"}" # Path to system BTRFS root

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

  DESCRIPTION:
    $(g "${BASH_SOURCE##*/}") unpacks desktop a archive into
    the TechLit system hosted in BTRFS volume at $(c btrfs-path)
                                        (default: $(c /var/btrfs))

    The lastest local version will be used by default

  NOTE:
    If no desktop archives are available, use $(g tl-comp-pull) to download one
"
  exit 1
fi

# Exit now if run as root user
assert-is-user

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

ARCH="${ARCH:-"/srv/desktop"}" # Archives directory

say "Syncing desktop & snapshot versions"
{
  if [ "$ARCH" = "/srv/desktop" ]; then
    "$ROOT/bin/tl-comp-sync" desktop
  fi
  COMP_DIR="$BTRFS"/@srv "$ROOT/bin/tl-comp-sync" snapshots
}

# The patch version -- x.x.x
COMP_DIR_FOR_LATEST="$(dirname "$ARCH")"
PATCH="${2:-"$(COMP_DIR="$COMP_DIR_FOR_LATEST" "$ROOT/bin/tl-comp-latest" desktop)"}"
# The minor version -- x.x.0
MINOR="$(echo "$PATCH" | cut -d. -f-2).0"
# The major version -- x.0.0
MAJOR="$(echo "$PATCH" | cut -d. -f-1).0.0"
SNAP="$BTRFS/@srv/snapshots"    # Snapshots directory
TMP="tmp-$(uuidgen | head -c4)" # Temp prefix

#
## Minis: Check for disk size; set up stage; delete old snapshotss
#
DELETE_ARCHIVE_AFTER_UNPACK=false
DISK_SIZE_GB=$(df -B1G "$BTRFS" | tail -n1 | awk '{print $2}')

delete_old_snapshots() {
  say "Deleting old snapshots to save space."
  find "$SNAP" -mindepth 1 -maxdepth 1 -type d | while read -r dir; do
    local keep=false
    dir=$(basename "$dir")

    for ver in "$MAJOR" "$MINOR" "$PATCH"; do
      if [[ "$dir" == v"$ver.d" ]] && [ -d "$SNAP/$dir/@root" ] && [ -d "$SNAP/$dir/@guest" ]; then
        keep=true
        break
      fi
    done

    if ! $keep; then
      sudo btrfs subvolume delete "$SNAP/$dir"/@root/home/guest || true
      sudo btrfs subvolume delete "$SNAP/$dir"/@{root,guest} || true
      if [ -d "$SNAP/$dir" ]; then
        run sudo rm -rf "$SNAP/$dir"
      fi
    fi
  done
}

delete_old_desktop() {
  say "Deleting old desktop components to save space."
  find "$ARCH" -name "v*.tar.gz" | while read -r file; do
    local keep=false
    for ver in "$MAJOR" "$MINOR" "$PATCH"; do
      if [[ "$(basename "$file")" == "v$ver.tar.gz" ]]; then
        keep=true
        break
      fi
    done

    if ! $keep; then
      run sudo rm -f "$file" "${file%.tar.gz}.sha256" "${file%.tar.gz}.changelog"
    fi
  done
}

if [[ "$DISK_SIZE_GB" -lt 32 ]]; then
  DEFAULT_STAGE=/srv/stage
else
  DEFAULT_STAGE="$BTRFS/@srv/snapshots"
fi

STAGE="${STAGE:-"$DEFAULT_STAGE"}"

if [[ "$DISK_SIZE_GB" -lt 32 ]]; then
  if [ "$STAGE" = "/srv/stage" ]; then
    SRV_AVAIL_B=$(df --output=avail -B1 "$STAGE" | tail -n 1 | xargs)
    if [[ "$SRV_AVAIL_B" -lt 17179869184 ]]; then # 16GiB
      if [ -d /srv/stage ]; then
        say "/srv/stage exists but there is insufficient space on $BTRFS to use it as staging."
        read -p "Delete /srv/stage to free up space? (y/N) " -n 1 -r
        echo
        if [[ $REPLY =~ ^[Yy]$ ]]; then
          run sudo rm -rf /srv/stage
        fi
      fi
    fi
  fi

  # Determine if this is a major update
  CURRENT_PATCH="$(COMP_DIR="$BTRFS/@srv" "$ROOT/bin/tl-comp-latest" snapshots || echo '0.0.0')"
  CURRENT_MAJOR_V="$(echo "$CURRENT_PATCH" | cut -d. -f1)"
  TARGET_MAJOR_V="$(echo "$PATCH" | cut -d. -f1)"

  # For major updates on low-storage devices (<32GB), we must perform a
  # destructive update by deleting current subvolumes to make space.
  # For minor/patch updates, we attempt a 'live' update by only deleting backups.
  if [ "$CURRENT_MAJOR_V" != "$TARGET_MAJOR_V" ]; then
    say "Major update detected. Deleting all current system subvolumes to make space."
    run sudo btrfs subvolume delete "$BTRFS"/@root{,.prev}/home/guest "$BTRFS"/@{root,guest}{,.prev} || :
    run sudo rm -rf "$BTRFS"/@root "$BTRFS"/@guest || :
  else
    say "Minor/patch update detected. Attempting live update by deleting only backup subvolumes."
    run sudo btrfs subvolume delete "$BTRFS"/@{root,guest}.prev || :
  fi

  if [ ! -d "$STAGE" ] || [ ! -w "$STAGE" ]; then
    run sudo rm -rf "$STAGE" || :
    run mkdir -p "$STAGE"
  fi

  delete_old_snapshots
  delete_old_desktop

  [[ "$DISK_SIZE_GB" -lt 20 ]] && TMP="mini"
fi

for ver in "$MAJOR" "$MINOR" "$PATCH"; do
  if [ -d "$SNAP/v$ver.d/@root" ] && [ -d "$SNAP/v$ver.d/@guest" ]; then
    continue
  fi

  if ! [ -f "$ARCH/v$ver.tar.gz" ]; then
    err ""
    err "Snapshot v$c$ver$r must be installed, but"
    err "  desktop archive v$c$ver$r is not available locally."
    err ""
    err "Download it with ${g}tl-comp-pull$r to continue."
    err ""
    exit 1
  fi

  run sudo mkdir -p "$SNAP/$TMP.$ver.d"
  if ! [ -f "$STAGE/$TMP.$ver.d/@root.btrfs" ] || ! [ -f "$STAGE/$TMP.$ver.d/@guest.btrfs" ]; then
    say "Verifying checksums"
    if ! (cd "$ARCH" && sha256sum -c "v$ver.sha256"); then
      err ""
      err "Desktop ${c}v$ver$r is corrupt or incmoplete!"
      err "  Could not verify ${c}$ver.sha256$r validity."
      err ""
      err "Download it with ${g}tl-comp-pull$r to try again."
      err ""
      exit 1
    fi

    run sudo mkdir -p "$STAGE/$TMP.$ver.d"
    run sudo tar -C "$STAGE/$TMP.$ver.d" -xzf "$ARCH/v$ver.tar.gz"
  fi

  for subvol in @root @guest; do
    run sudo btrfs receive -f "$STAGE/$TMP.$ver.d/$subvol.btrfs" "$SNAP/$TMP.$ver.d"
    # For devices with less than 20GB, we want to keep the unpacked snapshots; reduce I/O from unpacking again later
    if [[ "$DISK_SIZE_GB" -ge 20 ]]; then
      run sudo rm "$STAGE/$TMP.$ver.d/$subvol.btrfs"
    fi
  done

  run mv "$SNAP/$TMP.$ver.d" "$SNAP/v$ver.d"
done

#if [ -n "$STAGE" ]; then
#  say "Balacing BTRFS"
#  run sudo btrfs balance --full-balance "$BTRFS"
#fi

say "Syncing snapshot versions"
COMP_DIR="$BTRFS/@srv" "$ROOT/bin/tl-comp-sync" snapshots

say "Done."
