#!/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

#
## Minis: Check for disk size; set up stage; delete old snapshots
#
DISK_SIZE_GB=$(df --output=size -B1G "$BTRFS" | tail -n1)
IS_LOW_STORAGE=false
[[ "$DISK_SIZE_GB" -lt 32 ]] && IS_LOW_STORAGE=true
IS_MINI_SYSTEM=false
is-mini "$BTRFS" && IS_MINI_SYSTEM=true

if $IS_MINI_SYSTEM; then
  ARCH="/srv/desktop-mini"
  SNAP_EXT="mini.d"
else
  ARCH="${ARCH:-"/srv/desktop"}"
  SNAP_EXT="d"
fi

say "Syncing desktop & snapshot versions"
{
  if [ "$ARCH" = "/srv/desktop" ] || [ "$ARCH" = "/srv/desktop-mini" ]; then
    "$ROOT/bin/tl-comp-sync" "$(basename "$ARCH")"
  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" "$(basename "$ARCH")")"}"
# 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

# Early exit if all snapshots already exist
if [ -d "$SNAP/v$MAJOR.$SNAP_EXT/@root" ] && [ -d "$SNAP/v$MAJOR.$SNAP_EXT/@guest" ] \
  && [ -d "$SNAP/v$MINOR.$SNAP_EXT/@root" ] && [ -d "$SNAP/v$MINOR.$SNAP_EXT/@guest" ] \
  && [ -d "$SNAP/v$PATCH.$SNAP_EXT/@root" ] && [ -d "$SNAP/v$PATCH.$SNAP_EXT/@guest" ]; then
  say "$(g "Version $PATCH is already installed.") Nothing to unpack."
  exit 0
fi

TMP="tmp-$(uuidgen | head -c4)" # Temp prefix

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")

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

    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"}"
run mkdir -p "$STAGE"

if $IS_LOW_STORAGE; then
  # Check USB staging space if it's on a USB mount
  if [[ "$STAGE" == *"/srv/"* ]]; then # Simplified check for USB-based staging
    SRV_AVAIL_GB=$(df --output=avail -B1G "$STAGE" | tail -n 1)
    if [[ "$SRV_AVAIL_GB" -lt 14 ]]; then
      err "Insufficient space on USB staging area ($SRV_AVAIL_GB GB < 14 GB). Aborting."
      exit 1
    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

  run sudo rm -rf "$STAGE/"* || :
  run mkdir -p "$STAGE"

  # Only delete old snapshots if they are on the target system
  if [[ "$SNAP" == "$BTRFS"* ]]; then
    delete_old_snapshots
  fi
  # Only delete old desktop files if they are on the target system
  if [[ "$ARCH" == "$BTRFS"* ]]; then
    delete_old_desktop
  fi

  [ "$IS_MINI_SYSTEM" = true ] && TMP="mini"
fi

for ver in "$MAJOR" "$MINOR" "$PATCH"; do
  if [ -d "$SNAP/v$ver.$SNAP_EXT/@root" ] && [ -d "$SNAP/v$ver.$SNAP_EXT/@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 (desktop-mini), we want to keep the unpacked snapshots;
    # reduce I/O from unpacking again later.
    # For standard devices, delete the btrfs send file to save space.
    if ! $IS_MINI_SYSTEM; then
      run sudo rm "$STAGE/$TMP.$ver.d/$subvol.btrfs"
    fi
  done

  run mv "$SNAP/$TMP.$ver.d" "$SNAP/v$ver.$SNAP_EXT"
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."
