#!/usr/bin/env python3
"""Scan forbidden terms only in explicitly plot-bearing JSON fields.

Usage:
  scope_aware_forbidden_scan.py INPUT.json RULES.json

RULES.json shape:
{
  "include_paths": ["title", "domain", "premise", "parts.*.beats", "evidence.*.name", "evidence.*.supported_claim"],
  "patterns": {"medical": "\\b(bệnh viện|bác sĩ)\\b"}
}

Policy arrays, forbidden-term inventories, audit instructions, and negative
constraints are excluded unless explicitly listed. Exit 2 means genuine hits.
"""
import json
import re
import sys
from pathlib import Path


def values_at(node, segments, path=()):
    if not segments:
        if isinstance(node, str):
            yield ".".join(map(str, path)), node
        return
    head, *tail = segments
    if head == "*":
        items = node.items() if isinstance(node, dict) else enumerate(node) if isinstance(node, list) else ()
        for key, value in items:
            yield from values_at(value, tail, path + (key,))
    elif isinstance(node, dict) and head in node:
        yield from values_at(node[head], tail, path + (head,))


def main():
    if len(sys.argv) != 3:
        raise SystemExit("usage: scope_aware_forbidden_scan.py INPUT.json RULES.json")
    source_path, rules_path = map(Path, sys.argv[1:])
    source = json.loads(source_path.read_text())
    rules = json.loads(rules_path.read_text())
    fields = []
    for spec in rules["include_paths"]:
        fields.extend(values_at(source, spec.split(".")))
    hits = []
    for name, pattern in rules["patterns"].items():
        rx = re.compile(pattern, re.I)
        for path, text in fields:
            for match in rx.finditer(text):
                hits.append({"rule": name, "path": path, "match": match.group(0), "start": match.start()})
    result = {
        "status": "failed" if hits else "passed",
        "source": str(source_path),
        "rules": str(rules_path),
        "included_field_count": len(fields),
        "hits": hits,
    }
    print(json.dumps(result, ensure_ascii=False, indent=2))
    raise SystemExit(2 if hits else 0)


if __name__ == "__main__":
    main()
