#!/usr/bin/env bash
set -euo pipefail

nala_bin="${1:-${CARGO_TARGET_DIR:-target}/debug/nala}"

if [[ ! -x "${nala_bin}" ]]; then
	echo "Missing executable Nala binary: ${nala_bin}" >&2
	echo "Build one first or pass a binary path." >&2
	exit 1
fi

if [[ "$(id -u)" != "0" ]]; then
	echo "Deb tests need root because Nala requires root for install." >&2
	exit 1
fi

work_dir="$(mktemp -d)"
trap 'rm -rf "${work_dir}"' EXIT
chmod a+rx "${work_dir}"

policy_status="${work_dir}/policy.status"
dpkg-query --status dpkg >"${policy_status}"
mkdir "${work_dir}/policy-lists"
policy_options=(
	-o "Dir::State::status=${policy_status}"
	-o "Dir::State::lists=${work_dir}/policy-lists"
	-o "Dir::Etc::sourcelist=/dev/null"
	-o "Dir::Etc::sourceparts=-"
)
for format in text json; do
	format_options=()
	if [[ "${format}" == json ]]; then
		format_options=(--machine)
	fi
	"${nala_bin}" --no-tui --color never "${policy_options[@]}" \
		policy "${format_options[@]}" dpkg >"${work_dir}/policy-${format}-package"
	"${nala_bin}" --no-tui --color never "${policy_options[@]}" \
		policy "${format_options[@]}" >"${work_dir}/policy-${format}-global"
	grep -Fq "${policy_status}" "${work_dir}/policy-${format}-package"
	grep -Fq "${policy_status}" "${work_dir}/policy-${format}-global"
done
python3 - "${work_dir}" "${policy_status}" <<'PY'
import json, pathlib, sys
root, status = pathlib.Path(sys.argv[1]), sys.argv[2]
package = json.loads((root / "policy-json-package").read_text())
assert package[0]["versions"][0]["sources"] == [{"priority": 100, "source": status}]
global_policy = json.loads((root / "policy-json-global").read_text())
assert global_policy["package_files"][0]["source"] == status
assert global_policy["package_files"][0]["downloadable"] is False
PY
echo "PASS: text and JSON policy describe the installed-only status database."

for fixture in tests/deb/packages/broken-*; do
	case_name="$(basename "${fixture}")"
	deb_path="${work_dir}/${case_name}.deb"
	apt_log="${work_dir}/${case_name}.apt.log"
	nala_log="${work_dir}/${case_name}.nala.log"

	dpkg-deb --root-owner-group --build "${fixture}" "${deb_path}" >/dev/null

	if apt-get install -s "${deb_path}" >"${apt_log}" 2>&1; then
		echo "Expected apt-get install -s ${deb_path} to fail" >&2
		cat "${apt_log}" >&2
		exit 1
	fi

	nala_status=0
	"${nala_bin}" --no-tui --color never install --assume-no "${deb_path}" \
		>"${nala_log}" 2>&1 || nala_status=$?

	if [[ "${nala_status}" == "0" ]]; then
		echo "Expected Nala to reject ${case_name}" >&2
		cat "${nala_log}" >&2
		exit 1
	fi

	if grep -q "Nothing to do\\." "${nala_log}"; then
		echo "Nala hid unresolved dependencies as Nothing to do." >&2
		cat "${nala_log}" >&2
		exit 1
	fi

	if ! grep -Fq "missing-a" "${nala_log}" || ! grep -Fq "missing-b" "${nala_log}"; then
		echo "Expected Nala to report both missing dependency alternatives." >&2
		cat "${nala_log}" >&2
		exit 1
	fi

	echo "PASS: apt and nala reject ${case_name}."
done

repo_dir="${work_dir}/repo"
lists_dir="${work_dir}/lists"
archive_dir="${work_dir}/archives"
sources_list="${work_dir}/sources.list"
main_deb="${work_dir}/recommends-or-main.deb"
apt_log="${work_dir}/recommends-or.apt.log"
nala_log="${work_dir}/recommends-or.nala.log"

mkdir -p "${repo_dir}" "${lists_dir}/partial" "${archive_dir}/partial"
dpkg-deb --root-owner-group --build tests/deb/packages/recommends-or-main \
	"${main_deb}" >/dev/null
for package in recommends-or-bad recommends-or-good; do
	dpkg-deb --root-owner-group --build "tests/deb/packages/${package}" \
		"${repo_dir}/${package}_1.0_all.deb" >/dev/null
done
(
	cd "${repo_dir}"
	dpkg-scanpackages . /dev/null >Packages
) 2>/dev/null
printf 'deb [trusted=yes] file:%s ./\n' "${repo_dir}" >"${sources_list}"

apt_options=(
	-o "Dir::Etc::sourcelist=${sources_list}"
	-o "Dir::Etc::sourceparts=-"
	-o "Dir::State::lists=${lists_dir}"
	-o "Dir::Cache::Archives=${archive_dir}/"
)
if ! apt-get "${apt_options[@]}" update >"${work_dir}/apt-update.log" 2>&1; then
	cat "${work_dir}/apt-update.log" >&2
	exit 1
fi
apt-get "${apt_options[@]}" install -s "${main_deb}" >"${apt_log}" 2>&1

grep -Fq "recommends-or-good" "${apt_log}"
if grep -Fq "recommends-or-bad" "${apt_log}"; then
	echo "APT selected the broken recommendation alternative." >&2
	cat "${apt_log}" >&2
	exit 1
fi

nala_status=0
"${nala_bin}" --no-tui --color never "${apt_options[@]}" \
	install --assume-no "${main_deb}" >"${nala_log}" 2>&1 || nala_status=$?

if [[ "${nala_status}" == "0" ]]; then
	echo "Expected Nala --assume-no to refuse the planned transaction." >&2
	cat "${nala_log}" >&2
	exit 1
fi
grep -Fq "recommends-or-good" "${nala_log}"
if grep -Fq "recommends-or-bad" "${nala_log}"; then
	echo "Nala selected the broken recommendation alternative." >&2
	cat "${nala_log}" >&2
	exit 1
fi

echo "PASS: apt and nala select the valid recommendation alternative."
