#!/bin/bash
set -e -u

show_help() {
	local cache_size
	cache_size=$(du -sh @TERMUX_CACHE_DIR@/apt/archives 2>/dev/null | cut -f1)

	echo 'Usage: pkg command [arguments]'
	echo
	echo 'A tool for managing packages. Commands:'
	echo
	echo '  autoclean            - Remove all outdated packages from .deb package'
	echo '                         cache.'
	echo
	echo '  clean                - Remove all packages from .deb package cache.'
	[ -n "$cache_size" ] && echo "                         Using ${cache_size} now."
	echo
	echo '  files <packages>     - Show all files installed by packages.'
	echo
	echo '  install <packages>   - Install specified packages.'
	echo
	echo '  list-all             - List all packages available in repositories.'
	echo
	echo '  list-installed       - List installed packages.'
	echo
	echo '  reinstall <packages> - Reinstall specified installed packages at the'
	echo '                         latest version.'
	echo
	echo '  search <query>       - Search package by query, for example by name or'
	echo '                         description part.'
	echo
	echo '  show <packages>      - Show basic metadata, such as dependencies.'
	echo
	echo '  uninstall <packages> - Uninstall specified packages. Configuration files'
	echo '                         will be left intact.'
	echo
	echo '  upgrade              - Upgrade all installed packages to the latest'
	echo '                         version.'
	echo
	exit 1
}

select_mirror() {
	local main_repo="https://termux.org/packages"

	declare -A mirrors
	mirrors[50]="https://dl.bintray.com/termux/termux-packages-24"
	mirrors[23]="https://termux.mentality.rip/termux-packages-24"
	mirrors[15]="https://main.termux-mirror.ml"
	mirrors[12]="https://grimler.se/termux-packages-24"

	local current_mirror
	current_mirror=$(grep -P "^\s*deb\s+" @TERMUX_PREFIX@/etc/apt/sources.list | grep -oP 'https?://[a-z0-9/._-]+')

	# Do not update mirror if:
	# * Uses .cn domain - specific to Chinese users.
	# * If $TERMUX_PKG_NO_MIRROR_SELECT was set.
	if [ -n "${TERMUX_PKG_NO_MIRROR_SELECT-}" ] || grep -qP '.+\.cn/' <(echo "${current_mirror-x}"); then
		return
	fi

	# Mirrors are rotated if 6 hours timeout has been passed or mirror is no longer accessible.
	if [ -n "$(find @TERMUX_CACHE_DIR@/apt/pkgcache.bin -mmin -360 2>/dev/null)" ]; then
		if [ -n "${current_mirror}" ]; then
			echo -n "Checking availability of current mirror: "
			if timeout 6 curl --connect-timeout 5 --user-agent 'Termux-PKG/1.0 mirror-checker' --head --fail --location "${current_mirror%/}/dists/stable/Release" >/dev/null 2>&1; then
				echo "ok"
				return
			else
				echo "bad"
			fi
		fi
	fi

	# Test mirror availability, remove unaccessible mirrors from list.
	echo "Testing the available mirrors:"
	local w total_mirror_weight=0
	for w in "${!mirrors[@]}"; do
		echo -n "[*] ${mirrors[$w]}: "
		if timeout 6 curl --connect-timeout 5 --user-agent 'Termux-PKG/1.0 mirror-checker' --head --fail --location "${mirrors[$w]%/}/dists/stable/Release" >/dev/null 2>&1; then
			echo "ok"
			total_mirror_weight=$((total_mirror_weight + w))
		else
			echo "bad"
			unset "mirrors[$w]"
		fi
	done
	unset w

	# Weight-based mirror selection.
	local selected_mirror=""
	if ((total_mirror_weight > 0)); then
		local w random_weight calc_weight=0
		random_weight=$((RANDOM % total_mirror_weight + 1))
		for w in $(echo "${!mirrors[@]}" | tr ' ' '\n' | sort -n); do
			calc_weight=$((calc_weight + w))

			if ((calc_weight >= random_weight)); then
				echo "Picking mirror: ${mirrors[$w]}"
				selected_mirror="${mirrors[$w]}"
				break
			fi
		done
	fi

	if [ -n "${selected_mirror}" ]; then
		echo "deb ${selected_mirror}/ stable main" > @TERMUX_PREFIX@/etc/apt/sources.list
	else
		echo "Using fallback mirror: ${main_repo}"
		echo "deb ${main_repo}/ stable main" > @TERMUX_PREFIX@/etc/apt/sources.list
	fi
}

update_apt_cache() {
	if [ -z "$(find @TERMUX_CACHE_DIR@/apt/pkgcache.bin -mmin -20 2>/dev/null)" ]; then
		apt update
	fi
}

if [ $# = 0 ]; then
	show_help
fi

CMD="$1"
shift 1

case "$CMD" in
	f*) dpkg -L "$@";;
	h*) show_help;;
	add|i*)
		select_mirror
		update_apt_cache
		apt install "$@"
		;;
	autoc*) apt autoclean;;
	cl*) apt clean;;
	list-a*) apt list "$@";;
	list-i*) apt list --installed "$@";;
	rei*) apt install --reinstall "$@";;
	se*)
		select_mirror
		update_apt_cache
		apt search "$@"
		;;
	sh*) apt show "$@";;
	un*|rem*|rm|del*) apt remove "$@";;
	up*)
		select_mirror
		apt update
		apt full-upgrade "$@"
		;;
	*) echo "Unknown command: '$CMD' (run 'pkg help' for usage information)"; exit 1;;
esac
