#!/bin/sh
# Generated from distribution/bootstrap.sh; inspect/rebuild from the matching source.
mode=install
# Shared source for the standalone install.sh and run.sh launchers.
# tools/build-release.mjs prepends the shebang and fixes mode for each artifact.
set -eu
umask 077

fail() { printf 'JMPKit: %s\n' "$*" >&2; exit 1; }
note() { printf '%s\n' "$*" >&2; }
version=${JMPKIT_CLI_VERSION:-}
bin_dir=${JMPKIT_BIN_DIR:-${HOME:?HOME is required}/.local/bin}
rollback=no
if [ "$mode" = install ]; then
    while [ "$#" -gt 0 ]; do
        case "$1" in
            --version) [ "$#" -ge 2 ] || fail '--version needs a value'; version=$2; shift 2 ;;
            --bin-dir) [ "$#" -ge 2 ] || fail '--bin-dir needs a directory'; bin_dir=$2; shift 2 ;;
            --rollback) rollback=yes; shift ;;
            --help|-h)
                printf '%s\n' 'Install or update JMPKit for this user.' \
                    'sh install.sh [--version VERSION] [--bin-dir DIR] [--rollback]' \
                    'Default: ~/.local/bin/jmpkit. No sudo or shell-profile edits.'
                exit 0 ;;
            *) fail "Unknown installer option: $1 (try --help)" ;;
        esac
    done
fi

work=
lock=
child=
cleanup() {
    [ -z "$work" ] || rm -rf -- "$work"
    [ -z "$lock" ] || rmdir -- "$lock" 2>/dev/null || :
}
stop() {
    signal=$1
    status=$2
    if [ -n "$child" ]; then
        kill -"$signal" "$child" 2>/dev/null || :
        wait "$child" 2>/dev/null || :
    fi
    exit "$status"
}
trap cleanup 0
trap 'stop HUP 129' HUP
trap 'stop INT 130' INT
trap 'stop TERM 143' TERM

if [ "$mode" = install ]; then
    case "$bin_dir" in /*) ;; *) fail '--bin-dir must be an absolute path' ;; esac
    [ ! -L "$bin_dir" ] || fail 'The install directory must not be a symlink'
    mkdir -p -- "$bin_dir"
    mkdir -- "$bin_dir/.jmpkit-install.lock" 2>/dev/null ||
        fail 'Another installer is running (or an interrupted run left .jmpkit-install.lock)'
    lock=$bin_dir/.jmpkit-install.lock
    work=$(mktemp -d "$bin_dir/.jmpkit-install.XXXXXXXX") || fail 'Cannot stage in install directory'
    for existing in "$bin_dir/jmpkit" "$bin_dir/jmpkit.previous"; do
        [ ! -L "$existing" ] || fail "Refusing executable symlink: $existing"
        [ ! -e "$existing" ] || [ -f "$existing" ] || fail "Not a regular executable: $existing"
    done
    if [ "$rollback" = yes ]; then
        [ -x "$bin_dir/jmpkit.previous" ] || fail 'No previous executable to restore'
        cp -- "$bin_dir/jmpkit.previous" "$work/jmpkit"
        chmod 755 "$work/jmpkit"
        if [ -f "$bin_dir/jmpkit" ]; then cp -- "$bin_dir/jmpkit" "$work/previous"; fi
        mv -f -- "$work/jmpkit" "$bin_dir/jmpkit"
        if [ -f "$work/previous" ]; then mv -f -- "$work/previous" "$bin_dir/jmpkit.previous"; fi
        note "Restored $bin_dir/jmpkit. App keys and settings are unchanged."
        exit 0
    fi
else
    work=$(mktemp -d "${TMPDIR:-/tmp}/jmpkit-run.XXXXXXXX") || fail 'Cannot make a private temporary directory'
fi

for tool in curl uname sha256sum awk sed grep getconf; do
    command -v "$tool" >/dev/null 2>&1 || fail "Missing $tool; install it separately"
done
[ "$(uname -s)" = Linux ] || fail 'This release supports Linux only'
case "$(uname -m)" in x86_64|amd64) ;; *) fail 'This release supports x86-64 only' ;; esac
libc=$(getconf GNU_LIBC_VERSION 2>/dev/null) || fail 'This release needs glibc 2.34 or newer (not musl)'
printf '%s\n' "$libc" | awk '
    $1 == "glibc" && split($2, v, ".") >= 2 && (v[1] > 2 || (v[1] == 2 && v[2] >= 34)) {ok=1}
    END {exit !ok}' || fail 'This release needs glibc 2.34 or newer'

base=${JMPKIT_CLI_BASE_URL:-https://jmpkit.com/cli}
base=${base%/}
case "$base" in *[!A-Za-z0-9._:/-]*) fail 'Invalid download base URL' ;; esac
printf '%s\n' "$base" | grep -Eq '^https://[A-Za-z0-9._:/-]+$|^http://(127[.]0[.]0[.]1|localhost)(:[0-9]+)?/[A-Za-z0-9._/-]+$' ||
    fail 'Download base must be HTTPS (plain HTTP is allowed only for loopback tests)'
protocols='=https'
case "$base" in http://*) protocols='=http,https' ;; esac
fetch() {
    curl --fail --silent --show-error --location --proto "$protocols" \
        --proto-redir "$protocols" --connect-timeout 15 --max-time 120 "$1" -o "$2" ||
        fail 'Download failed; the installed executable was not replaced'
}
if [ -z "$version" ]; then
    fetch "$base/latest.json" "$work/latest.json"
    version=$(sed -n 's/^[[:space:]]*"version":[[:space:]]*"\([^"]*\)"[,]\{0,1\}[[:space:]]*$/\1/p' "$work/latest.json")
fi
case "$version" in ''|*[!A-Za-z0-9.-]*) fail 'Invalid release version' ;; esac
printf '%s\n' "$version" | grep -Eq '^[0-9]+[.][0-9]+[.][0-9]+(-[A-Za-z0-9.-]+)?$' || fail 'Invalid release version'
artifact=jmpkit-linux-x86_64-gnu
release=$base/releases/$version
fetch "$release/SHA256SUMS" "$work/SHA256SUMS"
expected=$(awk -v file="$artifact" 'NF == 2 && $2 == file {print $1}' "$work/SHA256SUMS")
[ "${#expected}" -eq 64 ] && printf '%s\n' "$expected" | grep -Eq '^[0-9a-f]{64}$' || fail 'Missing or invalid release checksum'
fetch "$release/$artifact" "$work/jmpkit"
actual=$(sha256sum "$work/jmpkit" | awk '{print $1}')
[ "$actual" = "$expected" ] || fail 'Checksum mismatch; refusing to install or run'
chmod 755 "$work/jmpkit"

if [ "$mode" = install ]; then
    # Check the loader/runtime before replacing an existing working executable.
    "$work/jmpkit" --version >/dev/null || fail 'Cannot execute this build; nothing was replaced'
    if [ -f "$bin_dir/jmpkit" ]; then
        cp -p -- "$bin_dir/jmpkit" "$work/previous"
        mv -f -- "$work/previous" "$bin_dir/jmpkit.previous"
    fi
    mv -f -- "$work/jmpkit" "$bin_dir/jmpkit"
    note "Installed JMPKit $version at $bin_dir/jmpkit"
    case ":${PATH:-}:" in *":$bin_dir:"*) ;; *) note "Add $bin_dir to PATH to run jmpkit from any directory." ;; esac
else
    # Keep inherited stdin for downloaded launchers, including TUI/file input.
    # A piped curl | sh consumes stdin; download this script first for those uses.
    "$work/jmpkit" "$@" <&0 &
    child=$!
    status=0
    wait "$child" || status=$?
    child=
    [ "$status" -ne 126 ] || note 'Cannot execute here; choose an executable TMPDIR or use install.sh.'
    exit "$status"
fi
