#!/bin/bash
#
# Framework-repo pre-commit hook.
#
# Mirrors what scaffolded webjs apps get via webjs create, adapted
# for the framework's own toolchain. Two gates:
#   1. Block direct commits to main/master. Use a feature branch.
#   2. Auto-generate matching changelog/<pkg>/<version>.md files
#      when a packages/<pkg>/package.json version bumped in the
#      staged diff.
#
# The test suite is NOT run here. CI (.github/workflows/ci.yml) is the
# test gate: it runs Conventions (webjs check), unit + integration,
# browser, e2e, and the dist build on every push and PR, and branch
# protection blocks a merge until all five pass. Running the full
# ~800-test suite on every local commit was redundant with that gate
# and made commit-per-logical-unit slow, so it was removed; commits
# stay fast and the gate lives in CI where it cannot be bypassed.
#
# Exception: the release workflow's `github-actions[bot]` commits
# the lockstep wrapper bumps directly to main (.github/workflows/
# release.yml step "Lockstep-bump wrappers"). That's intentional
# automation, not a human bypass, so we detect $GITHUB_ACTIONS=true
# and skip the entire hook for the bot. The bot's commit is a
# mechanical version-field write; there's nothing to validate.
# Human commits still hit every gate as designed.
#
# To bypass in emergencies (humans only): git commit --no-verify

if [ "$GITHUB_ACTIONS" = "true" ]; then
  echo "[pre-commit] github-actions runner detected; skipping all gates."
  exit 0
fi

BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null)

if [ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ]; then
  echo ""
  echo "ERROR: Cannot commit directly to '$BRANCH'."
  echo ""
  echo "Create a feature branch first:"
  echo "  git checkout -b feature/<name>"
  echo ""
  echo "To bypass (emergencies only): git commit --no-verify"
  echo ""
  exit 1
fi

# Gate 2: when a packages/<pkg>/package.json version bumped, auto-
# generate the matching changelog/<pkg>/<version>.md and stage it so
# the version-bump commit ships with its release notes in one shot.
# Bumps are detected by scanning the staged diff for a `+ "version":`
# line in any packages/*/package.json.
STAGED_PKG_BUMPS=$(git diff --cached --unified=0 -- \
    'packages/*/package.json' 'packages/editors/*/package.json' 'packages/wrappers/*/package.json' 2>/dev/null \
  | awk '
      # pkg = the directory immediately containing package.json, at any depth
      # (so a grouped package like packages/editors/intellisense maps to "intellisense").
      /^diff --git/ { match($0, /[A-Za-z0-9_-]+\/package\.json/); pkg = substr($0, RSTART, RLENGTH-13); next }
      pkg && /^\+\s*"version":\s*"[^"]+"/ {
        match($0, /"[0-9]+\.[0-9]+\.[0-9]+[^"]*"/); v = substr($0, RSTART+1, RLENGTH-2);
        print pkg "@" v
      }')

if [ -n "$STAGED_PKG_BUMPS" ]; then
  # Find which files need to exist and which are missing BEFORE we
  # run the generator, so we can stage exactly what the generator
  # produces (and fail loudly if it didn't produce them).
  #
  # The wrapper packages (create-webjs, webjsdev) are version-lockstep
  # mirrors of @webjsdev/cli and are explicitly NOT tracked in the
  # changelog system. Skip them: their bumps don't require a changelog
  # file, and scripts/backfill-changelog.js wouldn't produce one for
  # them anyway (they're not in its PACKAGES list).
  #
  # The editor packages (vscode, nvim) ARE tracked now (#413). They ship
  # via vsce/ovsx and the nvim git subtree rather than npm, but their
  # changelog entries carry `npm: false` so the publish-* scripts skip
  # the registry. So a vscode/nvim version bump DOES require a changelog
  # file, exactly like an npm package; backfill generates it.
  TO_GENERATE=""
  for bump in $STAGED_PKG_BUMPS; do
    pkg="${bump%@*}"; ver="${bump#*@}"
    if [ "$pkg" = "create-webjs" ] || [ "$pkg" = "webjsdev" ]; then
      continue
    fi
    if [ ! -f "changelog/$pkg/$ver.md" ]; then
      TO_GENERATE="$TO_GENERATE changelog/$pkg/$ver.md"
    fi
  done

  if [ -n "$TO_GENERATE" ]; then
    echo ""
    echo "Detected staged version bump(s) without a matching changelog file."
    echo "Running scripts/backfill-changelog.js to auto-generate:"
    for f in $TO_GENERATE; do echo "  + $f"; done
    echo ""
    if ! node scripts/backfill-changelog.js; then
      echo ""
      echo "ERROR: scripts/backfill-changelog.js failed. Fix the script error, or bypass with git commit --no-verify."
      echo ""
      exit 1
    fi

    # Stage the newly-generated files and verify each one now exists.
    STILL_MISSING=""
    for f in $TO_GENERATE; do
      if [ -f "$f" ]; then
        git add -- "$f"
      else
        STILL_MISSING="$STILL_MISSING\n  - $f"
      fi
    done
    if [ -n "$STILL_MISSING" ]; then
      echo ""
      echo "ERROR: the generator ran but did not produce the expected files:"
      echo -e "$STILL_MISSING"
      echo ""
      echo "This usually means the package's commit range contained zero"
      echo "feat / fix / breaking / perf commits, so the version bump has"
      echo "no user-facing changes to record. Either add an entry by hand,"
      echo "or bypass with: git commit --no-verify"
      echo ""
      exit 1
    fi
    echo "Staged the new changelog file(s); the commit will include them."
    echo ""
  fi
fi

exit 0
