#!/bin/sh
set -eu

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

download() {
    curl --fail --silent --show-error --location \
        --proto '=https' --proto-redir '=https' --tlsv1.2 \
        --connect-timeout 10 --max-time 180 --retry 2 \
        --output "$2" "$1"
}

main() {
    for required_command in curl uname mktemp awk sed install mv mkdir rm; do
        command -v "$required_command" >/dev/null 2>&1 || fail "$required_command is required."
    done

    case "$(uname -s)" in
        Darwin) operating_system=darwin ;;
        Linux) operating_system=linux ;;
        *) fail 'This installer supports macOS and Linux. Windows downloads: https://assetcenter.app/api#downloads' ;;
    esac
    case "$(uname -m)" in
        x86_64|amd64) architecture=amd64 ;;
        arm64|aarch64) architecture=arm64 ;;
        *) fail 'Supported processors are x64 and ARM64.' ;;
    esac
    binary="assetcenter-$operating_system-$architecture"

    if command -v sha256sum >/dev/null 2>&1; then
        checksum_command=sha256sum
    elif command -v shasum >/dev/null 2>&1; then
        checksum_command=shasum
    elif command -v openssl >/dev/null 2>&1; then
        checksum_command=openssl
    else
        fail 'Install sha256sum, shasum, or openssl to verify the download.'
    fi

    install_directory="${ASSETCENTER_INSTALL_DIR:-${HOME:?HOME must be set}/.local/bin}"
    case "$install_directory" in
        /*) ;;
        *) fail 'ASSETCENTER_INSTALL_DIR must be an absolute path.' ;;
    esac
    destination="$install_directory/assetcenter"
    if [ -d "$destination" ] || [ -L "$destination" ]; then
        fail "$destination is a directory or symlink. Choose another install directory."
    fi

    work_directory=$(mktemp -d "${TMPDIR:-/tmp}/assetcenter-install.XXXXXX") || fail 'Could not create a temporary directory.'
    staged_binary=''
    trap 'rm -rf "$work_directory"; if [ -n "$staged_binary" ]; then rm -f "$staged_binary"; fi' 0
    trap 'exit 1' HUP INT TERM

    download 'https://assetcenter.app/cli/releases/latest.json' "$work_directory/latest.json" || fail 'Could not find the latest CLI release.'
    version=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\(v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)".*/\1/p' "$work_directory/latest.json")
    case "$version" in
        ''|*[!v0-9.]*) fail 'The release manifest has an invalid version.' ;;
    esac
    printf '%s\n' "$version" | awk '/^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/ { valid = 1 } END { exit !valid }' || fail 'The release manifest has an invalid version.'

    printf 'Downloading AssetCenter %s for %s/%s...\n' "$version" "$operating_system" "$architecture"
    release_url="https://assetcenter.app/cli/releases/$version"
    download "$release_url/checksums.txt" "$work_directory/checksums.txt" || fail 'Could not download release checksums.'
    download "$release_url/$binary" "$work_directory/$binary" || fail 'Could not download the CLI binary.'

    expected_checksum=$(awk -v filename="$binary" '
        $2 == filename {
            matches++
            if (NF != 2 || length($1) != 64 || $1 ~ /[^a-f0-9]/) { invalid = 1 }
            checksum = $1
        }
        END {
            if (matches != 1 || invalid) { exit 1 }
            print checksum
        }
    ' "$work_directory/checksums.txt") || fail 'The checksum list is missing a valid, unique entry for this binary.'

    case "$checksum_command" in
        sha256sum) checksum_output=$(sha256sum "$work_directory/$binary") || fail 'SHA-256 verification failed.' ;;
        shasum) checksum_output=$(shasum -a 256 "$work_directory/$binary") || fail 'SHA-256 verification failed.' ;;
        openssl) checksum_output=$(openssl dgst -sha256 "$work_directory/$binary") || fail 'SHA-256 verification failed.' ;;
    esac
    if [ "$checksum_command" = openssl ]; then
        actual_checksum=$(printf '%s\n' "$checksum_output" | awk '{ print $NF }')
    else
        actual_checksum=$(printf '%s\n' "$checksum_output" | awk '{ print $1 }')
    fi
    [ "$actual_checksum" = "$expected_checksum" ] || fail 'Checksum mismatch. Your existing installation has not been changed.'

    mkdir -p "$install_directory" || fail "Could not create $install_directory. Choose a writable ASSETCENTER_INSTALL_DIR."
    staged_binary=$(mktemp "$install_directory/.assetcenter.XXXXXX") || fail 'Could not stage the installation. Choose a writable ASSETCENTER_INSTALL_DIR.'
    install -m 755 "$work_directory/$binary" "$staged_binary" || fail 'Could not install the verified binary.'
    mv -f "$staged_binary" "$destination" || fail 'Could not replace the installed CLI.'
    staged_binary=''

    printf '\nInstalled AssetCenter %s at %s\n' "$version" "$destination"
    case ":${PATH:-}:" in
        *":$install_directory:"*) ;;
        *)
            quoted_directory=$(printf '%s' "$install_directory" | sed "s/'/'\\\\''/g")
            printf '\nAdd it to your PATH:\n'
            case "${SHELL:-}" in
                */fish) printf "  fish_add_path '%s'\n" "$quoted_directory" ;;
                *) printf "  export PATH='%s':\"\$PATH\"\n" "$quoted_directory"
                   printf 'Add that line to your shell profile for new terminals.\n' ;;
            esac
            ;;
    esac
    printf '\nConnect your organization:\n  assetcenter auth login\n'
}

main "$@"
