#!/usr/bin/env bash

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
DEPS_FILE="${DEPS_FILE:-$SCRIPT_DIR/../deps.toml}"
LOCK_FILE="${LOCK_FILE:-$SCRIPT_DIR/../deps.lock}"
LOCAL_BIN="${LOCAL_BIN:-$HOME/.local/bin}"
MODE=install
ONLY=","
LOCK_STRICT="${LOCK_STRICT:-1}"

info() {
	printf "==> %s\n" "$1"
}

warn() {
	printf "warning: %s\n" "$1" >&2
}

die() {
	printf "error: %s\n" "$1" >&2
	exit 1
}

as_root() {
	if [ "$(id -u)" -eq 0 ]; then
		"$@"
	else
		sudo "$@"
	fi
}

usage() {
	cat <<EOF
Usage: scripts/install-deps [install|check|list|plan|update-lock] [--only name,name]

Commands:
  install  Install or upgrade dependencies from their configured official source
  check    Print installed versions for configured dependencies
  list     Print dependency manifest
  plan     Show planned actions for configured dependencies
  update-lock
           Refresh the dependency lock file for the current platform
EOF
}

parse_args() {
	while [ "$#" -gt 0 ]; do
		case "$1" in
		install | check | list | plan | update-lock)
			MODE="$1"
			;;
		--only)
			shift
			ONLY=",$1,"
			;;
		-h | --help)
			usage
			exit 0
			;;
		*)
			die "unknown argument: $1"
			;;
		esac
		shift
	done
}

manifest_commit() {
	git rev-parse HEAD 2>/dev/null || printf "unknown"
}

platform() {
	case "$(uname -s)" in
	Darwin)
		printf "mac"
		;;
	Linux)
		printf "linux"
		;;
	*)
		die "unsupported platform: $(uname -s). This script supports macOS and Linux."
		;;
	esac
}

arch() {
	case "$(uname -m)" in
	arm64 | aarch64)
		printf "arm64"
		;;
	x86_64 | amd64)
		printf "x86_64"
		;;
	*)
		die "unsupported architecture: $(uname -m)"
		;;
	esac
}

selected() {
	local name=$1

	[ "$ONLY" = "," ] || [[ "$ONLY" == *",$name,"* ]]
}

selected_state() {
	local name=$1
	selected "$name" && printf "selected" || printf "skipped"
}

normalize_text() {
	printf '%s' "$1" | tr '\n' ' ' | sed 's/[[:space:]]\+$//'
}

checksum_file() {
	local path=$1

	if command -v sha256sum >/dev/null 2>&1; then
		sha256sum "$path" | awk '{print $1}'
		return 0
	fi

	if command -v shasum >/dev/null 2>&1; then
		shasum -a 256 "$path" | awk '{print $1}'
		return 0
	fi

	die "sha256 checksum tool not found"
}

installed_version() {
	local name=$1 command=$2 installer=$3
	local version

	case "$installer" in
	official_cask)
		version="$(brew list --cask --versions "$name" 2>/dev/null || true)"
		if [ -n "$version" ]; then
			normalize_text "$version"
			return 0
		fi
		;;
	brew)
		version="$(brew list --versions "$name" 2>/dev/null || true)"
		if [ -n "$version" ]; then
			normalize_text "$version"
			return 0
		fi
		;;
	esac

	if command -v "$command" >/dev/null 2>&1; then
		version="$(version_output "$command" 2>&1 || true)"
		normalize_text "$version"
	else
		printf ""
	fi
}

lock_version_for() {
	local name=$1 platform_name=$2 arch_name=$3

	[ -f "$LOCK_FILE" ] || return 0

	python3 - "$LOCK_FILE" "$name" "$platform_name" "$arch_name" <<'PY'
import pathlib
import sys

try:
    import tomllib
except ModuleNotFoundError:  # pragma: no cover - python < 3.11 fallback
    import tomli as tomllib  # type: ignore

lock_path = pathlib.Path(sys.argv[1])
name = sys.argv[2]
platform_name = sys.argv[3]
arch_name = sys.argv[4]

with lock_path.open("rb") as fh:
    data = tomllib.load(fh)

deps = data.get("deps", {})
dep = deps.get(name, {})
platform_entry = dep.get(platform_name, {})

if isinstance(platform_entry, dict):
    nested_entry = platform_entry.get(arch_name, {})
    if isinstance(nested_entry, dict):
        version = nested_entry.get("version", "")
        if version:
            print(version)
            raise SystemExit(0)

    version = platform_entry.get("version", "")
    if version and platform_entry.get("arch", "") == arch_name:
        print(version)
        raise SystemExit(0)

if dep:
    print("__MISSING__")
PY
}

lock_checksum_for() {
	local name=$1 platform_name=$2 arch_name=$3

	[ -f "$LOCK_FILE" ] || return 0

	python3 - "$LOCK_FILE" "$name" "$platform_name" "$arch_name" <<'PY'
import pathlib
import sys

try:
    import tomllib
except ModuleNotFoundError:  # pragma: no cover - python < 3.11 fallback
    import tomli as tomllib  # type: ignore

lock_path = pathlib.Path(sys.argv[1])
name = sys.argv[2]
platform_name = sys.argv[3]
arch_name = sys.argv[4]

with lock_path.open("rb") as fh:
    data = tomllib.load(fh)

deps = data.get("deps", {})
dep = deps.get(name, {})
platform_entry = dep.get(platform_name, {})

if isinstance(platform_entry, dict):
    nested_entry = platform_entry.get(arch_name, {})
    if isinstance(nested_entry, dict):
        checksum = nested_entry.get("checksum", "")
        if checksum:
            print(checksum)
            raise SystemExit(0)

    if platform_entry.get("arch", "") == arch_name:
        checksum = platform_entry.get("checksum", "")
        if checksum:
            print(checksum)
            raise SystemExit(0)

if dep:
    print("__MISSING__")
PY
}

lock_source_for() {
	local name=$1 platform_name=$2 arch_name=$3

	[ -f "$LOCK_FILE" ] || return 0

	python3 - "$LOCK_FILE" "$name" "$platform_name" "$arch_name" <<'PY'
import pathlib
import sys

try:
    import tomllib
except ModuleNotFoundError:  # pragma: no cover - python < 3.11 fallback
    import tomli as tomllib  # type: ignore

lock_path = pathlib.Path(sys.argv[1])
name = sys.argv[2]
platform_name = sys.argv[3]
arch_name = sys.argv[4]

with lock_path.open("rb") as fh:
    data = tomllib.load(fh)

deps = data.get("deps", {})
dep = deps.get(name, {})
platform_entry = dep.get(platform_name, {})

if isinstance(platform_entry, dict):
    nested_entry = platform_entry.get(arch_name, {})
    if isinstance(nested_entry, dict):
        source_url = nested_entry.get("source_url", "")
        if source_url:
            print(source_url)
            raise SystemExit(0)

    source_url = platform_entry.get("source_url", "")
    if source_url and platform_entry.get("arch", "") == arch_name:
        print(source_url)
        raise SystemExit(0)

if dep:
    print("__MISSING__")
PY
}

lock_source_required() {
	local name=$1
	local installer=$2
	local source_url

	if [ "$installer" = "system" ]; then
		printf ""
		return 0
	fi

	case "$installer" in
	official_tarball | official_release)
		;;
	*)
		printf ""
		return 0
		;;
	esac

	if [ "$LOCK_STRICT" != "1" ]; then
		printf ""
		return 0
	fi

	source_url="$(lock_source_for "$name" "$(platform)" "$(arch)")"
	if [ -z "$source_url" ]; then
		die "$name is missing source_url from deps.lock for $(platform)/$(arch)"
	fi
	if [ "$source_url" = "__MISSING__" ]; then
		die "$name lock source missing for $(platform)/$(arch)"
	fi

	printf "%s" "$source_url"
}

lock_version_required() {
	local name=$1
	local installer=$2
	local version

	if [ "$installer" = "system" ] || [ "$LOCK_STRICT" != "1" ]; then
		printf ""
		return 0
	fi

	version="$(lock_version_for "$name" "$(platform)" "$(arch)")"
	if [ -z "$version" ]; then
		die "$name is missing from deps.lock for $(platform)/$(arch)"
	fi
	if [ "$version" = "__MISSING__" ]; then
		die "$name lock entry missing for $(platform)/$(arch)"
	fi

	printf "%s" "$version"
}

lock_checksum_required() {
	local name=$1
	local installer=$2
	local checksum

	if [ "$installer" = "system" ]; then
		printf ""
		return 0
	fi

	case "$installer" in
	official_tarball | official_release)
		;;
	*)
		printf ""
		return 0
		;;
	esac

	if [ "$LOCK_STRICT" != "1" ]; then
		printf ""
		return 0
	fi

	checksum="$(lock_checksum_for "$name" "$(platform)" "$(arch)")"
	if [ -z "$checksum" ]; then
		die "$name is missing checksum from deps.lock for $(platform)/$(arch)"
	fi
	if [ "$checksum" = "__MISSING__" ]; then
		die "$name lock checksum missing for $(platform)/$(arch)"
	fi

	printf "%s" "$checksum"
}

manifest_rows() {
	local mode=$1
	local platform_name=${2:-}

	python3 - "$DEPS_FILE" "$mode" "$platform_name" <<'PY'
import sys
import tomllib

path, mode, platform_name = sys.argv[1:4]

with open(path, "rb") as fh:
    data = tomllib.load(fh)

deps = data.get("deps", {})

for name, dep in deps.items():
    command = dep["command"]
    target = dep["target"]
    mac = dep.get("mac", {})
    linux = dep.get("linux", {})

    if mode == "all":
        print(
            name,
            command,
            target,
            mac.get("installer", ""),
            mac.get("source", ""),
            linux.get("installer", ""),
            linux.get("source", ""),
            sep="\t",
        )
    elif mode == "current":
        current = mac if platform_name == "mac" else linux
        print(
            name,
            command,
            target,
            current.get("installer", ""),
            current.get("source", ""),
            sep="\t",
        )
    else:
        raise SystemExit(f"unknown manifest row mode: {mode}")
PY
}

ensure_local_bin() {
	mkdir -p "$LOCAL_BIN"
	export PATH="$LOCAL_BIN:$PATH"
}

ensure_linux_bootstrap_tools() {
	command -v curl >/dev/null 2>&1 && command -v tar >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1 && return 0

	if command -v apt-get >/dev/null 2>&1; then
		export DEBIAN_FRONTEND=noninteractive
		export TZ="${TZ:-Etc/UTC}"
		as_root apt-get update
		as_root apt-get install -y --no-install-recommends ca-certificates curl tar gzip unzip
	else
		die "missing curl/tar/unzip and no bootstrap package manager is configured"
	fi
}

github_latest_tag() {
	local repo=$1

	curl -fsSL "https://api.github.com/repos/$repo/releases/latest" |
		sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p' |
		head -1
}

install_archive_binary() {
	local url=$1 binary=$2 strip_components=$3 expected_checksum=${4:-}
	local tmp
	local archive actual_checksum

	tmp="$(mktemp -d)"
	case "$url" in
	*.zip)
		archive="$tmp/archive.zip"
		curl -fsSL "$url" -o "$archive"
		unzip -q "$tmp/archive.zip" -d "$tmp/out"
		;;
	*.tar.gz | *.tgz)
		archive="$tmp/archive.tar.gz"
		curl -fsSL "$url" -o "$archive"
		mkdir -p "$tmp/out"
		tar -xzf "$tmp/archive.tar.gz" -C "$tmp/out" --strip-components="$strip_components"
		;;
	*)
		rm -rf "$tmp"
		die "unsupported archive URL: $url"
		;;
	esac

	if [ -n "$expected_checksum" ]; then
		actual_checksum="$(checksum_file "$archive")"
		if [ "$actual_checksum" != "$expected_checksum" ]; then
			rm -rf "$tmp"
			die "$binary archive checksum mismatch: expected=$expected_checksum actual=$actual_checksum"
		fi
	fi

	local found
	found="$(find "$tmp/out" -type f -name "$binary" -perm -111 | head -1)"
	[ -n "$found" ] || found="$(find "$tmp/out" -type f -name "$binary" | head -1)"
	[ -n "$found" ] || {
		rm -rf "$tmp"
		die "binary $binary not found in $url"
	}

	install -m 0755 "$found" "$LOCAL_BIN/$binary"
	rm -rf "$tmp"
}

version_output() {
	local command=$1

	case "$command" in
	fish)
		fish --version
		;;
	git)
		git --version
		;;
	lazygit)
		lazygit --version
		;;
	make)
		make --version | head -1
		;;
	nvim)
		nvim --version | head -1
		;;
	tmux)
		tmux -V
		;;
	ghostty)
		ghostty --version | head -1
		;;
	yazi)
		brew list --versions yazi 2>/dev/null || yazi --version
		;;
	*)
		"$command" --version
		;;
	esac
}

check_installed() {
	local name=$1 command=$2 target=$3 installer=${4:-}
	local actual

	actual="$(installed_version "$name" "$command" "$installer")"
	if [ -z "$actual" ]; then
		warn "$name is not installed: missing command $command"
		return 1
	fi

	info "$name target=$target installed=$(normalize_text "$actual")"
}

plan_installed() {
	local name=$1 command=$2 target=$3 installer=${4:-}
	local actual

	actual="$(installed_version "$name" "$command" "$installer")"
	if [ -n "$actual" ]; then
		printf "%s" "$actual"
	else
		printf "missing"
	fi
}

plan_status() {
	local name=$1 installer=$2 platform=$3

	case "$name:$installer:$platform" in
	fish:official_repo:linux | ghostty:community_ubuntu:linux)
		printf "implemented"
		;;
	fish:official_repo:mac)
		printf "system"
		;;
	*:apt:* | *:brew:* | *:official_cask:* | *:system:*)
		printf "system"
		;;
	zoxide:official_script:linux | *:official_tarball:* | *:official_script:* | *:official_release:*)
		printf "implemented"
		;;
	*:official_repo:* | *:community_ubuntu:* | *:cargo:* | *:source:*)
		printf "pending"
		;;
	*)
		printf "pending"
		;;
	esac
}

plan_install_path() {
	local name=$1 installer=$2 platform=$3

	case "$name:$installer:$platform" in
	fish:official_repo:linux)
		printf "system"
		;;
	*:apt:* | *:brew:* | *:official_cask:* | *:system:*)
		printf "system"
		;;
	*:official_tarball:linux | *:official_script:linux | *:official_release:linux | *:official_repo:linux | *:community_ubuntu:linux | *:cargo:linux | *:source:linux)
		if [ "$platform" = "linux" ]; then
			printf '%s' "$HOME/.local/bin"
		else
			printf "system"
		fi
		;;
	*)
		printf "system"
		;;
	esac
}

plan_action() {
	local name=$1 command=$2 target=$3

	if ! selected "$name"; then
		printf "skip"
		return 0
	fi

	if command -v "$command" >/dev/null 2>&1; then
		printf "upgrade"
	else
		printf "install"
	fi
}

install_mac() {
	local name=$1 installer=$2

	case "$installer" in
	system)
		command -v "$name" >/dev/null 2>&1 || die "$name is required on macOS but is not installed"
		;;
	brew)
		command -v brew >/dev/null 2>&1 || die "Homebrew is required to install $name"
		brew update
		if brew list "$name" >/dev/null 2>&1; then
			brew upgrade "$name" || true
		else
			brew install "$name"
		fi
		;;
	official_cask)
		command -v brew >/dev/null 2>&1 || die "Homebrew is required to install cask $name"
		brew update
		brew install --cask "$name" || brew upgrade --cask "$name" --greedy-latest
		;;
	official_script | official_release | official_tarball)
		die "$name uses $installer on macOS, but that installer is not implemented yet"
		;;
	*)
		die "unsupported macOS installer for $name: $installer"
		;;
	esac
}

ensure_apt_repository_support() {
	command -v add-apt-repository >/dev/null 2>&1 && return 0

	export DEBIAN_FRONTEND=noninteractive
	export TZ="${TZ:-Etc/UTC}"
	as_root apt-get update
	as_root apt-get install -y --no-install-recommends software-properties-common gnupg lsb-release
}

install_fish_linux() {
	ensure_apt_repository_support

	if [ -r /etc/os-release ]; then
		# shellcheck disable=SC1091
		. /etc/os-release
	fi

	case "${ID:-}" in
	ubuntu)
		;;
	*)
		die "fish official repository install is implemented for Ubuntu only; use the distro package or a different installer on ${ID:-unknown}"
		;;
	esac

	export DEBIAN_FRONTEND=noninteractive
	export TZ="${TZ:-Etc/UTC}"
	as_root add-apt-repository -y ppa:fish-shell/release-3
	as_root apt-get update
	as_root apt-get install -y --no-install-recommends fish
}

install_ghostty_linux() {
	ensure_local_bin
	ensure_linux_bootstrap_tools

	local tmp
	tmp="$(mktemp -d)"
	(
		cd "$tmp"
		curl -fsSL https://raw.githubusercontent.com/mkasberg/ghostty-ubuntu/HEAD/install.sh | bash
	)
	rm -rf "$tmp"
}

install_zoxide_linux() {
	ensure_local_bin
	ensure_linux_bootstrap_tools

	local tmp
	tmp="$(mktemp -d)"
	(
		cd "$tmp"
		curl -fsSL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh -s -- --bin-dir "$LOCAL_BIN"
	)
	rm -rf "$tmp"
}

install_linux() {
	local name=$1 installer=$2 expected_checksum=${3:-} locked_source=${4:-}

	ensure_local_bin
	ensure_linux_bootstrap_tools

	case "$installer" in
	apt)
		command -v apt-get >/dev/null 2>&1 || die "apt-get is required to install $name"
		export DEBIAN_FRONTEND=noninteractive
		export TZ="${TZ:-Etc/UTC}"
		as_root apt-get update
		as_root apt-get install -y --no-install-recommends "$name"
		;;
	official_repo)
		case "$name" in
		fish)
			install_fish_linux
			;;
		*)
			die "$name uses $installer on Linux, but that installer is not implemented yet"
			;;
		esac
		;;
	official_tarball)
		case "$name" in
		nvim)
			local asset_arch
			local url
			if [ "$(arch)" = "arm64" ]; then
				asset_arch=arm64
			else
				asset_arch=x86_64
			fi
			url="${locked_source:-https://github.com/neovim/neovim/releases/latest/download/nvim-linux-$asset_arch.tar.gz}"
			install_archive_binary \
				"$url" \
				nvim \
				1 \
				"$expected_checksum"
			;;
		*)
			die "$name has no official_tarball installer implementation"
			;;
		esac
		;;
	official_script)
		case "$name" in
		starship)
			curl -fsSL https://starship.rs/install.sh | sh -s -- -y -b "$LOCAL_BIN"
			;;
		zoxide)
			install_zoxide_linux
			;;
		*)
			die "$name has no official_script installer implementation"
			;;
		esac
		;;
	official_release)
		local tag version asset_arch url
		case "$name" in
		yazi)
			if [ "$(arch)" = "arm64" ]; then
				asset_arch=aarch64
			else
				asset_arch=x86_64
			fi
			if [ -n "$locked_source" ]; then
				url="$locked_source"
			else
				tag="$(github_latest_tag sxyazi/yazi)"
				[ -n "$tag" ] || die "failed to resolve latest yazi release"
				url="https://github.com/sxyazi/yazi/releases/download/$tag/yazi-$asset_arch-unknown-linux-gnu.zip"
			fi
			install_archive_binary "$url" yazi 0 "$expected_checksum"
			install_archive_binary "$url" ya 0
			;;
		eza)
			if [ "$(arch)" = "arm64" ]; then
				asset_arch=aarch64
			else
				asset_arch=x86_64
			fi
			if [ -n "$locked_source" ]; then
				url="$locked_source"
			else
				tag="$(github_latest_tag eza-community/eza)"
				[ -n "$tag" ] || die "failed to resolve latest eza release"
				url="https://github.com/eza-community/eza/releases/download/$tag/eza_$asset_arch-unknown-linux-gnu.tar.gz"
			fi
			install_archive_binary "$url" eza 0 "$expected_checksum"
			;;
		lazygit)
			if [ "$(arch)" = "arm64" ]; then
				asset_arch=arm64
			else
				asset_arch=x86_64
			fi
			if [ -n "$locked_source" ]; then
				url="$locked_source"
			else
				tag="$(github_latest_tag jesseduffield/lazygit)"
				[ -n "$tag" ] || die "failed to resolve latest lazygit release"
				version="${tag#v}"
				url="https://github.com/jesseduffield/lazygit/releases/download/$tag/lazygit_${version}_Linux_$asset_arch.tar.gz"
			fi
			install_archive_binary "$url" lazygit 0 "$expected_checksum"
			;;
		*)
			die "$name has no official_release installer implementation"
			;;
		esac
		;;
	community_ubuntu)
		case "$name" in
		ghostty)
			install_ghostty_linux
			;;
		*)
			die "$name uses $installer on Linux, but that installer is not implemented yet"
			;;
		esac
		;;
	official_appimage | cargo | source)
		die "$name uses $installer on Linux, but that installer is not implemented yet"
		;;
	*)
		die "unsupported Linux installer for $name: $installer"
		;;
	esac
}

install_one() {
	local name=$1 command=$2 target=$3 installer=$4 source=$5
	local locked current locked_checksum locked_source

	current="$(installed_version "$name" "$command" "$installer")"

	if [ "$installer" = "system" ]; then
		[ -n "$current" ] || die "$name is required on $(platform) but is not installed"
		info "$name target=$target installed=$(normalize_text "$current")"
		return 0
	fi

	locked="$(lock_version_required "$name" "$installer")"
	locked_checksum="$(lock_checksum_required "$name" "$installer")"
	locked_source="$(lock_source_required "$name" "$installer")"

	if [ -n "$locked" ] && [ -n "$current" ] && [ "$current" = "$locked" ]; then
		info "$name target=$target installed=$(normalize_text "$current")"
		return 0
	fi

	if [ "$(platform)" = "mac" ]; then
		install_mac "$name" "$installer"
	else
		install_linux "$name" "$installer" "$locked_checksum" "$locked_source"
	fi

	check_installed "$name" "$command" "$target" "$installer"

	current="$(installed_version "$name" "$command" "$installer")"
	if [ -n "$locked" ] && [ "$current" != "$locked" ]; then
		die "$name install does not match deps.lock: installed=$current lock=$locked"
	fi
}

plan_one() {
	local name=$1 command=$2 target=$3 installer=$4 source=$5
	local os action current status install_path

	os="$(platform)"
	action="$(plan_action "$name" "$command" "$target")"
	current="$(plan_installed "$name" "$command" "$target" "$installer")"
	status="$(plan_status "$name" "$installer" "$os")"
	install_path="$(plan_install_path "$name" "$installer" "$os")"

	printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" \
		"$name" \
		"$command" \
		"$target" \
		"$os" \
		"$installer" \
		"$source" \
		"$install_path" \
		"$status" \
		"$action" \
		"$current"
}

update_lock() {
	command -v python3 >/dev/null 2>&1 || die "python3 is required to update deps.lock"
	python3 "$SCRIPT_DIR/update-lock.py" "$DEPS_FILE" "$LOCK_FILE" --platform "$(platform)" --manifest-commit "$(manifest_commit)"
}

for_each_dep() {
	local callback=$1
	local name command target installer source

	while IFS=$'\t' read -r name command target installer source; do
		[[ -z "$name" ]] && continue
		selected "$name" || continue
		"$callback" "$name" "$command" "$target" "$installer" "$source"
	done < <(manifest_rows current "$(platform)")
}

for_each_dep_all() {
	local callback=$1
	local name command target installer source

	while IFS=$'\t' read -r name command target installer source; do
		[[ -z "$name" ]] && continue
		"$callback" "$name" "$command" "$target" "$installer" "$source"
	done < <(manifest_rows current "$(platform)")
}

for_each_dep_manifest() {
	local callback=$1
	local name command target mac_installer mac_source linux_installer linux_source

	while IFS=$'\t' read -r name command target mac_installer mac_source linux_installer linux_source; do
		[[ -z "$name" ]] && continue
		"$callback" "$name" "$command" "$target" "$mac_installer" "$mac_source" "$linux_installer" "$linux_source"
	done < <(manifest_rows all)
}

list_one() {
	printf "%s\t%s\ttarget:%s\tmac:%s\t%s\tlinux:%s\t%s\n" "$1" "$2" "$3" "$4" "$5" "$6" "$7"
}

check_one() {
	local name=$1 command=$2 target=$3 installer=$4
	local current locked checksum

	check_installed "$name" "$command" "$target" "$installer" || return 1

	if [ "$installer" = "system" ]; then
		return 0
	fi

	locked="$(lock_version_for "$name" "$(platform)" "$(arch)")"
	if [ "$locked" = "__MISSING__" ]; then
		warn "$name lock entry missing for platform $(platform)"
		return 1
	fi

	if [ -n "$locked" ]; then
		current="$(installed_version "$name" "$command" "$installer")"
		if [ "$current" != "$locked" ]; then
			warn "$name lock mismatch: installed=$current lock=$locked"
			return 1
		fi
	fi

	checksum="$(lock_checksum_for "$name" "$(platform)" "$(arch)")"
	if [ "$installer" = "official_tarball" ] || [ "$installer" = "official_release" ]; then
		if [ -z "$checksum" ] || [ "$checksum" = "__MISSING__" ]; then
			warn "$name lock checksum missing for $(platform)/$(arch)"
			return 1
		fi
	fi
}

main() {
	parse_args "$@"

	case "$MODE" in
	install)
		for_each_dep install_one
		;;
	check)
		for_each_dep check_one
		;;
	list)
		for_each_dep_manifest list_one
		;;
	plan)
		printf "name\tcommand\ttarget\tplatform\tinstaller\tsource\tinstall_path\tstatus\taction\tcurrent\n"
		for_each_dep_all plan_one
		;;
	update-lock)
		update_lock
		;;
	esac
}

main "$@"
