#!/usr/bin/env python3
"""Score a VoxStudio export where some labels are person names (recognition test).

Ground truth: manifest turns (voice A = enrolled person, B and C = not enrolled).
Reports: named utterances that are correct (A named as the person), false names
(B or C carrying the person name), anonymous utterances, and label consistency.
"""
import difflib, json, re, sys
from collections import Counter, defaultdict

def norm(s):
    return re.sub(r"[\s\W_]+", "", s.lower(), flags=re.UNICODE)

def parse(path):
    blocks = []
    for line in open(path, encoding="utf-8"):
        m = re.match(r"^(.+?):\s(.*)$", line.strip())
        if m:
            blocks.append((m.group(1), m.group(2)))
    return blocks

def cov(a, b):
    sm = difflib.SequenceMatcher(None, a, b, autojunk=False)
    return sum(x.size for x in sm.get_matching_blocks()) / max(1, len(a))

def main(manifest_path, export_path, enrolled_voice="A"):
    m = json.load(open(manifest_path, encoding="utf-8"))
    utts = [(t["speaker"], u["text"]) for t in m["turns"] for u in t["utterances"]]
    blocks = parse(export_path)
    bn = [norm(t) for _, t in blocks]
    rows = []
    for voice, text in utts:
        un = norm(text)
        best = max(range(len(blocks)), key=lambda i: cov(un, bn[i]))
        rows.append((voice, blocks[best][0]))
    named = lambda lab: not re.match(r"^Speaker \d+$", lab)
    named_rows = [(v, l) for v, l in rows if named(l)]
    correct_named = sum(1 for v, l in named_rows if v == enrolled_voice)
    false_named = sum(1 for v, l in named_rows if v != enrolled_voice)
    enrolled_total = sum(1 for v, _ in rows if v == enrolled_voice)
    per_label = defaultdict(Counter)
    for v, l in rows:
        per_label[l][v] += 1
    print(json.dumps({
        "utterances": len(rows),
        "labels": sorted(per_label),
        "enrolled_utterances": enrolled_total,
        "named_utterances": len(named_rows),
        "correct_names": correct_named,
        "false_names": false_named,
        "label_voice_counts": {k: dict(v) for k, v in per_label.items()},
    }, ensure_ascii=False, indent=2))

if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2])
