#!/usr/bin/env bash
# scripts/quality/clang-tidy.sh
#
# Run clang-tidy over every public header under code/include/.  We use
# `--use-color` and tee output to build-tidy/clang-tidy.log for later
# diffing.
#
# Local-only.  The check is exploratory until we agree on which warning
# classes are reasonable to enforce — CGAL header-only code triggers a
# lot of `modernize-*` / `readability-*` warnings that are upstream's
# choice, not ours.  See `.clang-tidy` for the curated subset.
#
# Usage:
#   bash scripts/quality/clang-tidy.sh                   # all headers
#   bash scripts/quality/clang-tidy.sh code/include/CGAL # subset
#
# Prerequisite: a compile_commands.json with the right include paths
# (cmake generates this automatically with CMAKE_EXPORT_COMPILE_COMMANDS=ON).
#
# Exit codes:
#   0  clang-tidy ran (output captured)
#   1  clang-tidy reported at least one error (post-policy filter)
#   2  prerequisite missing

set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT"

BUILD_DIR="build-tidy"
LOG="$BUILD_DIR/clang-tidy.log"

command -v clang-tidy >/dev/null 2>&1 || {
    echo "FAIL: clang-tidy not in PATH." >&2
    echo "       macOS: brew install llvm  && export PATH=\"\$(brew --prefix llvm)/bin:\$PATH\"" >&2
    echo "       Linux: sudo apt install clang-tidy" >&2
    exit 2
}

TARGET_DIR="${1:-code/include}"
[ -d "$TARGET_DIR" ] || { echo "FAIL: $TARGET_DIR is not a directory" >&2; exit 2; }

# Generate compile_commands.json (clang-tidy needs it for include paths).
# Enable WITH_CGAL_TESTS so the CGAL include directories are part of at
# least one compile entry — clang-tidy walks those when linting headers
# that don't appear in compile_commands.json directly.
cmake -S code -B "$BUILD_DIR" \
    -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
    -DWITH_CGAL_TESTS=ON \
    -DCMAKE_BUILD_TYPE=Release \
    -Wno-dev >/dev/null

# ── macOS workaround: brew-installed clang-tidy doesn't know where the
# Apple Command-Line-Tools SDK lives, so it can't find <cmath>, <complex>,
# <CGAL/...>, etc.  Pass `--extra-arg=-isysroot ...` to teach it.
EXTRA_ARGS=()
if [ "$(uname -s)" = "Darwin" ]; then
    SDK="$(xcrun --show-sdk-path 2>/dev/null || true)"
    if [ -n "$SDK" ]; then
        EXTRA_ARGS+=(--extra-arg=-isysroot --extra-arg="$SDK")
    fi
fi

mkdir -p "$BUILD_DIR"
: > "$LOG"

# Find every .h / .hpp under TARGET_DIR (skip deps + macOS dup files +
# viewer-only headers — those need `-DWITH_VIEWER=ON` plus a system
# GLFW/libigl that we don't drag into the lint build).
HEADERS=$(find "$TARGET_DIR" \
    \( -name "*.h" -o -name "*.hpp" \) \
    -type f \
    | grep -v "code/deps/" \
    | grep -v " 2\." \
    | grep -v "viewer_utils\.h$" \
    | grep -v "mesh_utils\.hpp$" \
    | sort)

echo "========================================"
echo "  clang-tidy run"
echo "  target:  $TARGET_DIR"
echo "  config:  .clang-tidy"
echo "  log:     $LOG"
echo "========================================"
echo

n=0
for h in $HEADERS; do
    n=$((n + 1))
    echo "── [$n] $h ─────────────────────────────────"
    # Use --quiet so we only see actual diagnostics, not "n warnings
    # generated" boilerplate.  Pipe through tee for the log file.
    clang-tidy --quiet \
        -p "$BUILD_DIR" \
        "${EXTRA_ARGS[@]}" \
        "$h" 2>&1 | tee -a "$LOG" || true
done

echo
echo "── Summary ──────────────────────────────────"
warn=$(grep -c "warning:" "$LOG" || true)
err=$(grep -c "error:"   "$LOG" || true)
echo "  files inspected: $n"
echo "  warnings:        $warn"
echo "  errors:          $err"
echo "  full log:        $LOG"

if [ "${err:-0}" -gt 0 ]; then
    exit 1
fi
exit 0
