#!/bin/sh
# land installer: the `land` binary plus the global agent skill, then sign-in.
#
#   curl -fsSL https://useland.dev/install | sh
#
# Steps:
#   1. downloads land-<version>-<target>.tar.gz and SHA256SUMS from
#        $LAND_RELEASE_BASE/<version>/<asset>
#      (STUB(morning: confirm hosting URL): default base https://useland.dev/releases), and refuses to install
#      unless the tarball's sha256 matches its line in SHA256SUMS;
#   2. installs `land` to $LAND_INSTALL_DIR (default ~/.local/bin);
#   3. installs the land skill (SKILL.md from the tarball) to ~/.claude/skills/land, and to ~/.codex/skills/land
#      when ~/.codex exists;
#   4. signs in. A person at a terminal gets `land login` (read from /dev/tty, so `curl | sh` works too).
#      An agent (no terminal on stdout, or no /dev/tty) gets `land login --no-wait`, run for it: that prints
#      {"url","code"} JSON for the agent to show the person.
# It never edits your repositories, shell profile or git config, and never reads or prints a key.
#
# Environment:
#   LAND_VERSION        version to install (default: the version this script was released with)
#   LAND_RELEASE_BASE   base URL holding <version>/<asset> (https, or file:// for testing)
#   LAND_INSTALL_DIR    where `land` goes (default ~/.local/bin)
#   LAND_NO_LOGIN=1     skip step 4
#   LAND_NO_SKILL=1     skip step 3
set -eu

VERSION="${LAND_VERSION:-0.1.0}"
BASE="${LAND_RELEASE_BASE:-https://useland.dev/releases}"
DIR="${LAND_INSTALL_DIR:-$HOME/.local/bin}"

say() { printf '%s\n' "land install: $*" >&2; }
die() { say "$1"; [ -n "${2:-}" ] && printf '  fix: %s\n' "$2" >&2; exit 1; }

case "$BASE" in
  https://*|file://*) ;;
  http://localhost*|http://127.0.0.1*) ;;
  *) die "LAND_RELEASE_BASE must be https (got $BASE)" "unset LAND_RELEASE_BASE" ;;
esac

command -v curl >/dev/null 2>&1 || die "curl is required" "install curl, then run this again"
command -v tar >/dev/null 2>&1 || die "tar is required" "install tar, then run this again"

os=$(uname -s); arch=$(uname -m)
case "$arch" in arm64) arch=aarch64 ;; amd64) arch=x86_64 ;; esac
case "$os-$arch" in
  Darwin-aarch64) target=aarch64-apple-darwin ;;
  Linux-x86_64) target=x86_64-unknown-linux-gnu ;;
  *) die "no land build for $os $arch yet" "available: macOS arm64, Linux x86_64" ;;
esac
asset="land-$VERSION-$target.tar.gz"

tmp=$(mktemp -d 2>/dev/null || mktemp -d -t land)
trap 'rm -rf "$tmp"' EXIT INT TERM

say "downloading $asset"
curl -fsSL --proto '=https,file' "$BASE/$VERSION/$asset" -o "$tmp/$asset" \
  || die "could not download $BASE/$VERSION/$asset" "check the network and LAND_VERSION, then run this again"
curl -fsSL --proto '=https,file' "$BASE/$VERSION/SHA256SUMS" -o "$tmp/SHA256SUMS" \
  || die "could not download $BASE/$VERSION/SHA256SUMS" "check the network, then run this again"

# SHA256SUMS lines are "<hex>  <name>"; the asset must appear exactly once.
want=$(awk -v a="$asset" '$2 == a || $2 == "*" a { print $1 }' "$tmp/SHA256SUMS")
case "$want" in
  ""|*[!0-9a-f]*) die "SHA256SUMS has no usable entry for $asset" "tell support@useland.dev" ;;
esac
if command -v sha256sum >/dev/null 2>&1; then got=$(sha256sum "$tmp/$asset" | cut -d' ' -f1)
else got=$(shasum -a 256 "$tmp/$asset" | cut -d' ' -f1); fi
[ "$want" = "$got" ] || die "checksum mismatch for $asset (want $want, got $got); nothing installed" "run this again; if it repeats, tell support@useland.dev"
say "checksum ok"

mkdir "$tmp/x"
tar -xzf "$tmp/$asset" -C "$tmp/x" || die "could not unpack $asset" "tell support@useland.dev"
[ -f "$tmp/x/land" ] || die "$asset has no land binary" "tell support@useland.dev"
chmod 0755 "$tmp/x/land"
"$tmp/x/land" --help >/dev/null 2>&1 || die "the downloaded binary does not run on this machine" "tell support@useland.dev: $asset"
mkdir -p "$DIR"
cp -f "$tmp/x/land" "$DIR/land.new.$$" && mv -f "$DIR/land.new.$$" "$DIR/land"
say "installed $DIR/land ($VERSION)"

case ":$PATH:" in
  *":$DIR:"*) LAND="land" ;;
  *) LAND="$DIR/land"; say "$DIR is not on PATH; add it: export PATH=\"$DIR:\$PATH\"" ;;
esac

if [ "${LAND_NO_SKILL:-}" != 1 ]; then
  if [ -f "$tmp/x/SKILL.md" ]; then
    for d in "$HOME/.claude/skills/land" "${CODEX_HOME:-$HOME/.codex}/skills/land"; do
      case "$d" in
        "$HOME/.claude/skills/land") ;;
        *) [ -d "$(dirname "$(dirname "$d")")" ] || continue ;;   # codex only if ~/.codex exists
      esac
      mkdir -p "$d" && cp "$tmp/x/SKILL.md" "$d/SKILL.md" && say "skill installed: $d/SKILL.md"
    done
  else
    say "the release has no skill file; agents can still run \`land merge --help\`"
  fi
fi

[ "${LAND_NO_LOGIN:-}" = 1 ] && exit 0

# A person at a terminal signs in now. `curl | sh` has stdin on the pipe, so read from /dev/tty, and require
# stdout to be a terminal too: an agent's captured shell fails one of these and never blocks.
if [ -t 1 ] && [ -r /dev/tty ] && ( : < /dev/tty ) 2>/dev/null; then
  say "signing in"
  "$LAND" login < /dev/tty
else
  say "no terminal; starting sign-in without waiting. Show the url to the person:"
  "$LAND" login --no-wait || say "run \`$LAND login --no-wait\` yourself (prints {\"url\",\"code\"})"
fi
