#!/bin/sh

readonly XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
readonly EXCLUDE_CONF="$XDG_CONFIG_HOME/pkg-cutter"
readonly tcols=$(stty size | cut -d" " -f2)
readonly tlines=$(stty size | cut -d" " -f1)

[ $tcols -lt 80 ] && dwidth=$((tcols-4)) || dwidth=76

exclude_opt=0	# exclude packages list generation mode
new_leafs_yes=0	# automatically seek new leafs after pkg removal
rm_count=0	# removed packages counter
sel_status="off" # default packages selection state (on|off)

display_usage() {
	<< EOF >&2 cat
Usage: ${0##*/} -h
       ${0##*/} [-oy]
       ${0##*/} -x

    -h - show this help
    -o - set selection to on by default
    -x - update exclude list
    -y - assume yes when there are new leaf packages

EOF
	exit 1
}

mktmp() {
	local tmp=$(mktemp -t "${0##*/}")

	if [ ! "$tmp" ]; then
		echo "===> Failed to create temporary file" >&2
		exit 1
	fi
	echo "$tmp"
}

number_humanize() {
	echo "$1" | awk '{
		bytes = $0;
		gb=2^30; mb=2^20; kb=2^10;

		if (bytes > gb) {
			size = bytes/gb;
			unit = "GB";
		} else if (bytes > mb) {
			size = bytes/mb;
			unit = "MB";
		} else if (bytes > kb) {
			size = bytes/kb;
			unit = "kB";
		} else {
			size = bytes;
			unit = "B ";
		}
		if (unit == "GB" || unit == "MB")
			printf "%.1f %s", size, unit;
		else
			printf "%.0f %s", size, unit;
	}' | tr ',' '.'
}

update_exclude_list() {
	local count=0 excluded items pkg status

	for pkg in $(pkg-static query '%n@%v'); do
		status="off"
		case $pkg_exclude in *${pkg%@*}*) status="on" ;; esac
		items="$items ${pkg%@*} ${pkg#*@} $status"
		count=$((count+1))
	done

	tmpfile=$(mktmp)
	echo "--checklist \"Select packages to exclude ($count items):\" \
		$((tlines-3)) $dwidth $((tlines-5)) $items" > "$tmpfile"
	excluded=$(dialog --stdout --file "$tmpfile" | sed 's|\"||g')
	dialog --clear
	rm "$tmpfile"

	[ "$excluded" ] || exit 0
	[ -d "$XDG_CONFIG_HOME" ] || mkdir "$XDG_CONFIG_HOME"
	[ -f "$EXCLUDE_CONF" ] && rm -f "$EXCLUDE_CONF"

	for pkg in $excluded; do
		echo "$pkg" >> "$EXCLUDE_CONF"
	done
	exit 0
}

while getopts "hoxy" option; do
	case $option in
	o)
		[ $exclude_opt -eq 1 ] && display_usage
		sel_status="on" ;;
	x)
		[ "$sel_status" = "on" -o $new_leafs_yes -eq 1 ] && display_usage
		exclude_opt=1 ;;
	y)
		new_leafs_yes=1 ;;
	*)
		display_usage
	esac
done

if [ $(id -u) -ne 0 ]; then
	if ! which sudo >/dev/null; then
		echo "===> sudo not found" >&2
		echo "===> This script requires root privileges or properly configured sudo." >&2
		exit 1
	fi
	SUDO="sudo"
fi

[ -f "$EXCLUDE_CONF" ] && pkg_exclude=$(grep -v '^#' "$EXCLUDE_CONF")
[ $exclude_opt -eq 1 ] && update_exclude_list

echo "===> Checking for leaf packages..."
while true; do
	pkg_leafs=$(pkg-static query -e '%#r = 0' %n-%v@%sb)
	count=0
	items=""

	for pkg in $pkg_leafs; do
		case $pkg_seen in *${pkg%@*}*) continue;; esac
		case $pkg_exclude in *${pkg%-*}*) continue;; esac
		[ ${pkg%-*} != "pkg" ] || continue

		size=$(number_humanize ${pkg#*@})
		pkg_seen="${pkg_seen} ${pkg%@*}"
		items="$items ${pkg%@*} \"$(printf '%8s' "$size")\" $sel_status"
		count=$((count+1))
	done

	if [ $rm_count -gt 0 -a $count -gt 0 ]; then
		if [ $new_leafs_yes -eq 0 ]; then
			dialog --yesno "There are new leaf packages. Continue?" 5 43
			[ $? -eq 1 ] && break
		fi
	fi

	[ $count -eq 0 ] && break

	[ "$tmpfile" ] || tmpfile=$(mktmp)
	echo "--checklist \"Select packages to delete ($count items):\" \
		$((tlines-3)) $dwidth $((tlines-5)) $items" > "$tmpfile"

	ret=$(dialog --stdout --file "$tmpfile" | sed 's|\"||g')
	[ "$ret" ] || break

	for bytes in $(pkg-static query '%sb' $ret); do
		rm_freed=$((rm_freed+bytes));
		rm_count=$((rm_count+1));
	done

	dialog --clear
	$SUDO pkg-static delete -y $ret
done

if [ "$tmpfile" ]; then
	rm "$tmpfile"
	dialog --clear
fi

[ "$pkg_seen" ] || echo "===> No leaf packages to remove"

[ $rm_count -gt 0 ] &&
	echo "===> Packages removed: $rm_count  Disk space freed: $(number_humanize $rm_freed)"
