#!/usr/bin/env bash
# Keep the generated artefacts in step with the tags in the tree.
#
# Two of them now, from the same scanner: the requirements matrix and the
# gesture vocabulary. Both are generated *from* the tree and cite line numbers
# in it, so both go stale on any commit that moves a line — a `cargo fmt` sweep
# above all, but equally a commit that merely adds a paragraph above a tag.
#
# The gate regenerates the matrix in CI and fails if the result differs from
# what is committed. That is the right check — a matrix that disagrees with the
# tree is worse than none, because it is read as current — but it fails *after*
# a push, on a commit that is otherwise fine, and it has now done so on six
# commits in a row because adding a `TRACES:` tag and regenerating the matrix
# are two actions and only the first is on anyone's mind.
#
# So it happens here instead, where the tags are being changed.
#
# Only when something that can carry a tag is staged: a commit touching
# workflows, packaging or the matrix itself pays nothing.
set -euo pipefail

staged="$(git diff --cached --name-only --diff-filter=ACMR)"
if ! grep -qE '\.(rs|slint|yaml|md)$' <<< "${staged}"; then
    exit 0
fi
# The artefacts are generated from the tree, so regenerating them because one
# was itself edited would be circular.
case "$(tr -d '[:space:]' <<< "${staged}")" in
    docs/dev/traceability.md | docs/gestures.md | ui/dr-ui/src/gesture_book.rs | docs/manual/index.html)
        exit 0
        ;;
esac

repo="$(git rev-parse --show-toplevel)"
cd "${repo}"

# Quiet unless it has something to say. A hook that prints on every commit is
# a hook people start passing --no-verify to.
if ! cargo run -q -p traceability -- report >/dev/null 2>&1; then
    echo "pre-commit: could not run the traceability report; leaving the matrix alone" >&2
    exit 0
fi

if ! git diff --quiet -- docs/dev/traceability.md; then
    git add docs/dev/traceability.md
    echo "pre-commit: regenerated docs/dev/traceability.md and staged it"
fi

# The gesture vocabulary, same discipline.
#
# **Failure here is reported and not swallowed**, unlike the matrix above. A
# matrix that will not build leaves the previous one in place, which is merely
# stale; a malformed `GESTURE:` block means a gesture the user is about to be
# told about in the wrong words, or not at all. The gate would catch it in CI
# either way — this is only about catching it a push earlier.
if ! out="$(cargo run -q -p traceability -- gestures 2>&1)"; then
    echo "pre-commit: the gesture scan failed — the tags below need fixing" >&2
    echo "${out}" >&2
    exit 1
fi

for f in docs/gestures.md ui/dr-ui/src/gesture_book.rs; do
    if ! git diff --quiet -- "${f}"; then
        git add "${f}"
        echo "pre-commit: regenerated ${f} and staged it"
    fi
done

# The manual's page, when its source is part of the commit. Rendered from
# nothing but the README, so there is no reason to pay for it otherwise.
if grep -qx 'docs/manual/README.md' <<< "${staged}"; then
    if ! out="$(cargo run -q -p traceability -- manual 2>&1)"; then
        echo "pre-commit: the manual would not render" >&2
        echo "${out}" >&2
        exit 1
    fi
    if ! git diff --quiet -- docs/manual/index.html; then
        git add docs/manual/index.html
        echo "pre-commit: regenerated docs/manual/index.html and staged it"
    fi
fi
