#!/bin/sh
# Subtype installer.   curl -fsSL https://subtypelang.com/install.sh | sh
#
# Installs the `sub` binary into ~/.local/bin (no sudo). It downloads a prebuilt release from subtypelang.com,
# checks its SHA-256 against the published SHA256SUMS, and puts it in place. Read it before you run it:
# it is about 120 lines of plain sh.
#
# It can also install the Subtype skill for Claude Code (so your agent writes scripts in Subtype): it asks at the end,
# or pass --skill / --no-skill. The skill goes to ~/.claude/skills/subtype (nothing else in your Claude settings is touched).
#
# Options (pass after `sh -s --` when piping):  --version X   --dir DIR   --skill   --no-skill   --skill-dir DIR   --uninstall   --help
# Environment: SUB_INSTALL_DIR, SUB_VERSION, SUB_BASE_URL (for testing), CLAUDE_SKILLS_DIR (default ~/.claude/skills)
set -eu

BASE="${SUB_BASE_URL:-https://subtypelang.com}"
DIR="${SUB_INSTALL_DIR:-$HOME/.local/bin}"
VERSION="${SUB_VERSION:-}"
SKILLS="${CLAUDE_SKILLS_DIR:-$HOME/.claude/skills}"
SKILL=ask   # ask | yes | no
UNINSTALL=0

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

while [ $# -gt 0 ]; do
  case "$1" in
    --version) [ $# -ge 2 ] || err "--version needs a value"; VERSION="$2"; shift 2 ;;
    --dir) [ $# -ge 2 ] || err "--dir needs a value"; DIR="$2"; shift 2 ;;
    --skill) SKILL=yes; shift ;;
    --no-skill) SKILL=no; shift ;;
    --skill-dir) [ $# -ge 2 ] || err "--skill-dir needs a value"; SKILLS="$2"; shift 2 ;;
    --uninstall) UNINSTALL=1; shift ;;
    -h|--help) sed -n '2,15p' "$0" 2>/dev/null | sed 's/^# \{0,1\}//'; exit 0 ;;
    *) err "unknown option: $1 (try --help)" ;;
  esac
done

if [ "$UNINSTALL" = 1 ]; then
  if [ -e "$DIR/sub" ]; then rm -f "$DIR/sub"; say "removed $DIR/sub"; else say "nothing to remove at $DIR/sub"; fi
  if [ -f "$SKILLS/subtype/SKILL.md" ] && grep -q '^name: subtype$' "$SKILLS/subtype/SKILL.md" 2>/dev/null; then rm -rf "$SKILLS/subtype"; say "removed the skill at $SKILLS/subtype"; fi
  exit 0
fi

if command -v curl >/dev/null 2>&1; then
  fetch() { curl -fsSL "$1" -o "$2"; }
  fetch_text() { curl -fsSL "$1"; }
elif command -v wget >/dev/null 2>&1; then
  fetch() { wget -q "$1" -O "$2"; }
  fetch_text() { wget -qO- "$1"; }
else
  err "needs curl or wget"
fi

if command -v sha256sum >/dev/null 2>&1; then sha() { sha256sum "$1" | cut -d' ' -f1; }
elif command -v shasum >/dev/null 2>&1; then sha() { shasum -a 256 "$1" | cut -d' ' -f1; }
else err "needs sha256sum or shasum to verify the download"; fi

os="$(uname -s)"; arch="$(uname -m)"
case "$os-$arch" in
  Linux-x86_64|Linux-amd64)  target="x86_64-unknown-linux-musl" ;;
  Linux-aarch64|Linux-arm64) target="aarch64-unknown-linux-musl" ;;
  Darwin-arm64)              target="aarch64-apple-darwin" ;;
  Darwin-x86_64)             target="x86_64-apple-darwin" ;;
  *) err "no prebuilt binary for $os $arch. Build from source: see $BASE/start/install/" ;;
esac

if [ -z "$VERSION" ]; then
  VERSION="$(fetch_text "$BASE/releases/latest/VERSION" | tr -d '[:space:]')" || err "could not reach $BASE (is it online?)"
  [ -n "$VERSION" ] || err "the server did not say which version is the latest"
fi

name="sub-$VERSION-$target"
tmp="$(mktemp -d 2>/dev/null || mktemp -d -t subtype)"
trap 'rm -rf "$tmp"' EXIT INT TERM

say "Installing sub $VERSION for $target"
fetch "$BASE/releases/$VERSION/SHA256SUMS" "$tmp/SHA256SUMS" || err "could not download the checksums for $VERSION"
want="$(grep " $name.tar.gz\$" "$tmp/SHA256SUMS" | cut -d' ' -f1 | head -n1)"
[ -n "$want" ] || err "there is no prebuilt binary for $target in version $VERSION yet. Build from source: $BASE/start/install/"
fetch "$BASE/releases/$VERSION/$name.tar.gz" "$tmp/$name.tar.gz" || err "could not download $name.tar.gz"
got="$(sha "$tmp/$name.tar.gz")"
[ "$got" = "$want" ] || err "checksum mismatch for $name.tar.gz (expected $want, got $got). Nothing was installed."
tar -xzf "$tmp/$name.tar.gz" -C "$tmp" || err "could not unpack the download"
[ -f "$tmp/$name/sub" ] || err "the download does not contain a sub binary"

mkdir -p "$DIR"
if [ -e "$DIR/sub" ]; then prev="$("$DIR/sub" --version 2>/dev/null || echo unknown)"; say "replacing $prev"; fi
cp "$tmp/$name/sub" "$DIR/sub.new" && chmod 755 "$DIR/sub.new" && mv -f "$DIR/sub.new" "$DIR/sub"
"$DIR/sub" --version >/dev/null 2>&1 || err "the installed binary does not run on this machine ($DIR/sub)"
say "installed $("$DIR/sub" --version) to $DIR/sub"

# ---- the Claude Code skill (optional) ----
if [ "$SKILL" = ask ]; then
  if [ -r /dev/tty ] && [ -w /dev/tty ]; then
    printf '\nAlso install the Subtype skill for Claude Code, so your agent uses Subtype for scripts? [y/N] ' > /dev/tty
    read -r ans < /dev/tty || ans=n
    case "$ans" in y|Y|yes|YES) SKILL=yes ;; *) SKILL=no ;; esac
  else
    SKILL=no
  fi
fi
if [ "$SKILL" = yes ]; then
  sname="subtype-skill-$VERSION"
  swant="$(grep " $sname.tar.gz\$" "$tmp/SHA256SUMS" | cut -d' ' -f1 | head -n1)"
  if [ -z "$swant" ]; then
    say "this release has no skill package; skipping the skill (see $BASE/agents/)"
  else
    fetch "$BASE/releases/$VERSION/$sname.tar.gz" "$tmp/$sname.tar.gz" || err "could not download the skill"
    sgot="$(sha "$tmp/$sname.tar.gz")"
    [ "$sgot" = "$swant" ] || err "checksum mismatch for the skill package. The sub binary is installed; the skill was not."
    mkdir -p "$tmp/skill" && tar -xzf "$tmp/$sname.tar.gz" -C "$tmp/skill" || err "could not unpack the skill"
    [ -f "$tmp/skill/subtype/SKILL.md" ] || err "the skill package has no SKILL.md"
    mkdir -p "$SKILLS"
    if [ -e "$SKILLS/subtype" ]; then say "replacing the skill at $SKILLS/subtype"; rm -rf "$SKILLS/subtype"; fi
    cp -R "$tmp/skill/subtype" "$SKILLS/subtype"
    find "$SKILLS/subtype" -name '*.sh' -exec chmod 755 {} + 2>/dev/null || true
    say "installed the Subtype skill to $SKILLS/subtype"
    say "start a new Claude Code session to pick it up. Optional: the reminder hook is described in $SKILLS/subtype/INSTALL.md"
  fi
fi

case ":$PATH:" in
  *":$DIR:"*) say "Try it:  sub init my-project && cd my-project && sub explain main.sub" ;;
  *) say ""; say "$DIR is not on your PATH. Add this to your shell profile:"; say "  export PATH=\"$DIR:\$PATH\""; say "then open a new terminal and run:  sub --version" ;;
esac
