# -*- coding: utf-8 -*-
import re, json, io, sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
slides = json.load(open(r"C:\GUARDiA\workspace\kintex\_workspace\proposal\_qa_slides.json", encoding="utf-8"))

# Full REQ universe
UNIV = {}
for pfx, cnt in [("F", 81), ("A", 20), ("N", 21), ("S", 20)]:
    for i in range(1, cnt + 1):
        UNIV[f"{pfx}-{i:03d}"] = None  # slide where covered

# Parse each text line for badge tokens with prefix-context + range + continuation.
# Grammar we support in a run:
#   REQ-<P>-<n>            single
#   REQ-<P>-<n>~<m>        range (same prefix)
#   ...·<P>-<n>            new prefix single continuation
#   ...·<P>-<n>~<m>        new prefix range continuation
#   ...·<n>               bare number continues LAST prefix (e.g. A-011·012)
#   ...·<n>~<m>           bare range continues last prefix (e.g. 067~069)
cover = {}  # req -> list of slides

def add(pfx, a, b, sn):
    for i in range(a, b + 1):
        key = f"{pfx}-{i:03d}"
        cover.setdefault(key, set()).add(sn)

# token: optional prefix letter, number, optional ~ number
tok = re.compile(r"(?:REQ-)?(?:([FANS])-)?(\d{2,3})(?:\s*~\s*(?:[FANS]-)?(\d{2,3}))?")

for s in slides:
    sn = s["n"]
    for t in s["texts"]:
        # only scan segments that look like badge context (contain REQ- or letter-number dot chains)
        for m in re.finditer(r"REQ-[FANS]-\d{2,3}(?:\s*~\s*\d{2,3})?(?:[·,\s]+(?:[FANS]-)?\d{2,3}(?:\s*~\s*\d{2,3})?)*", t):
            seg = m.group(0)
            last_pfx = None
            for mm in tok.finditer(seg):
                p, a, b = mm.group(1), mm.group(2), mm.group(3)
                if p:
                    last_pfx = p
                if last_pfx is None:
                    continue
                ai = int(a)
                bi = int(b) if b else ai
                # sanity: within universe range
                add(last_pfx, ai, bi, sn)

missing = sorted(k for k in UNIV if k not in cover)
print("=== RANGE-EXPANDED BADGE COVERAGE ===")
print("COVERED (badge):", len(cover), "/ 142")
print("NOT badge-covered (", len(missing), "):", ", ".join(missing))

# priority 7
prio = ["F-008", "F-010", "F-026", "F-032", "A-003", "A-005", "A-008"]
print("\n=== PRIORITY 7 BADGE STATUS ===")
for r in prio:
    print(f"{r}: badge slides = {sorted(cover.get(r, []))}")

# dump per-covered for the previously-flagged 18
flagged = ["F-005","F-008","F-010","F-026","F-032","F-034","F-036","F-038","F-039","F-054","F-074","F-075","F-076","A-003","A-005","A-008","S-005","S-006"]
print("\n=== PREVIOUSLY-FLAGGED 18: badge coverage after range expansion ===")
for r in flagged:
    sl = sorted(cover.get(r, []))
    print(f"{r}: {'BADGE ' + str(sl) if sl else 'NO BADGE'}")
