"""Grep CritMatic Lua sources for symbol references.

Phase 1 scans `*.lua` at the repo root and under `Modules/`. Excludes `Libs/`,
`Localization/`, and `.release/`. Word-boundary matching prevents
"UnitNameOf" from matching "UnitName".
"""
import re
from dataclasses import dataclass
from pathlib import Path

INCLUDE_GLOBS = ["*.lua", "Modules/*.lua"]
EXCLUDE_DIR_PARTS = {"Libs", "Localization", ".release"}


@dataclass(frozen=True)
class CallSite:
    symbol: str
    path: str  # repo-relative
    line: int
    snippet: str


def _iter_lua_files(root: Path):
    for pattern in INCLUDE_GLOBS:
        for p in root.glob(pattern):
            if any(part in EXCLUDE_DIR_PARTS for part in p.parts):
                continue
            yield p


def find_call_sites(symbols: set[str], root: Path) -> list[CallSite]:
    if not symbols:
        return []
    pattern = re.compile(r"\b(" + "|".join(re.escape(s) for s in symbols) + r")\b")
    sites: list[CallSite] = []
    for path in _iter_lua_files(root):
        try:
            text = path.read_text(encoding="utf-8")
        except (OSError, UnicodeDecodeError):
            continue
        for line_no, line in enumerate(text.splitlines(), start=1):
            for m in pattern.finditer(line):
                sites.append(
                    CallSite(
                        symbol=m.group(1),
                        path=str(path.relative_to(root)),
                        line=line_no,
                        snippet=line.strip(),
                    )
                )
    return sites
