#!/bin/sh
# homomorph installer  ·  https://homomorphic.sh
#
#   curl -fsSL https://homomorphic.sh | sh
#
# Installs the `homomorph` CLI for macOS and Linux (x86_64 / aarch64).
# Never uses sudo. Verifies SHA-256 (and minisign when available).
#
# Environment:
#   HOMOMORPH_VERSION      pin a version (default: latest)
#   HOMOMORPH_INSTALL_DIR  install directory (default: ~/.homomorph/bin)
#   HOMOMORPH_BASE_URL     platform base URL (default: https://homomorphic.sh)
#   HOMOMORPH_NO_MODIFY_PATH=1  do not touch shell rc files
#
# Flags:  --dry-run   print what would happen without downloading

set -eu

BASE_URL="${HOMOMORPH_BASE_URL:-https://homomorphic.sh}"
INSTALL_DIR="${HOMOMORPH_INSTALL_DIR:-$HOME/.homomorph/bin}"
VERSION="${HOMOMORPH_VERSION:-latest}"
DRY_RUN=0
MINISIGN_PUBKEY="RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3"

for arg in "$@"; do
  case "$arg" in
    --dry-run) DRY_RUN=1 ;;
    -h|--help) sed -n '2,17p' "$0"; exit 0 ;;
  esac
done

# ---- output -----------------------------------------------------------------

if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
  KLEIN="$(printf '\033[38;2;0;47;167m')"
  AZURE="$(printf '\033[38;2;59;139;255m')"
  GLACIER="$(printf '\033[38;2;143;216;255m')"
  MIST="$(printf '\033[38;2;111;134;184m')"
  MINT="$(printf '\033[38;2;126;226;184m')"
  CORAL="$(printf '\033[38;2;255;93;115m')"
  BOLD="$(printf '\033[1m')"
  RESET="$(printf '\033[0m')"
  KLEIN_BG="$(printf '\033[48;2;0;47;167m')"
else
  KLEIN=""; AZURE=""; GLACIER=""; MIST=""; MINT=""; CORAL=""; BOLD=""; RESET=""; KLEIN_BG=""
fi

say()  { printf '  %s◇%s %s\n' "$AZURE" "$RESET" "$1"; }
ok()   { printf '  %s◆%s %s\n' "$MINT" "$RESET" "$1"; }
warn() { printf '  %s◆%s %s\n' "$CORAL" "$RESET" "$1" >&2; }
die()  { warn "$1"; exit 1; }

banner() {
  printf '\n'
  printf '  %s▐%s%s%s homomorph %s%s▌%s  %sinstaller%s\n' "$KLEIN" "$KLEIN_BG" "$GLACIER" "$BOLD" "$RESET" "$KLEIN" "$RESET" "$MIST" "$RESET"
  printf '\n'
}

# ---- detection --------------------------------------------------------------

need() { command -v "$1" >/dev/null 2>&1 || die "required tool not found: $1"; }

detect_target() {
  os="$(uname -s)"
  arch="$(uname -m)"
  case "$os" in
    Darwin) os_id="apple-darwin" ;;
    Linux)  os_id="unknown-linux-musl" ;;
    *) die "unsupported OS: $os (homomorph supports macOS and Linux)" ;;
  esac
  case "$arch" in
    x86_64|amd64)  arch_id="x86_64" ;;
    arm64|aarch64) arch_id="aarch64" ;;
    *) die "unsupported architecture: $arch" ;;
  esac
  TARGET="${arch_id}-${os_id}"
}

fetch() {
  # fetch URL [output]
  if command -v curl >/dev/null 2>&1; then
    if [ -n "${2:-}" ]; then curl -fsSL --proto '=https' --tlsv1.2 -o "$2" "$1"; else curl -fsSL --proto '=https' --tlsv1.2 "$1"; fi
  elif command -v wget >/dev/null 2>&1; then
    if [ -n "${2:-}" ]; then wget -q --https-only -O "$2" "$1"; else wget -q --https-only -O - "$1"; fi
  else
    die "need curl or wget"
  fi
}

sha256() {
  if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | awk '{print $1}'
  elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | awk '{print $1}'
  else die "need sha256sum or shasum"; fi
}

json_field() {
  # json_field <json> <key>   (flat string values only)
  printf '%s' "$1" | tr -d '\n' | sed -n "s/.*\"$2\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -n1
}

asset_sha() {
  # asset_sha <manifest> <target>
  printf '%s' "$1" | tr -d '\n' | sed 's/},/}\n/g' | grep "\"target\"[[:space:]]*:[[:space:]]*\"$2\"" | sed -n 's/.*"sha256"[[:space:]]*:[[:space:]]*"\([0-9a-fA-F]*\)".*/\1/p' | head -n1
}

asset_url() {
  printf '%s' "$1" | tr -d '\n' | sed 's/},/}\n/g' | grep "\"target\"[[:space:]]*:[[:space:]]*\"$2\"" | sed -n 's/.*"url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1
}

# ---- main -------------------------------------------------------------------

banner
need uname; need mktemp; need tar
detect_target
say "target ${GLACIER}${TARGET}${RESET}"

if [ "$VERSION" = "latest" ]; then
  MANIFEST_URL="$BASE_URL/v1/releases/latest"
else
  MANIFEST_URL="$BASE_URL/v1/releases/${VERSION#v}"
fi
say "manifest ${MIST}${MANIFEST_URL}${RESET}"

if [ "$DRY_RUN" = 1 ]; then
  say "dry run: would install to ${GLACIER}${INSTALL_DIR}${RESET}"
  exit 0
fi

MANIFEST="$(fetch "$MANIFEST_URL")" || die "could not fetch release manifest"
RELEASE_VERSION="$(json_field "$MANIFEST" version)"
[ -n "$RELEASE_VERSION" ] || die "malformed manifest (no version)"
URL="$(asset_url "$MANIFEST" "$TARGET")"
SHA="$(asset_sha "$MANIFEST" "$TARGET")"
[ -n "$URL" ] || die "no build for $TARGET in v$RELEASE_VERSION"
case "$URL" in
  http*) ;;
  *) URL="$BASE_URL$URL" ;;
esac

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

say "downloading homomorph ${GLACIER}v${RELEASE_VERSION}${RESET}"
fetch "$URL" "$TMP/homomorph.tar.gz" || die "download failed"

if [ -n "$SHA" ]; then
  GOT="$(sha256 "$TMP/homomorph.tar.gz")"
  [ "$GOT" = "$SHA" ] || die "checksum mismatch (expected $SHA, got $GOT)"
  ok "sha256 verified"
else
  warn "manifest carries no checksum for $TARGET; continuing without verification"
fi

if command -v minisign >/dev/null 2>&1; then
  if fetch "$URL.minisig" "$TMP/homomorph.tar.gz.minisig" 2>/dev/null; then
    minisign -Vm "$TMP/homomorph.tar.gz" -P "$MINISIGN_PUBKEY" >/dev/null 2>&1 && ok "minisign signature verified" || die "minisign verification failed"
  fi
fi

mkdir -p "$INSTALL_DIR"
tar -xzf "$TMP/homomorph.tar.gz" -C "$TMP"
BIN="$(find "$TMP" -type f -name homomorph | head -n1)"
[ -n "$BIN" ] || die "archive did not contain a homomorph binary"
chmod +x "$BIN"
mv -f "$BIN" "$INSTALL_DIR/homomorph"
ok "installed ${GLACIER}${INSTALL_DIR}/homomorph${RESET}"

# Optional Soufflé-compiled sidecar (same manifest, target engine-$TARGET).
ENGINE_TARGET="engine-${TARGET}"
ENGINE_URL="$(asset_url "$MANIFEST" "$ENGINE_TARGET")"
ENGINE_SHA="$(asset_sha "$MANIFEST" "$ENGINE_TARGET")"
if [ -n "$ENGINE_URL" ]; then
  case "$ENGINE_URL" in
    http*) ;;
    *) ENGINE_URL="$BASE_URL$ENGINE_URL" ;;
  esac
  say "downloading datalog sidecar ${GLACIER}${ENGINE_TARGET}${RESET}"
  if fetch "$ENGINE_URL" "$TMP/engine.tar.gz"; then
    if [ -n "$ENGINE_SHA" ]; then
      GOT="$(sha256 "$TMP/engine.tar.gz")"
      [ "$GOT" = "$ENGINE_SHA" ] || warn "sidecar checksum mismatch; skipping"
    fi
    if [ -f "$TMP/engine.tar.gz" ]; then
      tar -xzf "$TMP/engine.tar.gz" -C "$TMP" || true
      EBIN="$(find "$TMP" -type f -name 'homomorph-engine*' | head -n1)"
      if [ -n "$EBIN" ]; then
        chmod +x "$EBIN"
        mv -f "$EBIN" "$INSTALL_DIR/homomorph-engine"
        ok "installed ${GLACIER}${INSTALL_DIR}/homomorph-engine${RESET}"
      fi
    fi
  else
    say "no datalog sidecar for this target (native engine remains the default)"
  fi
else
  say "datalog sidecar not in manifest; run ${GLACIER}homomorph doctor${RESET} / scripts/build-engine.sh to compile locally"
fi

# ---- PATH -------------------------------------------------------------------

case ":$PATH:" in
  *":$INSTALL_DIR:"*) ON_PATH=1 ;;
  *) ON_PATH=0 ;;
esac

if [ "$ON_PATH" = 0 ] && [ -z "${HOMOMORPH_NO_MODIFY_PATH:-}" ]; then
  LINE="export PATH=\"$INSTALL_DIR:\$PATH\""
  for rc in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.profile"; do
    if [ -f "$rc" ] && ! grep -Fq "$INSTALL_DIR" "$rc"; then
      printf '\n# homomorph\n%s\n' "$LINE" >> "$rc"
      say "added to PATH in ${MIST}${rc}${RESET}"
    fi
  done
  if [ -n "${FISH_VERSION:-}" ] || command -v fish >/dev/null 2>&1; then
    fishdir="$HOME/.config/fish/conf.d"
    if [ -d "$HOME/.config/fish" ]; then
      mkdir -p "$fishdir"
      printf 'fish_add_path -g %s\n' "$INSTALL_DIR" > "$fishdir/homomorph.fish"
    fi
  fi
fi

printf '\n'
if [ "$ON_PATH" = 1 ]; then
  "$INSTALL_DIR/homomorph" --version >/dev/null 2>&1 && ok "$("$INSTALL_DIR/homomorph" --version)"
  printf '\n  run  %s%shomomorph scan .%s  inside an fhEVM project\n\n' "$GLACIER" "$BOLD" "$RESET"
else
  ok "done"
  printf '\n  restart your shell, or run:\n\n      %sexport PATH="%s:$PATH"%s\n\n  then:  %s%shomomorph scan .%s\n\n' "$GLACIER" "$INSTALL_DIR" "$RESET" "$GLACIER" "$BOLD" "$RESET"
fi
