#!/usr/bin/env bash
set -euo pipefail

# Generated by fallow setup-hooks.
# Installer version: @@FALLOW_INSTALLER_VERSION@@
# Requires bash and jq. On Windows run via git-bash or WSL.
# Blocks Claude Code git commit and git push when fallow audit returns verdict fail.
# Runtime errors fail open with a single stderr notice so skips stay visible.
#
# Version floor (FALLOW_GATE_MIN_VERSION, default 2.46.0). Older binaries miss
# the uncommitted-changes inclusion fix (aabb8e1b) and can silently pass
# audits that should fail. Set the env var to the empty string to disable.
# Floor comparison uses `sort -V`; GNU and BSD agree on plain semver but
# diverge on prereleases (BSD sorts `2.48.0-alpha.1` ABOVE `2.48.0`, GNU below).
# If you set a prerelease floor explicitly, verify the behavior on the target OS.

if ! command -v jq >/dev/null 2>&1; then
  echo "fallow-gate: jq not on PATH, skipping audit." >&2
  exit 0
fi

INPUT="$(cat)"
CMD="$(jq -r '.tool_input.command // empty' <<<"$INPUT")"

if ! printf '%s\n' "$CMD" | grep -Eq '(^|[[:space:];|&()])git[[:space:]]+(commit|push)([[:space:]]|$)'; then
  exit 0
fi

if command -v fallow >/dev/null 2>&1; then
  RUNNER=(fallow)
  BIN_DESC="$(command -v fallow)"
elif command -v npx >/dev/null 2>&1 && VER_PROBE="$(npx --no-install fallow --version 2>/dev/null || true)" && [[ "$VER_PROBE" == fallow* ]]; then
  RUNNER=(npx --no-install fallow)
  BIN_DESC="npx --no-install fallow"
else
  echo "fallow-gate: fallow binary not found (tried PATH and npx --no-install), skipping audit." >&2
  exit 0
fi

VERSION_RAW="$("${RUNNER[@]}" --version 2>/dev/null || true)"
VERSION="${VERSION_RAW#fallow }"
VERSION="${VERSION%% *}"

MIN_VERSION="${FALLOW_GATE_MIN_VERSION-2.46.0}"
if [ -n "$MIN_VERSION" ] && [ -n "$VERSION" ]; then
  LOWER="$(printf '%s\n%s\n' "$MIN_VERSION" "$VERSION" | sort -V | head -n1)"
  if [ "$LOWER" != "$MIN_VERSION" ]; then
    {
      echo "fallow-gate: blocked: $BIN_DESC is fallow $VERSION, below required $MIN_VERSION."
      echo "fallow-gate: older binaries miss the uncommitted-changes fix (v2.46.0) and can"
      echo "fallow-gate: silently pass audits that would otherwise fail."
      echo "fallow-gate: upgrade the fallow on PATH (e.g. npm install -g fallow@latest or"
      echo "fallow-gate: cargo install fallow-cli), or set FALLOW_GATE_MIN_VERSION= to disable."
    } >&2
    exit 2
  fi
fi

TMP_JSON="$(mktemp)"
TMP_ERR="$(mktemp)"
cleanup() {
  rm -f "$TMP_JSON" "$TMP_ERR"
}
trap cleanup EXIT

if "${RUNNER[@]}" audit --format json --quiet --explain >"$TMP_JSON" 2>"$TMP_ERR"; then
  STATUS=0
else
  STATUS=$?
fi

VERDICT="$(jq -r '.verdict // empty' <"$TMP_JSON" 2>/dev/null || true)"
IS_ERROR="$(jq -r '.error // false' <"$TMP_JSON" 2>/dev/null || echo false)"

if [ "$VERDICT" = "fail" ]; then
  echo "fallow-gate: blocked by fallow ${VERSION:-unknown} at $BIN_DESC" >&2
  cat "$TMP_JSON" >&2
  exit 2
fi

if [ "$STATUS" -eq 2 ] || [ "$IS_ERROR" = "true" ]; then
  MSG="$(jq -r '.message // empty' <"$TMP_JSON" 2>/dev/null || true)"
  if [ -n "$MSG" ]; then
    echo "fallow-gate: fallow audit runtime error ($MSG), skipping." >&2
  else
    echo "fallow-gate: fallow audit runtime error, skipping." >&2
  fi
  exit 0
fi

if [ "$STATUS" -ne 0 ]; then
  ERR_LINE="$(sed -n '1p' "$TMP_ERR" 2>/dev/null || true)"
  if [ -n "$ERR_LINE" ]; then
    echo "fallow-gate: fallow audit exited $STATUS ($ERR_LINE), skipping." >&2
  else
    echo "fallow-gate: fallow audit exited $STATUS, skipping." >&2
  fi
  exit 0
fi

exit 0
