#compdef apk

function _apk {

	local -a global_opts=(
		"(-h --help)"{-h,--help}"[Print help information]"
		"(-i --interactive --no-interactive)"{-i,--interactive}"[Ask confirmation before performing certain operations]"
		"(-i --interactive --no-interactive)"--no-interactive"[Don't ask for confirmation before performing certain operations]"
		"(-p --root)"{-p,--root}"[Manage file system at ROOT]:directory:_files -/"
		"(-q --quiet)"{-q,--quiet}"[Print less information]"
		"(-U --update-cache --cache-max-age)"{-U,--update-cache}"[Alias for '--cache-max-age 0']"
		\*{-v,--verbose}"[Print more information (can be specified twice)]"
		"(-V --version)"{-V,--version}"[Print program version and exit]"
		"(-X --repository)"{-X,--repository}"[Specify additional package repository]:repository:_host"
		"--allow-untrusted[Install packages with untrusted signature or no signature]"
		"--arch[Temporarily override architecture]:arch:(aarch64 armhf armv7 loongarch64 mips64 ppc64le riscv64 s390x x86 x86_64)"
		# FIXME relative to ROOT
		"--cache-dir[Temporarily override the cache directory]:directory:_files -/"
		"(-U --update-cache --cache-max-age)--cache-max-age[Maximum age for index in cache before it's refreshed]:minutes"
		"(--cache-packages --no-cache-packages)"--cache-packages"[Store a copy of packages at installation time to cache]"
		"(--cache-packages --no-cache-packages)"--no-cache-packages"[Don't store a copy of packages at installation time to cache]"
		"(--cache-predownload --no-cache-predownload)"--cache-predownload"[Download needed packages to cache before starting to commit a transtaction]"
		"(--cache-predownload --no-cache-predownload)"--no-cache-predownload"[Don't download packages to cache before starting to commit a transtaction]"
		"--force-binary-stdout[Continue even if binary data will be printed to the terminal]"
		"--force-broken-world[DANGEROUS: Delete world constraints until a solution without conflicts is found]"
		"--force-missing-repositories[Continue even if some of the repository indexes are not available]"
		"--force-no-chroot[Disable chroot for scripts (can damage the host system)]"
		"--force-non-repository[Continue even if packages may be lost on reboot]"
		"--force-old-apk[Continue even if packages use unsupported features]"
		"--force-overwrite[Overwrite files in other packages]"
		"--force-refresh[Do not use cached files]"
		# FIXME relative to ROOT
		"--keys-dir[Override directory of trusted keys]:directory:_files -/"
		"(--legacy-info --no-legacy-info)"--legacy-info"[Use legacy format for \"info\" applet]"
		"(--legacy-info --no-legacy-info)"--no-legacy-info"[Use new query format for \"info\" applet]"
		"--no-cache[Do not use any local cache path]"
		"--no-check-certificate[Do not validate the HTTPS server certificates]"
		"--no-logfile[Disable writing to the log file]"
		"--no-network[Do not use the network]"
		"--preserve-env[Pass user environment down to scripts]"
		"--print-arch[Print default arch and exit]"
		"(--progress --no-progress)"--progress"[Enable progress bar even for pipes]"
		"(--progress --no-progress)"--no-progress"[Disable progress bar even for TTYs]"
		"--progress-fd[Write progress to the specified file descriptor]:file-descriptors"
		"--purge[Delete modified configuration files or uninstalled packages from cache]"
		"--repositories-file[Override system repositories]:repository-file:_files"
		"--repository-config[Specify additional package repository configuration]:repository-config"
		"--timeout[Timeout network connections if no progress is made in TIME seconds]:seconds"
		"--wait[Wait to get an exclusive repository lock before failing]:seconds"
	)

	local -a commit_opts=(
		"(-s --simulate)"{-s,--simulate}"[Simulate the requested operation without making any changes]"
		"--clean-protected[Do not create .apk-new files in configuration directories]"
		"--overlay-from-stdin[Read list of overlay files from stdin]"
		"--no-commit-hooks[Skip pre/post hook scripts]"
		"--no-scripts[Do not execute any scripts]"
		"--initramfs-diskless-boot[Enables selected force options, disables commit hooks and more]"
	)

	local -a generation_opts=(
		# TODO all levels
		"(-c --compression)"{-c,--compression}"[Set compression algorithm and level]:apk-compression:(none deflate deflate zstd)"
		"--sign-key[Set private key file for signing]:file:_files"
	)

	local -a query_opts=(
		"--all-matches[Select all matched packages]"
		"--available[Filter selection to available packages]"
		# TODO completion
		"--fields[A comma separated list of fields to include in the output]:fields"
		"--format[Specify output format]:format:(default yaml json)"
		"--from[Where to search packages]:from:(system repositories installed none)"
		"--installed[Filter selection to installed packages]"
		"--match[A comma separated list of fields to match the query against]:fields"
		"--recursive[Run solver algorithm with given arguments to select packages]"
		"--upgradable[Filter selection to upgradable packages]"
		"--world[Include world dependencies in constraints]"
		"--orphaned[Filter selection to orphaned packages]"
	)

	local -a index_opts=(
		"(-d --description)"{-d,--description}"[Add a description to the index]"
		"(-o --output)"{-o,--output}"[Output generated index to file]:output:_files"
		"(-x --index)"{-x,--index}"[Read an existing index to speed up the creation of the new index]"
	)

	local -a latest_opt=("(-l --latest)"{-l,--latest}"[Always choose the latest package by version]")
	local -a upgrade_opt=("(-u --upgrade)"{-u,--upgrade}"[Upgrade packages and their dependencies]")

	local context state state_descr line
	typeset -A opt_args
	local curcontext="$curcontext"
	local ret=1

	# TODO respect --root
	function _ccache_apk_world { [[ "$1" -ot /etc/apk/world ]] }
	function _ccache_apk_avail {
		for i in /var/cache/apk/APKINDEX.*; do
			[[ "$1" -ot "$i" ]] && return
		done
	}

	function _apk_available_pkgs {
		local -a _apk_available_packs
		zstyle ":completion:${curcontext}:" cache-policy _ccache_apk_avail
		local IFS=$'\n'
		if _cache_invalid apk_index_packages_available || ! _retrieve_cache apk_index_packages_available; then
			_apk_available_packs=(${${$(apk list -a 2>/dev/null)%% *}%-*-r[[:digit:]]*})
			_store_cache apk_index_packages_available _apk_available_packs
		fi
		_describe 'available packages' _apk_available_packs
	}

	function _apk_installed_pkgs {
		local -a _apk_installed_packs
		zstyle ":completion:${curcontext}:" cache-policy _ccache_apk_world
		local IFS=$'\n'
		if _cache_invalid apk_index_packages_installed || ! _retrieve_cache apk_index_packages_installed; then
			_apk_installed_packs=(${${$(apk list -I 2>/dev/null)%% *}%-*-r[[:digit:]]*})
			_store_cache apk_index_packages_installed _apk_installed_packs
		fi
		_describe 'installed packages' _apk_installed_packs
	}

	function _apk_packages {
		_alternative 'repo:available packages:_apk_available_pkgs' 'localpkgs:local packages:_files -g "*.apk"'
	}

	function _apk_cache {
		local -a cache_subcmds=(
			"clean:Remove package files which are no longer necessary"
			"download:Fetch package files from the repositories and store them in the cache"
			"sync:Clean and Download"
		)
		_describe 'subcommand' cache_subcmds
	}

	function _apk_subcmds {
		local -a cmds=(
			"add:Add packages to world and commit changes"
			"del:Remove constraints from world and commit changes"
			"fix:Fix, reinstall or upgrade packages without modifying world"
			"update:Update repository indexes"
			"upgrade:Install upgrades available from repositories"
			"cache:Manage the local package cache"
			"query:Query information about packages by various criteria"
			"list:List packages matching a pattern or other criteria"
			"dot:Render dependencies as graphviz graphs"
			"policy:Show repository policy for packages"
			"search:Search for packages by name or description"
			"info:Give detailed information about packages or repositories"
			"mkndx:Create repository index (v3) file from packages"
			"mkpkg:Create package (v3)"
			"index:Create repository index (v2) file from packages"
			"fetch:Download packages from global repositories to a local directory"
			"manifest:Show checksums of package contents"
			"verify:Verify package integrity and signature"
			"adbsign:Sign, resign or recompress v3 packages and indexes"
			"audit:Audit system for changes"
			"stats:Show statistics about repositories and installations"
			"version:Compare package versions or perform tests on version strings"
			"adbdump:Dump v3 files in textual representation"
			"adbgen:Generate v3 files from text representation"
			"convdb:Convert v2 installed database to v3 format"
			"convndx:Convert v2 indexes to v3 format"
		)
		_describe 'subcommand' cmds
	}

	local -a completion_spec=($global_opts ':subcommand:_apk_subcmds')

	case ${${words:#-*}[2]} in
	(add)
		completion_spec+=(
			$commit_opts \
			$latest_opt \
			$upgrade_opt \
			"--initdb[Initialize a new package database]" \
			"(-t --virtual)"{-t,--virtual}"[Create virtual package with given dependencies]" \
			"--usermode[Create usermode database with --initdb]" \
			"*:package:_apk_packages"
		)
	;;
	(del)
		# TODO when -r isn't given we should only list constrains in /etc/apk/world
		completion_spec+=(
			$commit_opts \
			"(-r --rdepends)"{-r,--rdepends}"[Recursively delete all top-level reverse dependencies]" \
			"*:installed package:_apk_installed_pkgs"
		)
	;;
	(fix)
		completion_spec+=(
			$commit_opts \
			"(-d --depends)"{-d,--depends}"[Fix dependencies of specified packages]" \
			"(-r --reinstall)"{-r,--reinstall}"[Reinstall packages]" \
			"(-u --upgrade)"{-u,--upgrade}"[Upgrade if an upgrade is available and does not break dependencies]" \
			"(-x --xattr)"{-x,--xattr}"[Fix packages with broken xattrs]" \
			"--directory-permissions[Reset all directory permissions]" \
			"*:package:_apk_packages"
		)
	;;
	(update) completion_spec+=($commit_opts);;
	(upgrade)
		completion_spec+=(
			$commit_opts \
			$latest_opt \
			"(-a --available)"{-a,--available}"[Reset all packages to versions available from current repositories]" \
			"--ignore[Upgrade all other packages than the ones listed]" \
			"--no-self-upgrade[Do not do an early upgrade of the 'apk-tools' package]" \
			"--prune[Remove packages which are no longer available from any configured repository]" \
			"--self-upgrade-only[Only perform a self-upgrade of the 'apk-tools' package]" \
			"*:package:_apk_packages"
		)
	;;
	(cache)
		completion_spec+=(
			$latest_opt \
			$upgrade_opt \
			"--add-dependencies[Add the argument dependencies to world dependencies]" \
			"(-a --available)"{-a,--available}"[Only select packages from active repositories]" \
			"--ignore-conflict:Ignore conflicts when resolving dependencies" \
			"(-s --simulate)"{-s,--simulate}"[Simulate the requested operation without making any changes]" \
			'2:subcommand:_apk_cache'
		)
	;;
	(query) completion_spec+=($query_opts);;
	(list)
		completion_spec+=(
			$query_opts \
			"(-a --available)"{-a,--available}"[Consider only available packages]" \
			"(-d --depends)"{-d,--depends}"[List packages by dependency]" \
			"(-I --installed)"{-I,--installed}"[Consider only installed packages]" \
			"--manifest[List installed packages in format '<name> <version>']" \
			"(-o --origin)"{-o,--origin}"[List packages by origin]" \
			"(-O --orphaned)"{-O,--orphaned}"[Consider only orphaned packages]" \
			"(-P --providers)"{-P,--providers}"[List packages by provider]" \
			"(-u --upgradable --upgradeable)"{-u,--upgradable,--upgradeable}"[Consider only upgradable packages]" \
			"*:pattern"
		)
	;;
	(dot)
		completion_spec+=(
			$query_opts \
			"--errors[Consider only packages with errors]" \
			"--installed[Consider only installed packages]"
		)
	;;
	(policy) completion_spec+=($query_opts "*:package:_apk_packages");;
	(search)
		completion_spec+=(
			$query_opts \
			"(-a --all)"{-a,--all}"[Print all matching package versions]" \
			"(-d --description)"{-d,--description}"[Search in description as well]" \
			"(-e -x --exact)"{-e,-x,--exact}"[Match package names exactly]" \
			"--has-origin[Match by package origin]" \
			"(-o --origin)"{-o,--origin}"[Print base package name]" \
			"(-r --rdepends)"{-r,--rdepends}"[Print reverse dependencies]" \
			"*:package:_apk_packages"
		)
	;;
	(info)
		completion_spec+=(
			$query_opts \
			"(-a --all)"{-a,--all}"[List all information known about the package]" \
			"(-d --description)"{-d,--description}"[Print the package description]" \
			"(-e --exists)"{-e,--exists}"[Check package installed status]" \
			"(-L --contents)"{-L,--contents}"[List files included in the package]" \
			"(-P --provides)"{-P,--provides}"[List what the package provides]" \
			"(-r --rdepends)"{-r,--rdepends}"[List reverse dependencies of the package]" \
			"(-R --depends)"{-R,--depends}"[List the dependencies of the package]" \
			"(-s --size)"{-s,--size}"[Print the package's installed size]" \
			"(-w --webpage)"{-w,--webpage}"[Print the URL for the package's upstream webpage]" \
			"(-W --who-owns)"{-W,--who-owns}"[Print the package which owns the specified file]:file:_files" \
			"(-i --install-if)"{-i,--install-if}"[List the package's install_if rule]" \
			"--license[Print the package SPDX license identifier]" \
			"--replaces[List the other packages for which this package is marked as a replacement]" \
			"(-I --rinstall-if)"{-I,--rinstall-if}"[List other packages whose install_if rules refer to this package]" \
			"(-t --triggers)"{-t,--triggers}"[Print active triggers for the package]" \
			"*:package:_apk_packages"
		)
	;;
	(mkndx)
		completion_spec+=(
			$generation_opts \
			$index_opts \
			"--filter-spec[Filter previous index only]:pkgname-spec" \
			"--hash[Use HASH as the algorithm for apk v3 integrity]:(sha256 sha256-160)" \
			"--pkgname-spec[Specify how the download url should be constructed]:pkgname-spec"
		)
	;;
	(mkpkg)
		completion_spec+=(
			$generation_opts \
			"(-F --files)"{-F,--files}"[Include files from]:path:_files -/" \
			"(-I --info)"{-I,--info}"[Specify metadata for the package]:info" \
			"(-o --output)"{-o,--output}"[Set output file name]:file:_files" \
			"(--rootnode --no-rootnode)"--rootnode"[Generate rootnode entry]" \
			"(--rootnode --no-rootnode)"--no-rootnode"[Generate rootnode entry]" \
			"(-s --script)"{-s,--script}"[Add a script with a specific type]:" \
			"(-t --trigger)"{-t,--trigger}"[Add a trigger]:file:_files"
		)
	;;
	(index)
		completion_spec+=(
			$index_opts \
			"--merge[Merge packages into the existing INDEX]"
			"--prune-origin[Prune old packages with origin of new packages]"
			"--no-warnings[Disable warnings about missing dependencies]" \
			"--rewrite-arch[Set all package's architecture to arch]:arch:(aarch64 armhf armv7 loongarch64 mips64 ppc64le riscv64 s390x x86 x86_64)" \
			"*:package:_apk_packages"
		)
	;;
	(fetch)
		completion_spec+=(
			$query_opts \
			"--built-after[Only fetch packages build after TIMESPEC]:timespec" \
			"(-l --link)"{-l,--link}"[Create hard links if possible]" \
			"(-o --output)"{-o,--output}"[Where to write the downloaded files]:directory:_dir_list" \
			"--pkgname-spec[Generate downloaded package names with PKGNAME_SPEC specification]:pkgname-spec" \
			"(-R --recursive)"{-R,--recursive}"[Fetch packages and all of their dependencies]" \
			"(-s --stdout)"{-s,--stdout}"[Dump the .apk file(s) to stdout]" \
			"--simulate[Simulate the requested operation without making any changes]" \
			"(-w --world)"{-w,--world}"[Download packages needed to satisfy world]" \
			"--url[Print the full URL for downloaded packages]" \
			"*:package:_apk_packages"
		)
	;;
	(manifest) completion_spec+=("*:package:_apk_packages");;
	(verify) completion_spec+=("*:package:_apk_packages");;
	(adbsign)
		completion_spec+=(
			$generation_opts \
			"--reset-signatures[Remove all existing signatures]"
		)
	;;
	(audit)
		completion_spec+=(
			"--backup[Audit configuration files only (default)]" \
			"--check-permissions[Check file permissions too]" \
			"--details[Enable reporting of detail records]" \
			"--full[Audit all system files]" \
			"--ignore-busybox-symlinks[Ignore symlinks whose target is the busybox binary]" \
			"--packages[Print only the packages with changed files]" \
			"--protected-paths[Use given FILE for protected paths listings]:file:_files" \
			"--system[Audit all system files]" \
			"(-r --recursive)"{-r,--recursive}"[Descent into directories and audit them as well]" \
			"*:files:_files"
		)
	;;
	(version)
		completion_spec+=(
			"(-a --all)"{-a,--all}"[Consider packages from all repository tags]" \
			"(-c --check)"{-c,--check}"[Check versions for validity]:*: " \
			"(-I --indexes)"{-I,--indexes}"[Print the version and description for each repository's index]:*: " \
			"(-l --limit)"{-l,--limit}"[Limit to packages with output matching given operand]:operand:('>' '=' '<' '>=' '<=')" \
			"(-t --test)"{-t,--test}"[Compare two version strings]" \
			"*:package:_apk_packages"
		)
	;;
	(adbdump)
		completion_spec+=(
			"--format[Specify the output format]:format:(json yaml)"
		)
	;;
	(adbgen) ;;
	(convdb) completion_spec+=($generation_opts) ;;
	(convndx) completion_spec+=($generation_opts) ;;
	esac

	_arguments -C -s $completion_spec && ret=0
	return ret
}
