#!/usr/bin/env bash
# Pre-push gate. Blocks the push if any quality check fails.
#
# Install: `make hooks` (points git core.hooksPath at .githooks/).
# Bypass: never. If this runs slowly, fix the slow test; don't reach
# for --no-verify (git-commit skill forbids it).
#
# Fast path (T-348): run the full ~2min test suite only when the push touches
# lib/ (app + runtime Dart source) or pubspec.* (deps / version). test/,
# assets/, docs, and tooling changes ride along with a lib change in practice,
# and an otherwise-skipped push is covered by the next one that does touch lib.
# The full suite is always available via `make push-check`, and the release CI
# runs it forced on a tagged version. So a lib/pubspec-free push runs just the
# instant decisions + changelog gates. A state we can't classify (unfetched
# remote, new branch) runs the full gate.
set -euo pipefail

cd "$(git rev-parse --show-toplevel)"

z40=0000000000000000000000000000000000000000

# Collect every file changed across the commits being pushed. git feeds the
# hook one line per ref on stdin: <local-ref> <local-sha> <remote-ref> <remote-sha>.
changed=""
force_full=0
while read -r _local_ref local_sha _remote_ref remote_sha; do
  [[ "$local_sha" == "$z40" ]] && continue # branch deletion — nothing to test
  if [[ "$remote_sha" == "$z40" ]]; then
    # New remote branch: diff from its merge-base with main, else play it safe.
    base="$(git merge-base "$local_sha" origin/main 2>/dev/null || true)"
  else
    base="$remote_sha"
  fi
  # If we can't resolve a base locally (e.g. the remote advanced and we haven't
  # fetched its objects), we can't classify the diff — run the full gate.
  if [[ -z "$base" ]] || ! git cat-file -e "$base^{commit}" 2>/dev/null; then
    force_full=1
    break
  fi
  changed+=$'\n'"$(git diff --name-only "$base" "$local_sha")"
done

# Run the full gate when lib/ (app + runtime source) or pubspec.* (deps /
# version) is touched, or when we couldn't classify above.
needs_gate=1
if [[ "$force_full" -eq 0 ]]; then
  trigger_files="$(printf '%s\n' "$changed" | grep -E '^(lib/|pubspec\.)' || true)"
  [[ -z "$trigger_files" ]] && needs_gate=0
fi

if [[ "$needs_gate" -eq 0 ]]; then
  echo "==> pre-push: no lib/ or pubspec change — decisions + changelog gates, skipping tests"
  make decisions-validate changelog-gate
else
  echo "==> pre-push: make push-check"
  make push-check
fi
