#!/bin/sh
# Installed by `vibey-gh install` — do not edit; edit the template in vibey-gh.
#
# THE GATE. A repository that has adopted the vibey GitHub automation must keep it
# installed and working. If the tooling is missing, or the fingerprints it enforces are
# not intact, the push is refused — to any branch, local or remote.
#
# The point is not ceremony. Provenance that can be skipped whenever it is inconvenient
# is provenance nobody can rely on, so the check has to sit on the last action before
# code leaves the machine.
#
# Escape hatch: `git push --no-verify` still works, because a hook that cannot be
# bypassed in an emergency gets uninstalled instead. CI applies the same rule server-side,
# so skipping here only defers the failure rather than avoiding it.

set -e

red() { printf '\033[0;31m%s\033[0m\n' "$1"; }


# Resolve the CLI. `vibey-gh` on PATH is the normal case, but a project virtualenv that
# has not been activated is just as normal — and a gate that reports "not installed"
# when the tool IS installed is a gate people learn to bypass. Look where it actually
# lives before giving up. Hooks run from the top of the working tree.
# Where this repository's own copy of vibey-gh lives, printed as a directory — or
# nothing, which is the ordinary case for a repository that merely adopted it.
#
# What is looked for is the pyproject that DECLARES the distribution, not a fixed path.
# It sits at the top of the tree in the standalone repository and under `src/` in the
# monorepo that absorbed it, and hard-coding either one breaks the other. `git ls-files`
# keeps the search bounded to tracked files, so a vendored copy under `.venv/` or
# `site/` can never match, and it is available here by definition: hooks run inside a
# git repository, from the top of the working tree.
vibey_gh_self() {
  # Read from `[install] self_source` in .vibey-gh.toml at runtime rather than rendered
  # in: `install.installed()` compares these hooks byte-for-byte against the template, so
  # a substituted hook would be permanently "out of date" and refuse every push.
  #
  # A DECLARED path, never a search. Searching the tree for a pyproject that declares
  # `name = "vibey-gh"` reads whatever is in the working tree, which on a contributor's
  # branch is whatever they put there -- and this hook executes what it finds.
  dir=$(sed -n 's/^[[:space:]]*self_source[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' \
    .vibey-gh.toml 2>/dev/null | head -n 1)
  [ -n "$dir" ] || dir=.
  case "$dir" in /*|*..*) return 0 ;; esac
  grep -qE '^name = "vibey-gh"' "$dir/pyproject.toml" 2>/dev/null || return 0
  [ -d "$dir/vibey_gh" ] || return 0
  printf '%s' "$dir"
}


vibey_gh() {
  # A repository that CARRIES vibey-gh must run that source, never an installed copy.
  # Its `develop` is ahead of the last release nearly always, so a globally installed
  # vibey-gh compares the repository's managed assets against the older ones it bundles,
  # reports them out of date, and refuses every push — a contributor who installed the
  # tool the obvious way cannot commit to it. The package is dependency-free stdlib, so
  # `python3 -m` against the checkout needs no install and no virtualenv at all.
  if [ -z "${_VIBEY_GH_SELF+x}" ]; then
    _VIBEY_GH_SELF=$(vibey_gh_self)
  fi
  # Every `python3` below runs with PYTHONSAFEPATH=1. Without it, `-c` and `-m` put the
  # current directory -- the top of the working tree -- first on sys.path, so a checked-out
  # branch carrying a `vibey_gh/` package of its own would be imported and executed by
  # this hook in place of the real one. The self-hosted branch still runs its source: it
  # names that source on PYTHONPATH, which PYTHONSAFEPATH leaves alone. Python 3.11+
  # honours the variable and older interpreters ignore it; vibey-gh requires 3.11.
  if [ -n "$_VIBEY_GH_SELF" ] && PYTHONSAFEPATH=1 \
      PYTHONPATH="$_VIBEY_GH_SELF${PYTHONPATH:+:$PYTHONPATH}" \
      python3 -c "import vibey_gh.cli" >/dev/null 2>&1; then
    PYTHONSAFEPATH=1 PYTHONPATH="$_VIBEY_GH_SELF${PYTHONPATH:+:$PYTHONPATH}" \
      python3 -m vibey_gh.cli "$@"
  elif command -v vibey-gh >/dev/null 2>&1; then
    vibey-gh "$@"
  elif [ -n "${VIRTUAL_ENV:-}" ] && [ -x "${VIRTUAL_ENV}/bin/vibey-gh" ]; then
    "${VIRTUAL_ENV}/bin/vibey-gh" "$@"
  elif [ -x ".venv/bin/vibey-gh" ]; then
    ./.venv/bin/vibey-gh "$@"
  elif [ -x "venv/bin/vibey-gh" ]; then
    ./venv/bin/vibey-gh "$@"
  elif PYTHONSAFEPATH=1 python3 -c "import vibey_gh.cli" >/dev/null 2>&1; then
    PYTHONSAFEPATH=1 python3 -m vibey_gh.cli "$@"
  elif PYTHONSAFEPATH=1 python3 -c "import vibey_bootstrap.gh.cli" >/dev/null 2>&1; then
    PYTHONSAFEPATH=1 python3 -m vibey_bootstrap.gh.cli "$@"   # pre-split layout
  else
    return 127
  fi
}

if ! vibey_gh trailer-key >/dev/null 2>&1; then
  red "✖ push refused: the vibey GitHub automation is not installed."
  echo
  echo "  This repository requires it for provenance and release automation."
  echo
  echo "      pip install vibey"
  echo "      vibey-gh install"
  echo
  echo "  Then push again. To bypass once: git push --no-verify"
  exit 1
fi

if ! vibey_gh check --quiet; then
  red "✖ push refused: the provenance fingerprints are not intact."
  echo
  echo "      vibey-gh check          # see what is missing"
  echo "      vibey-gh check --apply  # add the missing file headers"
  echo
  echo "  Commit trailers are added automatically by the commit-msg hook."
  echo "  To bypass once: git push --no-verify"
  exit 1
fi

# Chain to a pre-existing project hook, so adopting this does not discard local checks.
# Its refusal is this hook's refusal. `set -e` and being the last line already carry the
# status out; `|| exit $?` says so explicitly, so neither can be lost to a later edit.
if [ -x "$(dirname "$0")/pre-push.local" ]; then
  "$(dirname "$0")/pre-push.local" "$@" || exit $?
fi
