#!/bin/sh
# RYQO runner installer.
#
#   curl -fsSL https://get.ryqo.io | sh
#
# Deliberately POSIX sh and nothing else: this runs before RYQO exists on the
# machine, so it may not assume bash, node, or anything but a shell and curl.
#
# What it does, in order: work out the platform, fetch the matching tarball,
# unpack it beside the previous version, move the symlink, and hand over to
# `ryqo pair`. Credentials are never handled here — pairing does that, and it
# does it without anything being copied by hand (RYQ-75).
set -eu

BASE_URL="${RYQO_BASE_URL:-https://get.ryqo.io}"
PREFIX="${RYQO_PREFIX:-$HOME/.ryqo}"
BIN_DIR="${RYQO_BIN_DIR:-$HOME/.local/bin}"
APP_DIR="$PREFIX/app"

say() { printf '%s\n' "$*"; }
die() { printf '\n  ✗ %s\n\n' "$*" >&2; exit 1; }

need() { command -v "$1" >/dev/null 2>&1 || die "\`$1\` is required but not installed."; }
need curl
need tar
need uname

detect_platform() {
  os=$(uname -s)
  arch=$(uname -m)
  case "$os" in
    Darwin) os=darwin ;;
    Linux) os=linux ;;
    # Nothing here is impossible to support, but silently installing something
    # that cannot run is worse than saying so.
    *) die "RYQO does not ship a build for $os yet." ;;
  esac
  case "$arch" in
    arm64 | aarch64) arch=arm64 ;;
    x86_64 | amd64) arch=x64 ;;
    *) die "RYQO does not ship a build for $arch yet." ;;
  esac
  printf '%s-%s' "$os" "$arch"
}

PLATFORM=$(detect_platform)
VERSION="${RYQO_VERSION:-latest}"

if [ "$VERSION" = "latest" ]; then
  VERSION=$(curl -fsSL "$BASE_URL/latest.txt" 2>/dev/null | tr -d '\r\n ' || true)
  [ -n "$VERSION" ] || die "Could not ask $BASE_URL which version is current."
fi

TARBALL="ryqo-$VERSION-$PLATFORM.tar.gz"
URL="$BASE_URL/$TARBALL"
TARGET="$APP_DIR/$VERSION"

say ""
say "  Installing RYQO runner $VERSION ($PLATFORM)"
say "    from $URL"

TMP=$(mktemp -d)
# Any exit path cleans up, including the failures below.
trap 'rm -rf "$TMP"' EXIT INT TERM

curl -fsSL "$URL" -o "$TMP/$TARBALL" || die "Download failed. Is $VERSION published for $PLATFORM?"

mkdir -p "$TARGET"
# Unpacked into a version directory rather than over the previous one, so an
# interrupted install cannot leave a half-replaced runtime behind.
tar -xzf "$TMP/$TARBALL" -C "$TARGET" --strip-components=1 || die "The archive did not unpack."

[ -x "$TARGET/bin/ryqo" ] || die "The archive is missing bin/ryqo — refusing to link it."

mkdir -p "$BIN_DIR"
ln -sfn "$TARGET/bin/ryqo" "$BIN_DIR/ryqo"

say "  ✓ Installed to $TARGET"
say "    Linked  $BIN_DIR/ryqo"

# A symlink nobody can reach is not an install. Say it plainly rather than
# leaving the next command to fail with "command not found".
case ":$PATH:" in
  *":$BIN_DIR:"*) ;;
  *)
    say ""
    say "  ⚠ $BIN_DIR is not on your PATH. Add this to your shell profile:"
    say "      export PATH=\"\$PATH:$BIN_DIR\""
    ;;
esac

"$TARGET/bin/ryqo" service install || say "  ⚠ Could not set up automatic start; run \`ryqo service install\` later."

# What RYQO DRIVES but no longer carries.
#
# ⚠️ Said here, at install time, because the alternative is finding out much
# later and much worse. The tarball stopped bundling Claude Code and Codex (that
# is most of a quarter-gigabyte, and it made the archive platform-specific), so
# a machine without them installs perfectly and then cannot run a single agent.
# The cockpit does say so per account, but only once the daemon is paired and
# reporting — minutes later, in a different place, to somebody who has already
# moved on.
MISSING=""
command -v claude >/dev/null 2>&1 || MISSING="$MISSING claude"
command -v codex >/dev/null 2>&1 || MISSING="$MISSING codex"
if [ -n "$MISSING" ]; then
  say ""
  say "  ⚠ RYQO runs the providers' own agents, and this machine is missing:$MISSING"
  say "    Install what you plan to use, then sign in with \`ryqo auth\`:"
  case "$MISSING" in
    *claude*) say "      Claude Code  https://claude.com/code" ;;
  esac
  case "$MISSING" in
    *codex*) say "      Codex        npm i -g @openai/codex" ;;
  esac
fi

# Which RYQO this machine belongs to.
#
# ⚠️ Passed to `pair`, because a fresh install has no idea. The runner defaults
# to http://127.0.0.1:3210 — right for a developer running Convex locally, and
# wrong for literally every real install, which then fails with "Could not reach
# RYQO at 127.0.0.1" and no hint that a flag exists. Self-hosted is the product,
# so the address cannot be a constant; the cockpit prints this one-liner with its
# own URLs already filled in.
PAIR_ARGS=""
[ -n "${RYQO_CONVEX_URL:-}" ] && PAIR_ARGS="--convex-url $RYQO_CONVEX_URL"
[ -n "${RYQO_WEB_URL:-}" ] && PAIR_ARGS="$PAIR_ARGS --web-url $RYQO_WEB_URL"

# Pairing needs a person at a browser, and a piped installer has no terminal to
# ask in. Hand over only when there is one; otherwise print the next step.
if [ -t 0 ] && [ -t 1 ]; then
  say ""
  # Unquoted on purpose: empty must expand to no arguments at all.
  # shellcheck disable=SC2086
  exec "$TARGET/bin/ryqo" pair $PAIR_ARGS
else
  say ""
  say "  Next, pair this machine:"
  say "      $BIN_DIR/ryqo pair $PAIR_ARGS"
  say ""
fi
