#!/usr/bin/env bash
# Pre-commit gate: make precommit (format BE+FE + lint + typecheck + testmon-scoped
# tests) + dashboard build. The full suite still runs in CI (`make all`); this is a
# fast, change-aware local gate so commits don't wait on the whole test matrix.
# Enable once per clone:  make install-hooks
# Bypass (emergency only): SKIP_PRECOMMIT=1 git commit ...
# Or: git commit --no-verify
set -euo pipefail

if [[ "${SKIP_PRECOMMIT:-}" == "1" ]]; then
  echo "[pre-commit] SKIP_PRECOMMIT=1 — skipping checks"
  exit 0
fi

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

# Documentation-only commits do not need code checks or a dashboard build.
# Include deletions and both sides of renames when deciding what changed.
DOCS_ONLY=1
HAS_CHANGES=0
while IFS= read -r -d '' path; do
  HAS_CHANGES=1
  case "$path" in
    README.md|README.*.md) ;;
    *) DOCS_ONLY=0 ;;
  esac
done < <(git diff --cached --name-only --no-renames -z)
if [[ "$HAS_CHANGES" == "1" && "$DOCS_ONLY" == "1" ]]; then
  echo "[pre-commit] Documentation-only changes — skipping code checks and dashboard build"
  exit 0
fi

# Remember staged paths so we can re-add them after auto-format rewrites the worktree.
# Portable (bash 3.2+): avoid `mapfile` (bash 4+ only).
STAGED_FILES=()
while IFS= read -r line; do
  [[ -n "$line" ]] && STAGED_FILES+=("$line")
done < <(git diff --cached --name-only --diff-filter=ACMR || true)

echo "[pre-commit] make precommit  (format-all + lint + typecheck + testmon-scoped test)"
make precommit

# If format rewrote files that were already staged, refresh the index so the
# commit includes the formatted content (worktree vs index drift).
if ((${#STAGED_FILES[@]} > 0)); then
  existing=()
  for f in "${STAGED_FILES[@]}"; do
    if [[ -e "$f" || -L "$f" ]]; then
      existing+=("$f")
    fi
  done
  if ((${#existing[@]} > 0)); then
    git add -- "${existing[@]}"
  fi
fi

echo "[pre-commit] dashboard npm run build"
(
  cd "$ROOT/dashboard"
  npm run build
)

echo "[pre-commit] all checks passed"
