#!/bin/sh
# utoo bootstrap placeholder.
#
# Two paths replace this file with the real platform binary:
#   1. postinstall (fast path) — copies from the optional @utoo/utoo-${OS}-
#      ${ARCH} sibling installed alongside us into bin/utoo.
#   2. this script (self-heal) — runs only if (1) was skipped or failed
#      (--no-optional, --ignore-scripts, missing platform variant, network
#      blip, EACCES on global prefix, ...). Downloads the same tarball
#      directly from the registry and atomic-renames it onto bin/utoo.
#
# Either way the user's first invocation succeeds; failed postinstall is
# recoverable instead of a permanent dead end.
#
# Flow:
#
#   user runs `utoo …` or `ut …`
#           │
#           ▼  (npm shim symlink, both `utoo` and `ut` point here)
#   <pkg>/bin/utoo
#           │
#           ├── if real binary  ─▶  exec, done.
#           │
#           └── if still placeholder (this script):
#                   resolve $0 through symlinks → real <pkg>/bin/utoo
#                   detect OS / ARCH
#                   walk up to find utoo's package.json → version
#                   for REG in [$UTOO_REGISTRY?, npmjs, npmmirror]:
#                       curl -fsSL --connect-timeout 10 --max-time 120
#                            <REG>/@utoo/utoo-${OS}-${ARCH}/-/...tgz
#                       first 2xx wins
#                   tar -xzf into mktemp dir
#                   stage tmp/package/bin/utoo as bin/utoo.tmp
#                   mv -f utoo.tmp utoo  (atomic; current open fd stays valid)
#                   trap clear + rm -rf $TMP  (exec skips traps)
#                   exec bin/utoo "$@"
#
# Invariants:
#   - bin/utoo is the only physical bin file. bin/ut also exists as a
#     placeholder but is never invoked (npm bin map: `ut` → `bin/utoo`).
#   - The flow is idempotent. Any mid-flight failure (download / tar / pre-mv
#     crash) leaves either the placeholder or the real binary on disk — never
#     a half-installed state. Next invocation retries.
set -e

# Resolve $0 through symlinks. npm registers global bins as symlinks
# (`$prefix/bin/utoo` -> `$prefix/lib/node_modules/utoo/bin/utoo`); without
# this, `dirname "$0"` yields the symlink dir and the package.json walk-up
# below misses the real package root.
SELF_PATH="$0"
while [ -L "$SELF_PATH" ]; do
    LINK=$(readlink "$SELF_PATH")
    case "$LINK" in
        /*) SELF_PATH="$LINK" ;;
        *) SELF_PATH="$(dirname "$SELF_PATH")/$LINK" ;;
    esac
done
SELF_DIR=$(cd "$(dirname "$SELF_PATH")" && pwd)

UNAME_S=$(uname -s 2>/dev/null || echo "")
case "$UNAME_S" in
    MINGW*|MSYS*|CYGWIN*) OS="win32" ;;
    Darwin) OS="darwin" ;;
    Linux) OS="linux" ;;
    *)
        if [ "${OSTYPE:-}" = "msys" ] || [ "${OSTYPE:-}" = "win32" ]; then
            OS="win32"
        else
            echo "utoo: unsupported OS: ${UNAME_S:-unknown}" >&2
            exit 1
        fi
        ;;
esac

if [ "$OS" = "win32" ]; then
    case "${PROCESSOR_ARCHITECTURE:-}" in
        AMD64|x86_64) ARCH="x64" ;;
        ARM64) ARCH="arm64" ;;
        *) ARCH="x64" ;;
    esac
else
    ARCH=$(uname -m)
    case "$ARCH" in
        x86_64|amd64) ARCH="x64" ;;
        aarch64|arm64) ARCH="arm64" ;;
        *)
            echo "utoo: unsupported arch: $ARCH" >&2
            exit 1
            ;;
    esac
fi

PKG="utoo-${OS}-${ARCH}"

# Resolve installed version from the enclosing utoo package.json.
PKG_ROOT=""
d="$SELF_DIR"
while [ "$d" != "/" ] && [ -n "$d" ]; do
    if [ -f "$d/package.json" ] && grep -q '"name"[[:space:]]*:[[:space:]]*"utoo"' "$d/package.json"; then
        PKG_ROOT="$d"
        break
    fi
    d=$(dirname "$d")
done

if [ -z "$PKG_ROOT" ]; then
    echo "utoo: cannot locate utoo package.json from $SELF_DIR" >&2
    exit 1
fi

VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$PKG_ROOT/package.json" \
    | head -1 | sed 's/.*"\([^"]*\)"$/\1/')

if [ -z "$VERSION" ]; then
    echo "utoo: cannot read version from $PKG_ROOT/package.json" >&2
    exit 1
fi

# Registry order mirrors utoo.land/install. Keep this list in sync with the
# canonical installer if you add a mirror.
REGISTRIES="https://registry.npmjs.org https://registry.npmmirror.com"
[ -n "${UTOO_REGISTRY:-}" ] && REGISTRIES="$UTOO_REGISTRY $REGISTRIES"

if ! command -v curl >/dev/null 2>&1; then
    echo "utoo: curl is required to bootstrap the binary" >&2
    exit 1
fi
if ! command -v tar >/dev/null 2>&1; then
    echo "utoo: tar is required to bootstrap the binary" >&2
    exit 1
fi

echo "utoo: bootstrapping @utoo/${PKG}@${VERSION}..." >&2

TMP=$(mktemp -d)
trap 'rm -rf "$TMP"' EXIT INT TERM

DOWNLOADED=0
for REG in $REGISTRIES; do
    URL="${REG}/@utoo/${PKG}/-/${PKG}-${VERSION}.tgz"
    # --max-time caps the whole transfer; without it a registry that accepts
    # the connection then trickles bytes hangs the user's first command.
    if curl -fsSL --connect-timeout 10 --max-time 120 -o "$TMP/pkg.tgz" "$URL" 2>/dev/null; then
        DOWNLOADED=1
        break
    fi
done

if [ "$DOWNLOADED" != "1" ]; then
    echo "utoo: failed to download @utoo/${PKG}@${VERSION} from any registry" >&2
    echo "utoo: tried: $REGISTRIES" >&2
    exit 1
fi

if ! tar -xzf "$TMP/pkg.tgz" -C "$TMP"; then
    echo "utoo: failed to extract package archive" >&2
    exit 1
fi

SRC_BIN="$TMP/package/bin/utoo"
if [ ! -f "$SRC_BIN" ]; then
    echo "utoo: binary not found in package (expected package/bin/utoo)" >&2
    exit 1
fi

# Atomic install. Stage as a sibling tmp file, then rename onto bin/utoo.
# POSIX rename keeps this script's open fd intact, so the current invocation
# keeps running while future invocations see the new binary. npm shims for
# both `utoo` and `ut` resolve to bin/utoo via the package.json bin map, so
# replacing only this one file covers both commands.
cp "$SRC_BIN" "$SELF_DIR/utoo.tmp"
chmod +x "$SELF_DIR/utoo.tmp"
mv -f "$SELF_DIR/utoo.tmp" "$SELF_DIR/utoo"

# `exec` replaces the process image and skips the EXIT/INT/TERM trap. Clean
# up the temp dir manually, otherwise every bootstrap leaks an mktemp dir.
trap - EXIT INT TERM
rm -rf "$TMP"

exec "$SELF_DIR/utoo" "$@"
