#!/usr/bin/env bash
# Announce a push on the Switchboard board, so the other agent hears about it
# without anyone remembering to say so.
#
# Runs before the push completes. If the push then fails, the board has a line
# for a commit that is not on the remote, which is noisy but harmless and
# visible to whoever pushed. The alternative is no announcement at all, since
# git has no post-push hook.
#
# Configure per clone:
#   git config switchboard.url   https://your-board.up.railway.app
#   git config switchboard.token YOUR_TOKEN
# Never put the token in the repo. git config keeps it in .git/config, which
# is not tracked.

# Refuse a push that is behind the remote. Pushing over someone else's work
# is the other failure the board cannot prevent, and unlike the claim check
# this one git already knows the answer to. It just does not refuse by
# default when the push would be a fast-forward of a stale branch.
branch=$(git rev-parse --abbrev-ref HEAD)
upstream=$(git rev-parse --abbrev-ref "@{upstream}" 2>/dev/null || true)
# git hands the hook the remote being pushed to as $1. Fall back to the name
# in the upstream ref, then to origin.
remote="$1"
if [ -z "$remote" ]; then
  remote="${upstream%%/*}"
fi
[ -n "$remote" ] || remote=origin
if [ -n "$upstream" ]; then
  # The remote being pushed to, not a hardcoded "origin". A repo whose
  # remote is named anything else fetched nothing, counted against a
  # stale tracking ref, reported zero behind, and let a force-push bury
  # a collaborator's work with no warning printed.
  git fetch -q "$remote" "$branch" 2>/dev/null || true
  behind=$(git rev-list --count "HEAD..$upstream" 2>/dev/null || echo 0)
  if [ "${behind:-0}" -gt 0 ]; then
    echo "" >&2
    echo "switchboard: push refused. You are $behind commit(s) behind $upstream." >&2
    echo "Someone pushed while you were working. Pull first, so their work is not" >&2
    echo "buried under yours:" >&2
    echo "  git pull --rebase" >&2
    echo "" >&2
    exit 1
  fi
fi

URL=$(git config --get switchboard.url)
TOKEN=$(git config --get switchboard.token)
[ -n "$URL" ] && [ -n "$TOKEN" ] || exit 0   # not configured, stay silent

remote_ref_read=0
while read -r _local_ref local_sha remote_ref _remote_sha; do
  remote_ref_read=1
  # A delete pushes the null sha. Nothing to announce.
  [ "$local_sha" = "0000000000000000000000000000000000000000" ] && continue

  branch=${remote_ref#refs/heads/}
  subject=$(git log -1 --format=%s "$local_sha")
  files=$(git show --stat --format= --name-only "$local_sha" | grep -c . || true)

  body=$(python3 - "$local_sha" "$branch" "$subject" "$files" <<'PY'
import json, sys
sha, branch, subject, files = sys.argv[1:5]
print(json.dumps({"type": "signal", "body": {
    "name": "PUSHED", "sha": sha[:8], "branch": branch,
    "subject": subject, "files": int(files)}}))
PY
)
  curl -s -m 10 -X POST "$URL/api/post" \
    -H "Authorization: Bearer $TOKEN" \
    -H "User-Agent: switchboard-mcp/hook" \
    -H "Content-Type: application/json" \
    -d "$body" > /dev/null || true
done

exit 0
