#!/usr/bin/env bash
# tooling/godot-cold-parse [--run-menu] — cold-cache headless parse check.
#
# Used by /pr-process step 1c before push. Deletes the cached script-class
# registry so the parse simulates the cold-start ordering CI / fresh clones
# see: Sprint 36 close caught a new `class_name MetaScreen` base class and
# six extending scripts that parsed fine on warm developer caches but hit
# `Could not find base class "MetaScreen"` post-merge, because the
# autoload-vs-class_name registration order only resolves correctly once the
# class cache is seeded (see CLAUDE.md -> GDScript conventions -> Autoload
# parse-order rule).
#
# Godot's resource scanner emits category errors (e.g. "Export type can only
# be built-in, a resource, a node, or an enum") that do NOT always prefix
# with SCRIPT ERROR — they appear as plain ERROR lines. The filter below
# catches both, then drops known pre-existing noise from the autoload
# class_name parse-order trap. Sprint 36 shipped a scanner error the old
# narrower grep missed; this is why the filter stays wide.
#
# --run-menu: also launch main_menu.tscn briefly (for branches with UI changes).
#
# Exit 0 + "clean" if no matches. Exit 1 + the matched lines if any are found.
set -euo pipefail

REPO_ROOT="$(git rev-parse --show-toplevel)"
RUN_MENU=false
[ "${1:-}" = "--run-menu" ] && RUN_MENU=true

rm -f "$REPO_ROOT/client/.godot/global_script_class_cache.cfg"

# A truly cold checkout (fresh clone or worktree — .godot/ is gitignored) has
# no resource-import cache, and every imported asset (fonts, ogg) then "fails
# loading" during the parse run: a wall of false positives. Seed the cache
# with an import pass first; source assets are tracked, so this is always
# reconstructible. (Found live: first run in a fresh worktree, 2026-07-13.)
if [ ! -d "$REPO_ROOT/client/.godot/imported" ] || [ -z "$(ls -A "$REPO_ROOT/client/.godot/imported" 2>/dev/null)" ]; then
    echo "godot-cold-parse: no import cache — running one-time import pass..." >&2
    set +e
    IMPORT_OUT=$(godot --headless --path "$REPO_ROOT/client" --import 2>&1)
    IMPORT_EXIT=$?
    set -e
    if [ "$IMPORT_EXIT" -ne 0 ]; then
        echo "godot-cold-parse: import pass exited $IMPORT_EXIT" >&2
        printf '%s\n' "$IMPORT_OUT" | tail -20 >&2
        exit "$IMPORT_EXIT"
    fi
fi

FILTER='^(SCRIPT )?ERROR|Parse Error|Export type'

# Capture the godot run separately from the filter pipeline: with the
# trailing `|| true` on the greps, a nonzero exit from godot itself (crash,
# missing binary, corrupted install) would otherwise report "clean". Nothing
# downstream re-reads the raw output now that this is scripted, so fail loud.
set +e
RAW=$(godot --headless --path "$REPO_ROOT/client" --quit 2>&1)
GODOT_EXIT=$?
set -e
if [ "$GODOT_EXIT" -ne 0 ]; then
    echo "godot-cold-parse: godot itself exited $GODOT_EXIT — not a parse verdict" >&2
    printf '%s\n' "$RAW" | tail -20 >&2
    exit "$GODOT_EXIT"
fi

MATCHES=$(printf '%s\n' "$RAW" \
  | grep -iE "$FILTER" \
  | grep -v "Failed loading resource: res://assets" \
  | grep -v "Cannot infer the type" \
  | grep -vE '(Messagepack|LocalBridge|ServerProcess|Constants)" not declared' || true)

if [ "$RUN_MENU" = true ]; then
    # Deliberately no exit-code check here: `timeout` kills the menu after
    # 10s by design (exit 124 is the expected shutdown path); only the
    # scraped error lines carry signal for this bounded run.
    MENU_MATCHES=$(timeout 10 godot --path "$REPO_ROOT/client" res://scenes/main_menu.tscn 2>&1 \
      | grep -iE "$FILTER" || true)
    if [ -n "$MENU_MATCHES" ]; then
        MATCHES="$MATCHES
$MENU_MATCHES"
    fi
fi

if [ -n "$MATCHES" ]; then
    echo "$MATCHES"
    exit 1
fi

# Restore a FULL class cache before exiting: the cold parse run re-seeds
# global_script_class_cache.cfg only partially — addon classes (e.g. gdUnit4's
# GdUnitTestCIRunner) are missing, which leaves tests/run-godot unable to even
# start (0 tests in ~350ms; found live when the pre-push gate ran the suite
# right after this script, 2026-07-14). The cold verdict above is already
# decided; this restore just returns the tree to a runnable state.
godot --headless --path "$REPO_ROOT/client" --import > /dev/null 2>&1 || true

echo "godot-cold-parse: clean"
