#!/bin/sh
(
set -eu

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

require_command() {
    command -v "$1" >/dev/null 2>&1 || die "required command not found: $1"
}

path_owner() {
    case "$ssf_os" in
        Darwin) stat -f '%u' "$1" ;;
        Linux) stat -c '%u' "$1" ;;
        *) return 1 ;;
    esac
}

require_owned_directory() {
    ssf_path=$1
    [ ! -L "$ssf_path" ] || die "refusing symlinked directory: $ssf_path"
    [ -d "$ssf_path" ] || die "not a directory: $ssf_path"
    [ "$(path_owner "$ssf_path")" = "$ssf_uid" ] || die "directory is not owned by the current user: $ssf_path"
}

verify_sha256() {
    ssf_file=$1
    ssf_expected=$2
    if command -v sha256sum >/dev/null 2>&1; then
        ssf_actual=$(sha256sum "$ssf_file" | awk '{print $1}')
    elif command -v shasum >/dev/null 2>&1; then
        ssf_actual=$(shasum -a 256 "$ssf_file" | awk '{print $1}')
    else
        die "sha256sum or shasum is required"
    fi
    [ "$ssf_actual" = "$ssf_expected" ] || die "archive SHA-256 mismatch"
}

cleanup() {
    if [ -n "${ssf_staged:-}" ] && [ -e "$ssf_staged" ]; then
        rm -f "$ssf_staged"
    fi
    if [ -n "${ssf_tmp:-}" ] && [ -d "$ssf_tmp" ]; then
        rm -rf "$ssf_tmp"
    fi
}

main() {
    umask 022
    ssf_version=0.1.0
    ssf_base_url="https://github.com/solidsf-inc/ssf/releases/download/v$ssf_version"
    ssf_os=$(uname -s)
    ssf_arch=$(uname -m)
    ssf_uid=$(id -u)
    ssf_staged=
    ssf_tmp=

    case "$ssf_os/$ssf_arch" in
        Darwin/arm64)
            ssf_asset=ssf-macos-arm64.tar.gz
            ssf_sha256=30f8e9465a58e5073f6deb5915cfa08f98dbb9a8ad5613a915337ef98df6a925
            ssf_bytes=2296377
            ;;
        Linux/x86_64)
            ssf_asset=ssf-linux-x86_64.tar.gz
            ssf_sha256=3daa4bf8ede1f4ac3ef53771e6afc1ac0fbf5063e8423ec097353d86c43d6504
            ssf_bytes=2706851
            ;;
        Linux/aarch64|Linux/arm64)
            ssf_asset=ssf-linux-arm64.tar.gz
            ssf_sha256=a11834420e14922a81e477bb9aaef724a93b43f04bf75144bb84e31b3f5aa557
            ssf_bytes=2342721
            ;;
        *)
            die "unsupported target: $ssf_os/$ssf_arch"
            ;;
    esac

    [ -n "${HOME:-}" ] || die "HOME is not set"
    case "$HOME" in
        /*) ;;
        *) die "HOME must be an absolute path" ;;
    esac

    for ssf_command in curl tar mktemp stat id wc awk sort cp chmod mv rm mkdir tr uname; do
        require_command "$ssf_command"
    done

    ssf_tmp_root=${TMPDIR:-/tmp}
    case "$ssf_tmp_root" in
        /*) ;;
        *) die "temporary directory must be an absolute path" ;;
    esac
    [ -d "$ssf_tmp_root" ] || die "temporary directory does not exist: $ssf_tmp_root"
    ssf_tmp=$(mktemp -d "$ssf_tmp_root/ssf-install.XXXXXX") || die "could not create temporary directory"
    trap cleanup 0
    trap 'exit 1' HUP INT TERM
    ssf_archive="$ssf_tmp/$ssf_asset"
    ssf_extract="$ssf_tmp/extract"
    mkdir "$ssf_extract"

    curl -fsSL \
        --proto '=https' \
        --proto-redir '=https' \
        --tlsv1.2 \
        --connect-timeout 15 \
        --max-time 300 \
        --max-filesize "$ssf_bytes" \
        --retry 2 \
        --retry-delay 1 \
        "$ssf_base_url/$ssf_asset" \
        -o "$ssf_archive"

    [ "$(wc -c < "$ssf_archive" | tr -d '[:space:]')" = "$ssf_bytes" ] || die "archive size mismatch"
    verify_sha256 "$ssf_archive" "$ssf_sha256"

    ssf_members=$(tar -tzf "$ssf_archive" | LC_ALL=C sort)
    ssf_expected_members=$(printf '%s\n' LICENSE THIRD_PARTY_LICENSES.txt ssf | LC_ALL=C sort)
    [ "$ssf_members" = "$ssf_expected_members" ] || die "archive member set mismatch"
    tar -tvzf "$ssf_archive" | awk 'substr($1, 1, 1) != "-" { exit 1 } END { if (NR != 3) exit 1 }' \
        || die "archive contains a non-regular entry"

    tar -xzf "$ssf_archive" -C "$ssf_extract"
    for ssf_member in ssf LICENSE THIRD_PARTY_LICENSES.txt; do
        [ -s "$ssf_extract/$ssf_member" ] || die "missing or empty extracted file: $ssf_member"
        [ ! -L "$ssf_extract/$ssf_member" ] || die "refusing extracted symlink: $ssf_member"
    done
    chmod 755 "$ssf_extract/ssf"
    [ "$("$ssf_extract/ssf" --version)" = "ssf $ssf_version" ] || die "staged binary version mismatch"

    ssf_local="$HOME/.local"
    ssf_bin="$ssf_local/bin"
    ssf_target="$ssf_bin/ssf"
    [ ! -L "$ssf_local" ] || die "refusing symlinked directory: $ssf_local"
    if [ -e "$ssf_local" ]; then
        require_owned_directory "$ssf_local"
    else
        mkdir "$ssf_local"
        require_owned_directory "$ssf_local"
    fi
    [ ! -L "$ssf_bin" ] || die "refusing symlinked directory: $ssf_bin"
    if [ -e "$ssf_bin" ]; then
        require_owned_directory "$ssf_bin"
    else
        mkdir "$ssf_bin"
        require_owned_directory "$ssf_bin"
    fi
    if [ -L "$ssf_target" ] || [ -d "$ssf_target" ]; then
        die "refusing non-regular install target: $ssf_target"
    fi
    if [ -e "$ssf_target" ]; then
        [ -f "$ssf_target" ] || die "refusing non-regular install target: $ssf_target"
        [ "$(path_owner "$ssf_target")" = "$ssf_uid" ] || die "install target is not owned by the current user: $ssf_target"
    fi

    ssf_staged=$(mktemp "$ssf_bin/.ssf.XXXXXX") || die "could not stage installed binary"
    cp "$ssf_extract/ssf" "$ssf_staged"
    chmod 755 "$ssf_staged"
    [ "$("$ssf_staged" --version)" = "ssf $ssf_version" ] || die "staged install version mismatch"
    mv -f "$ssf_staged" "$ssf_target"
    ssf_staged=
    [ "$("$ssf_target" --version)" = "ssf $ssf_version" ] || die "installed binary version mismatch"

    printf 'Installed ssf %s to %s\n' "$ssf_version" "$ssf_target"
    case ":${PATH:-}:" in
        *":$ssf_bin:"*) ;;
        *) printf 'Add %s to PATH to run ssf directly.\n' "$ssf_bin" ;;
    esac
    cleanup
    trap - 0
}

main "$@"
)
