#!/bin/sh
# Sinfo CLI (sf) installer — OSS / verifiable / hub-independent.
#
#   curl -fsSL https://sinfo.dev/install.sh | sh
#
# sinfo.dev が配る静的バイナリ (sf-<triple>.tar.gz) を取得し、 同梱の SHA256SUMS と
# sha256 を照合してから配置する。 商用 hub (sinfohub / api.sinfohub.com) には一切
# 依存しない — OSS の sf 入手はここで完結する。 CDN/ミラーが差し替えても hash 不一致で
# 検出して中断する (= `curl|sh` の "怖い" を hash 照合で消す)。 信用するのは TLS で
# 取った小さな SHA256SUMS だけで、 バイナリ本体はどこから落ちても検証で守れる。
#
# まず中身を読んでから実行したい場合:
#   curl -fsSL https://sinfo.dev/install.sh -o install.sh && less install.sh && sh install.sh
#
# 上書き可能な環境変数:
#   SINFO_DIST         配布 base URL    (default: https://sinfo.dev/dist)
#   SINFO_VERSION      vX.Y.Z / latest  (default: latest = $SINFO_DIST/stable の中身)
#   SINFO_BIN          binary name      (default: sf)
#   SINFO_INSTALL_DIR  install dir      (default: $HOME/.local/bin)
#
# binary は ~/.local/bin (= user-bin の慣習)。 Sinfo のデータ (登録 project / vup 履歴)
# は ~/.sinfo/db に分離されており、 binary とは別物。 uninstall は binary を消すだけ
# (`rm ~/.local/bin/sf`)。 `rm -rf ~/.sinfo` はデータごと消えるのでやらないこと。
set -eu

DIST="${SINFO_DIST:-https://sinfo.dev/dist}"
VERSION="${SINFO_VERSION:-latest}"
BIN="${SINFO_BIN:-sf}"
INSTALL_DIR="${SINFO_INSTALL_DIR:-$HOME/.local/bin}"
DIST="${DIST%/}"

err()  { printf 'Error: %s\n' "$1" >&2; exit 1; }
have() { command -v "$1" >/dev/null 2>&1; }

# ── 必須ツール ─────────────────────────────────────────────
have curl || err "curl が必要です"
have tar  || err "tar が必要です"
if   have sha256sum; then SHA="sha256sum"
elif have shasum;    then SHA="shasum -a 256"
else err "sha256sum も shasum も無し (整合性検証に必須)"; fi

# ── OS/Arch → Rust target triple ──────────────────────────
arch="$(uname -m)"; os="$(uname -s)"
case "$arch" in
  arm64|aarch64) ARCH="aarch64" ;;
  x86_64|amd64)  ARCH="x86_64"  ;;
  *) err "未対応の arch: $arch" ;;
esac
case "$os" in
  Darwin) OS="apple-darwin"      ;;
  Linux)  OS="unknown-linux-gnu" ;;
  *) err "未対応の OS: $os (現状 macOS / Linux のみ)" ;;
esac
TRIPLE="${ARCH}-${OS}"
ASSET="${BIN}-${TRIPLE}.tar.gz"

# ── version 解決 (latest = $DIST/stable の中身 = "vX.Y.Z") ──
if [ "$VERSION" = "latest" ]; then
  VERSION="$(curl -fsSL "$DIST/stable" 2>/dev/null | tr -d ' \t\r\n')" \
    || err "最新版の解決に失敗: $DIST/stable"
  [ -n "$VERSION" ] || err "$DIST/stable が空です"
fi
BASE="$DIST/$VERSION"

printf 'Sinfo installer\n  target : %s\n  version: %s\n  source : %s\n  dest   : %s/%s\n' \
  "$TRIPLE" "$VERSION" "$BASE" "$INSTALL_DIR" "$BIN"

# ── SHA256SUMS から期待 hash を取得 (TLS で取る小さな信頼の起点) ──
sums="$(curl -fsSL "$BASE/SHA256SUMS" 2>/dev/null)" \
  || err "SHA256SUMS の取得に失敗 ($BASE/SHA256SUMS)"
# 標準 sha256sum 形式: "<hash>  <filename>"。 該当 asset 行の hash を抜く。
WANT="$(printf '%s\n' "$sums" | grep " ${ASSET}\$" | awk '{print $1}' | head -1)"
[ -n "$WANT" ] || err "この platform ($TRIPLE) 向け '$ASSET' が $VERSION にありません"

# ── download → sha256 照合 → 展開 → 配置 ──────────────────
tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' EXIT
printf 'Downloading %s ...\n' "$ASSET"
curl -fsSL "$BASE/$ASSET" -o "$tmp/$ASSET" || err "download に失敗 ($BASE/$ASSET)"

GOT="$($SHA "$tmp/$ASSET" | awk '{print $1}')"
if [ "$GOT" != "$WANT" ]; then
  printf 'Error: 整合性検証に失敗 (sha256 不一致)\n  expected: %s\n  got:      %s\n配布物が改竄/破損している可能性があります。 中断しました。\n' \
    "$WANT" "$GOT" >&2
  exit 1
fi
printf '  ok sha256 verified (%s)\n' "$GOT"

tar -xzf "$tmp/$ASSET" -C "$tmp" || err "展開に失敗"
src="$tmp/$BIN"
[ -f "$src" ] || src="$(find "$tmp" -type f -name "$BIN" 2>/dev/null | head -1)"
[ -n "${src:-}" ] && [ -f "$src" ] || err "展開物に '$BIN' が見つかりません"

mkdir -p "$INSTALL_DIR"
cp "$src" "$INSTALL_DIR/$BIN" && chmod 0755 "$INSTALL_DIR/$BIN"
# sf は歴史的に `sinfo` alias も張る。 他 bin (sfh 等) では張らない
# — さもないと `SINFO_BIN=sfh` install が sf の sinfo alias を上書きしてしまう。
[ "$BIN" = "sf" ] && ln -sf "$INSTALL_DIR/$BIN" "$INSTALL_DIR/sinfo" 2>/dev/null || true

# 旧 install (~/.sinfo/bin, data dir 同居) からの移行: 古い binary を掃除して PATH 二重を防ぐ。
# データ (~/.sinfo/db) は触らない。
OLD_DIR="$HOME/.sinfo/bin"
if [ "$INSTALL_DIR" != "$OLD_DIR" ] && [ -e "$OLD_DIR/$BIN" ]; then
  rm -f "$OLD_DIR/$BIN" 2>/dev/null || true
  [ "$BIN" = "sf" ] && rm -f "$OLD_DIR/sinfo" 2>/dev/null || true
  rmdir "$OLD_DIR" 2>/dev/null || true
  printf '  旧 install を掃除: %s (データ %s は保持)\n' "$OLD_DIR" "$HOME/.sinfo/db"
fi

printf '\nInstalled: %s/%s (%s)\n' "$INSTALL_DIR" "$BIN" "$VERSION"
case ":$PATH:" in
  *":$INSTALL_DIR:"*) "$INSTALL_DIR/$BIN" --version 2>/dev/null || true ;;
  *) printf '\nPATH に追加してください:\n  export PATH="%s:$PATH"\n(~/.zshrc 等に追記して再ログイン)\n' "$INSTALL_DIR" ;;
esac
