#!/bin/sh
# CLEO_MANAGED_HOOK v1
# T1588 — project-agnostic T-ID enforcement for every commit being pushed.
#
# git invokes this with `<remote> <url>` as args and feeds ref updates on
# stdin: `<local-ref> <local-sha> <remote-ref> <remote-sha>` (one per line).
#
# For each new commit being pushed (commits in `local-sha` that are NOT
# already in any remote ref), require a T-ID in the subject. Same allow-
# list as commit-msg: merge / revert / fixup / squash / amend.
#
# Override: `git push --no-verify` (standard git override).
#
# T1595:reconcile-extension-point
# Pre-push reconcile gate hooks here (see T1595 worker).
# Reserved range below — DO NOT remove these markers; T1595 extends here.
# T1595:reconcile-extension-point-end
#
# POSIX `/bin/sh` only. No node/pnpm dependency.
set -e

ZERO_SHA="0000000000000000000000000000000000000000"
EMPTY_TREE_SHA=""
FAIL=0
FAIL_LOG=""

check_subject() {
  subject="$1"
  case "$subject" in
    'Merge '*) return 0 ;;
    'Revert '*) return 0 ;;
    'fixup! '*) return 0 ;;
    'squash! '*) return 0 ;;
    'amend! '*) return 0 ;;
  esac
  if printf '%s' "$subject" | grep -Eq 'T[0-9]+'; then
    return 0
  fi
  return 1
}

# Read each ref-update line from stdin.
while read -r local_ref local_sha remote_ref remote_sha; do
  # Branch deletion (push :branch) — nothing to validate.
  if [ "$local_sha" = "$ZERO_SHA" ]; then
    continue
  fi

  # Scan range: commits reachable from local_sha that are NOT reachable
  # from any remote ref. This is rebase-safe — after `git rebase origin/main`
  # the new base commits (which include release-ship / chore(changelog) /
  # ci: nudge commits that legitimately lack T-IDs) are already on
  # `origin/main` and therefore excluded from the scan. The naive
  # `$remote_sha..$local_sha` form would include those rebased-on commits
  # because the OLD remote_sha is no longer an ancestor of the new
  # local_sha after a rebase. Using `--not --remotes` for BOTH new and
  # existing branches gives consistent, project-agnostic behaviour.
  #
  # T10488 (Saga T9862 Wave 5) — narrow scan to truly-local commits.
  range="$local_sha --not --remotes"

  # Subject extraction: %s = subject. NUL-delimit for safety.
  # shellcheck disable=SC2086
  commits=$(git rev-list $range 2>/dev/null || true)
  for sha in $commits; do
    subject=$(git log -1 --pretty=%s "$sha" 2>/dev/null || true)
    if [ -z "$subject" ]; then
      continue
    fi
    if ! check_subject "$subject"; then
      FAIL=1
      FAIL_LOG="${FAIL_LOG}  ${sha}  ${subject}
"
    fi
  done
done

if [ "$FAIL" -ne 0 ]; then
  cat >&2 <<EOF
cleo pre-push hook: refusing push — commits are missing task IDs.

${FAIL_LOG}
Every commit MUST reference at least one CLEO task (e.g. \`T1588\`).
Fix the subjects (\`git rebase -i\` + reword), or override with:

  git push --no-verify

EOF
  exit 1
fi

exit 0
