#!/usr/bin/env sh
remote="$1"
zero=$(git hash-object --stdin </dev/null | tr '0-9a-f' '0')

# Each half runs only when a commit being pushed touches what it checks.
# The TypeScript checks also cover the `.ts`, `README.md` and `package.json`
# files under pnpm/ and pnpr/ (spellcheck, eslint, meta-updater).
rust_changed=
ts_changed=
while read -r local_ref local_oid remote_ref remote_oid; do
  [ "$local_oid" = "$zero" ] && continue # branch deletion, nothing to check

  if [ "$remote_oid" = "$zero" ]; then
    # New branch on the remote: inspect every commit not already pushed anywhere.
    range="$local_oid --not --remotes=$remote"
  else
    range="$remote_oid..$local_oid"
  fi

  files=$(git -c core.quotePath=false log --no-renames --pretty=format: --name-only $range 2>/dev/null | sort -u)
  if printf '%s\n' "$files" | grep -q -E '^(pnpm|pnpr)/'; then
    rust_changed=1
  fi
  # An empty list (a lone merge commit, say) keeps the TypeScript checks on.
  if [ -z "$files" ] || printf '%s\n' "$files" | grep -v -E '^(pnpm|pnpr)/' | grep -q . ||
    printf '%s\n' "$files" | grep -q -E '\.([cm]?[jt]s|json)$|(^|/)README\.md$'; then
    ts_changed=1
  fi
done

ts_pid=
if [ -n "$ts_changed" ]; then
  # Runs alongside the Rust checks; its output is held back until they finish.
  ts_log=$(mktemp)
  (pnpm run compile-only && pnpm run lint --quiet) >"$ts_log" 2>&1 &
  ts_pid=$!
else
  echo "✓ Only Rust files changed — skipping TypeScript pre-push checks."
fi

rust_status=0
if [ -n "$rust_changed" ]; then
  pnpm run pre-push:rust || rust_status=$?
else
  echo "✓ No changes under pnpm/ or pnpr/ — skipping Rust pre-push checks."
fi

ts_status=0
if [ -n "$ts_pid" ]; then
  wait "$ts_pid" || ts_status=$?
  if [ "$ts_status" -ne 0 ]; then
    cat "$ts_log"
    echo "✗ TypeScript pre-push checks failed."
  fi
  rm -f "$ts_log"
fi

[ "$rust_status" -eq 0 ] && [ "$ts_status" -eq 0 ]
