#!/bin/sh
# bin/lint — manual linting for raylib-jamstack (Ruby + C/C++).
#
# Runs RuboCop (Ruby), clang-format (C/C++ formatting), and clang-tidy
# (C/C++ static analysis) on the project's hand-written sources. NOT automatic
# — run it deliberately, at the end of an implementation pass.
#
# Usage:
#   bin/lint              # report only (exit 1 if any issues)
#   bin/lint --fix        # safe autocorrect: RuboCop -a + clang-format -i
#                         # (clang-tidy is NEVER auto-fixed — it only reports)
#   bin/lint --ruby       # Ruby only (RuboCop)
#   bin/lint --c          # C/C++ only (clang-format + clang-tidy)
#
# What this checks:
#   Ruby (.rb):   RuboCop — style/layout/lint (.rubocop.yml: DisabledByDefault,
#                 opt-in to Layout + Lint + safe Style; excludes Metrics/length
#                 cops; TargetRubyVersion 3.4 for mruby endless-method support)
#   C/C++:        clang-format — formatting consistency (.clang-format: Allman,
#                 2-space, 100-col, return-type-on-own-line)
#                 clang-tidy — bug-finding checks (bugprone-*, cert-*,
#                 clang-analyzer-*), scoped to hand-written files only
#
# What this does NOT check (handled elsewhere):
#   - Syntax errors: caught at build time by the mruby-compiler gem (rake fails)
#   - Type errors:   Steep per-edit (RBS type checker, see opencode.json)
#
# Excludes generated/vendored code:
#   - mrbgems/raylib/src/raylib_gen.c (generated by tools/gen_raylib.rb)
#   - vendor/** (vendored mruby/raylib/rmlui/flecs/joltc)
#   - build/**, zig-out/**, .cache/**, .live/** (build/runtime artifacts)
#
# See .agents/knowledge/linting.md for the full rationale.
set -eu

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"

# --- PATH setup (mirror rebuild.sh: strip /mnt/c, add gem bin dir) ---
CLEANPATH=$(echo "$PATH" | tr ':' '\n' | grep -v '^/mnt/c' | paste -sd:)
export PATH="/home/tradam/.local/share/gem/ruby/3.4.0/bin:$CLEANPATH"

CLANG_FORMAT="/usr/lib/llvm21/bin/clang-format"
CLANG_TIDY="/usr/lib/llvm21/bin/clang-tidy"

# Hand-written C/C++ sources (NOT raylib_gen.c which is generated, NOT vendor/).
C_SOURCES="src/main.c mrbgems/raylib/src/raylib_bindings.c mrbgems/flecs/src/flecs_bindings.c mrbgems/jolt/src/jolt_bindings.c mrbgems/rmlui/src/rml_bindings.cpp"

FIX=0
RUN_RUBY=1
RUN_C=1

for arg in "$@"; do
  case "$arg" in
    --fix)    FIX=1 ;;
    --ruby)   RUN_C=0 ;;
    --c)      RUN_RUBY=0 ;;
    -h|--help)
      sed -n '2,30p' "$0"
      exit 0
      ;;
    *)
      echo "unknown flag: $arg (try --help)" >&2
      exit 2
      ;;
  esac
done

EXIT_CODE=0

# ─── Ruby: RuboCop ───────────────────────────────────────────────────────────
if [ "$RUN_RUBY" = 1 ]; then
  echo "── RuboCop (Ruby) ──────────────────────────────────────────────────────"
  if [ "$FIX" = 1 ]; then
    echo "  running with safe autocorrect (-a)..."
    rubocop -a || EXIT_CODE=1
  else
    rubocop || EXIT_CODE=1
  fi
  echo ""
fi

# ─── C/C++: clang-format ─────────────────────────────────────────────────────
if [ "$RUN_C" = 1 ]; then
  echo "── clang-format (C/C++ formatting) ──────────────────────────────────────"
  if [ ! -x "$CLANG_FORMAT" ]; then
    echo "  SKIP: $CLANG_FORMAT not found (install llvm/clang-tools)" >&2
  elif [ "$FIX" = 1 ]; then
    echo "  rewriting in place (-i)..."
    "$CLANG_FORMAT" -i $C_SOURCES
    echo "  done (clang-format applied)"
  else
    echo "  dry-run (reporting violations)..."
    # --dry-run --Werror makes it exit non-zero if ANY file needs formatting.
    if ! "$CLANG_FORMAT" --dry-run --Werror $C_SOURCES 2>&1; then
      EXIT_CODE=1
      echo "  (run 'bin/lint --fix' to auto-format)"
    else
      echo "  all C/C++ files are clang-format clean"
    fi
  fi
  echo ""
fi

# ─── C/C++: clang-tidy (report only — NEVER auto-fix) ───────────────────────
if [ "$RUN_C" = 1 ]; then
  echo "── clang-tidy (C/C++ static analysis) ───────────────────────────────────"
  if [ ! -x "$CLANG_TIDY" ]; then
    echo "  SKIP: $CLANG_TIDY not found (install llvm/clang-tools)" >&2
  elif [ ! -f "compile_commands.json" ]; then
    echo "  SKIP: compile_commands.json not found (run ./rebuild.sh first)" >&2
  else
    echo "  running bug-finding checks (bugprone-*, cert-*, clang-analyzer-*)..."
    # --header-filter restricts diagnostics to OUR headers (not vendored).
    # compile_commands.json (-p .) provides the include roots + -DMRB_INT64.
    "$CLANG_TIDY" -p . \
      --checks='-*,bugprone-*,cert-*,clang-analyzer-*' \
      --header-filter='^mrbgems/.*/src/.*|^src/.*' \
      $C_SOURCES 2>&1 || true   # clang-tidy exits non-zero on warnings; that's OK
    echo "  done (clang-tidy reports only — no auto-fix)"
  fi
  echo ""
fi

# ─── Summary ─────────────────────────────────────────────────────────────────
if [ "$EXIT_CODE" = 0 ]; then
  echo "✓ lint clean"
else
  echo ""
  echo "✗ lint found issues (run 'bin/lint --fix' for safe autocorrects)"
fi
exit "$EXIT_CODE"
