#!/bin/sh
# shellcheck disable=SC2310,SC2312 # the harness reads command output through substitutions on purpose

set -eu

ROOT=$(CDPATH='' cd -- "$(dirname "$0")/.." && pwd)
INSTALLER=${ROOT}/install.sh
TEST_ROOT=$(mktemp -d 2>/dev/null || mktemp -d -t quinjet-tests)
FIXTURES=${TEST_ROOT}/fixtures
FAKE_BIN=${TEST_ROOT}/bin
DOWNLOAD_LOG=${TEST_ROOT}/downloads.log
ORIGINAL_PATH=${PATH}

cleanup() {
    rm -rf "${TEST_ROOT}"
}
trap cleanup EXIT HUP INT TERM

mkdir -p "${FIXTURES}" "${FAKE_BIN}"
: >"${DOWNLOAD_LOG}"

fail() {
    printf 'FAIL: %s\n' "$*" >&2
    exit 1
}

assert_contains() {
    needle=$1
    file=$2
    grep -F "${needle}" "${file}" >/dev/null 2>&1 || fail "expected '${needle}' in ${file}"
}

assert_equals() {
    expected=$1
    actual=$2
    [ "${expected}" = "${actual}" ] || fail "expected '${expected}', got '${actual}'"
}

sha256() {
    file=$1
    if command -v sha256sum >/dev/null 2>&1; then
        sha256sum "${file}" | awk '{print $1}'
    else
        shasum -a 256 "${file}" | awk '{print $1}'
    fi
}

prepare_release() {
    asset=$1
    contents=$2
    printf '%s' "${contents}" >"${FIXTURES}/${asset}"
    printf '%s  dist/%s\n' "$(sha256 "${FIXTURES}/${asset}")" "${asset}" >"${FIXTURES}/SHA256SUMS"
}

cat >"${FAKE_BIN}/uname" <<'EOF'
#!/bin/sh
case "${1:-}" in
    -s) printf '%s\n' "$QUINJET_TEST_OS" ;;
    -m) printf '%s\n' "$QUINJET_TEST_ARCH" ;;
    *) printf '%s %s\n' "$QUINJET_TEST_OS" "$QUINJET_TEST_ARCH" ;;
esac
EOF

cat >"${FAKE_BIN}/curl" <<'EOF'
#!/bin/sh
output=
url=
while [ "$#" -gt 0 ]; do
    case "$1" in
        -o | --output)
            output=$2
            shift 2
            ;;
        http://* | https://*)
            url=$1
            shift
            ;;
        *)
            shift
            ;;
    esac
done
[ -n "$output" ] && [ -n "$url" ] || exit 2
printf '%s\n' "$url" >>"$QUINJET_TEST_DOWNLOAD_LOG"
cp "$QUINJET_TEST_FIXTURES/${url##*/}" "$output"
EOF
chmod +x "${FAKE_BIN}/uname" "${FAKE_BIN}/curl"

run_installer() {
    test_home=$1
    test_os=$2
    test_arch=$3
    shift 3
    mkdir -p "${test_home}"
    env \
        HOME="${test_home}" \
        PATH="${FAKE_BIN}:${ORIGINAL_PATH}" \
        SHELL=/bin/sh \
        QUINJET_TEST_OS="${test_os}" \
        QUINJET_TEST_ARCH="${test_arch}" \
        QUINJET_TEST_FIXTURES="${FIXTURES}" \
        QUINJET_TEST_DOWNLOAD_LOG="${DOWNLOAD_LOG}" \
        QUINJET_NO_MODIFY_PATH=1 \
        sh "${INSTALLER}" "$@"
}

printf 'test: installs a pinned Linux x86_64 release\n'
case_dir=${TEST_ROOT}/linux-x86
bin_dir=${case_dir}/bin
prepare_release quinjet-linux-x86_64 'linux x86 binary'
run_installer "${case_dir}/home" Linux x86_64 --version 1.2.3 --bin-dir "${bin_dir}" >"${case_dir}.out" 2>&1
assert_equals 'linux x86 binary' "$(cat "${bin_dir}/quinjet")"
[ -x "${bin_dir}/quinjet" ] || fail "installed Unix binary is not executable"
assert_contains 'https://github.com/pulkitxm/quinjet/releases/download/v1.2.3/quinjet-linux-x86_64' "${DOWNLOAD_LOG}"
assert_contains 'verified SHA-256 checksum' "${case_dir}.out"

printf 'test: selects the latest macOS Apple Silicon release\n'
case_dir=${TEST_ROOT}/macos-arm
bin_dir=${case_dir}/bin
prepare_release quinjet-macos-aarch64 'macOS ARM binary'
run_installer "${case_dir}/home" Darwin arm64 --bin-dir "${bin_dir}" >"${case_dir}.out" 2>&1
assert_equals 'macOS ARM binary' "$(cat "${bin_dir}/quinjet")"
assert_contains 'https://github.com/pulkitxm/quinjet/releases/latest/download/quinjet-macos-aarch64' "${DOWNLOAD_LOG}"

printf 'test: selects the Linux ARM64 release\n'
case_dir=${TEST_ROOT}/linux-arm
bin_dir=${case_dir}/bin
prepare_release quinjet-linux-aarch64 'Linux ARM binary'
run_installer "${case_dir}/home" Linux aarch64 --bin-dir "${bin_dir}" >"${case_dir}.out" 2>&1
assert_equals 'Linux ARM binary' "$(cat "${bin_dir}/quinjet")"
assert_contains 'https://github.com/pulkitxm/quinjet/releases/latest/download/quinjet-linux-aarch64' "${DOWNLOAD_LOG}"

printf 'test: rejects a checksum mismatch without replacing an installation\n'
case_dir=${TEST_ROOT}/bad-checksum
bin_dir=${case_dir}/bin
mkdir -p "${bin_dir}"
printf 'existing binary' >"${bin_dir}/quinjet"
printf 'tampered binary' >"${FIXTURES}/quinjet-linux-x86_64"
printf '%064d  quinjet-linux-x86_64\n' 0 >"${FIXTURES}/SHA256SUMS"
if run_installer "${case_dir}/home" Linux x86_64 --bin-dir "${bin_dir}" >"${case_dir}.out" 2>&1; then
    fail "checksum mismatch unexpectedly succeeded"
fi
assert_equals 'existing binary' "$(cat "${bin_dir}/quinjet")"
assert_contains 'checksum verification failed' "${case_dir}.out"

printf 'test: updates a shell profile once for the default bin directory\n'
case_dir=${TEST_ROOT}/path-update
home_dir=${case_dir}/home
prepare_release quinjet-linux-x86_64 'path binary'
mkdir -p "${home_dir}"
for run in 1 2; do
    env \
        HOME="${home_dir}" \
        PATH="${FAKE_BIN}:${ORIGINAL_PATH}" \
        SHELL=/bin/zsh \
        QUINJET_TEST_OS=Linux \
        QUINJET_TEST_ARCH=x86_64 \
        QUINJET_TEST_FIXTURES="${FIXTURES}" \
        QUINJET_TEST_DOWNLOAD_LOG="${DOWNLOAD_LOG}" \
        sh "${INSTALLER}" >"${case_dir}.${run}.out" 2>&1
done
assert_equals '1' "$(grep -c "^export PATH=\"\\\$HOME/.local/bin:\\\$PATH\"\$" "${home_dir}/.zshrc")"
assert_contains 'Added by the Quinjet installer' "${home_dir}/.zshrc"

printf 'test: rejects unsupported systems before downloading\n'
case_dir=${TEST_ROOT}/unsupported
before=$(wc -l <"${DOWNLOAD_LOG}" | tr -d ' ')
if run_installer "${case_dir}/home" FreeBSD x86_64 --bin-dir "${case_dir}/bin" >"${case_dir}.out" 2>&1; then
    fail "unsupported operating system unexpectedly succeeded"
fi
after=$(wc -l <"${DOWNLOAD_LOG}" | tr -d ' ')
assert_equals "${before}" "${after}"
assert_contains 'unsupported operating system: FreeBSD' "${case_dir}.out"

printf 'test: rejects unsafe version values before downloading\n'
case_dir=${TEST_ROOT}/invalid-version
before=$(wc -l <"${DOWNLOAD_LOG}" | tr -d ' ')
if run_installer "${case_dir}/home" Linux x86_64 --version 'v1/../../invalid' --bin-dir "${case_dir}/bin" >"${case_dir}.out" 2>&1; then
    fail "invalid release version unexpectedly succeeded"
fi
after=$(wc -l <"${DOWNLOAD_LOG}" | tr -d ' ')
assert_equals "${before}" "${after}"
assert_contains 'invalid release version' "${case_dir}.out"

printf 'All shell installer tests passed.\n'
