#!/usr/bin/env sh
#
# DDIPE CLI installer.
#
#   curl -fsSL https://get.reysecurity.ai | sh
#   curl -fsSL https://get.reysecurity.ai | sh -s -- --license=<token>
#   curl -fsSL https://get.reysecurity.ai | sh -s -- --uninstall
#
# Downloads the `ddipe` CLI for this OS/arch, verifies its checksum, unpacks it
# once into a versioned directory, and links `ddipe` onto your PATH. No Python
# required. Running it again upgrades: the new version is unpacked beside the
# old one and the link is switched atomically.
#
# Env overrides:
#   DDIPE_INSTALL_BASE   base URL (default: https://get.reysecurity.ai)
#   DDIPE_CHANNEL        latest | a version like v0.7.0 (default: latest; 0.7.0 is
#                        the first release this installer can unpack)
#   DDIPE_BIN_DIR        where the `ddipe` link goes
#                        (default: /usr/local/bin if writable, else ~/.local/bin)
#   DDIPE_HOME           where versions are unpacked (default: ~/.local/share/ddipe)
#
set -eu

BASE="${DDIPE_INSTALL_BASE:-https://get.reysecurity.ai}"
CHANNEL="${DDIPE_CHANNEL:-latest}"
BIN_DIR="${DDIPE_BIN_DIR:-/usr/local/bin}"
DDIPE_HOME="${DDIPE_HOME:-$HOME/.local/share/ddipe}"
LICENSE=""
UNINSTALL=0

for arg in "$@"; do
  case "$arg" in
    --license=*) LICENSE="${arg#--license=}" ;;
    --uninstall) UNINSTALL=1 ;;
    *) echo "ddipe: unknown option: $arg" >&2; exit 2 ;;
  esac
done

# A link location the user can write without root. Falling back to ~/.local/bin
# rather than asking for sudo: a pipe from the internet does not get root.
if mkdir -p "$BIN_DIR" 2>/dev/null && [ -w "$BIN_DIR" ]; then
  dest="$BIN_DIR"
else
  dest="$HOME/.local/bin"
fi
link="$dest/ddipe"

if [ "$UNINSTALL" -eq 1 ]; then
  # Only remove a link that points into our own directory, so an unrelated
  # `ddipe` that happens to sit in the same place is never touched.
  if [ -L "$link" ]; then
    case "$(readlink "$link")" in
      "$DDIPE_HOME"/*) rm -f "$link"; echo "ddipe: removed $link" ;;
    esac
  fi
  rm -rf "$DDIPE_HOME"
  echo "ddipe: removed $DDIPE_HOME"
  echo "ddipe: your license and local data in ~/.ddipe were left in place."
  exit 0
fi

os="$(uname -s | tr '[:upper:]' '[:lower:]')"
arch="$(uname -m)"
case "$arch" in
  x86_64 | amd64) arch="x64" ;;
  arm64 | aarch64) arch="arm64" ;;
  *) echo "ddipe: unsupported architecture: $arch" >&2; exit 1 ;;
esac
case "$os" in
  darwin | linux) ;;
  *) echo "ddipe: unsupported OS: $os (macOS and Linux only)" >&2; exit 1 ;;
esac

target="ddipe-${os}-${arch}"
url="${BASE}/ddipe/${CHANNEL}/${target}.tar.gz"

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT

# Check the target against what is actually published, rather than special-
# casing platforms one at a time. The download host is S3 behind CloudFront
# with no list permission, so a missing object answers 403, not 404 — and a
# bare "403" reads like a broken account rather than an unbuilt platform.
#
# Keep in step with the build matrix in .github/workflows/build-cli.yml.
PUBLISHED="darwin-arm64 linux-x64 linux-arm64"
case " $PUBLISHED " in
  *" ${os}-${arch} "*) ;;
  *)
    echo "ddipe: no binary is published for ${os}-${arch}." >&2
    echo "       Published targets: ${PUBLISHED}." >&2
    echo "       Contact Rey Security if you need this platform." >&2
    exit 1 ;;
esac

echo "ddipe: downloading ${target} (${CHANNEL})…"
curl -fsSL "$url" -o "$tmp/ddipe.tar.gz"

# Verify the checksum — REQUIRED (fail closed). The published .sha256 is the only
# client-side integrity control on the curl|sh path, so a missing, unreachable, or
# mismatching checksum aborts the install rather than running an unverified binary.
if ! curl -fsSL "${url}.sha256" -o "$tmp/ddipe.sha256"; then
  echo "ddipe: could not fetch ${target}.tar.gz.sha256 — aborting (integrity cannot be verified)." >&2
  exit 1
fi
expected="$(awk '{print $1}' "$tmp/ddipe.sha256")"
if command -v sha256sum >/dev/null 2>&1; then
  actual="$(sha256sum "$tmp/ddipe.tar.gz" | awk '{print $1}')"
else
  actual="$(shasum -a 256 "$tmp/ddipe.tar.gz" | awk '{print $1}')"
fi
if [ -z "$expected" ] || [ "$expected" != "$actual" ]; then
  echo "ddipe: checksum verification failed — aborting." >&2
  exit 1
fi
echo "ddipe: checksum verified."

# Unpack once, here, rather than on every launch. The previous single-file build
# re-extracted itself to a temporary directory each time it ran — ~10 s per
# command, longer than the timeout of the agent hooks that call it.
tar -xzf "$tmp/ddipe.tar.gz" -C "$tmp"
version="$("$tmp/ddipe/ddipe" --version 2>/dev/null | awk '{print $NF}')"
case "$version" in
  "" | */* | .*)
    echo "ddipe: the downloaded build does not run on this machine — aborting." >&2
    exit 1 ;;
esac

mkdir -p "$DDIPE_HOME/versions" "$dest"
target_dir="$DDIPE_HOME/versions/$version"
rm -rf "$target_dir"
mv "$tmp/ddipe" "$target_dir"
# tar restored the build date; mark it as the newest install for the pruning below.
touch "$target_dir"

# Switch the link atomically: a rename never leaves `ddipe` missing, even for
# an agent hook that fires in the middle of an upgrade. A previous single-file
# install at the same path is simply replaced.
rm -f "$dest/.ddipe.new"
ln -s "$target_dir/ddipe" "$dest/.ddipe.new"
mv -f "$dest/.ddipe.new" "$link"

# Keep the two most recent versions for rollback, remove the rest.
ls -1t "$DDIPE_HOME/versions" | tail -n +3 | while read -r old; do
  [ "$old" = "$version" ] || rm -rf "$DDIPE_HOME/versions/$old"
done

echo ""
echo "  ✓ ddipe $version installed — $link"
case ":$PATH:" in
  *":$dest:"*) ;;
  *) echo "  → add it to your PATH:  export PATH=\"$dest:\$PATH\"" ;;
esac

# Another `ddipe` earlier on the PATH silently wins over the one just installed:
# the user runs something else entirely and has no way to tell. Say which.
resolved="$(command -v ddipe 2>/dev/null || true)"
if [ -n "$resolved" ] && [ "$resolved" != "$link" ]; then
  echo "" >&2
  echo "  ddipe: warning — another ddipe comes first on your PATH:" >&2
  echo "           $resolved" >&2
  echo "         typing \`ddipe\` will run that one, not $version." >&2
  echo "         remove it, or put $dest earlier in your PATH." >&2
fi

# The binary is free to download and does nothing without a license. That is the
# protection: not who holds the bytes, but who holds a token.
if [ -n "$LICENSE" ]; then
  if "$link" activate "$LICENSE" >/dev/null 2>&1; then
    echo "  ✓ license activated"
  else
    echo "" >&2
    echo "  ddipe: license activation failed — installed but not usable." >&2
    echo "  retry with:  ddipe activate <your-license-key>" >&2
    exit 1
  fi
else
  echo "  → next: ddipe activate <your-license-key>"
fi

# Installing the binary protects nothing on its own. Saying so here is the
# difference between a customer who is covered and one who believes they are.
echo ""
echo "  then install the runtime gate into your agent:"
echo "      ddipe moat-install --platform codex  --scope user --apply"
echo "      ddipe moat-install --platform claude --scope user --apply"
echo ""
echo "  on Codex, hooks do not run until you approve them in the agent. the"
echo "  installer reports whether DDIPE Runtime is active or still awaiting approval."
echo ""
