"""Small whitespace-token WER teaching implementation; not NIST/Whisper parity."""
import re,json,sys
from pathlib import Path
def tokens(s):return re.findall(r"\w+(?:'\w+)?",s.casefold(),re.UNICODE)
def score(ref,hyp):
    a,b=tokens(ref),tokens(hyp)
    # state = total errors, substitutions, deletions, insertions
    dp=[[(0,0,0,0) for _ in range(len(b)+1)] for _ in range(len(a)+1)]
    for i in range(1,len(a)+1):dp[i][0]=(i,0,i,0)
    for j in range(1,len(b)+1):dp[0][j]=(j,0,0,j)
    for i in range(1,len(a)+1):
        for j in range(1,len(b)+1):
            if a[i-1]==b[j-1]:dp[i][j]=dp[i-1][j-1]
            else:
                e,s,d,n=dp[i-1][j-1];sub=(e+1,s+1,d,n)
                e,s,d,n=dp[i-1][j];delete=(e+1,s,d+1,n)
                e,s,d,n=dp[i][j-1];insert=(e+1,s,d,n+1)
                dp[i][j]=min((sub,delete,insert),key=lambda x:x[0])
    e,s,d,n=dp[-1][-1]
    return {'referenceWords':len(a),'substitutions':s,'deletions':d,'insertions':n,'errors':e,'wer':None if not a else e/len(a)}
if __name__=='__main__':
    rows=[]
    for f in json.loads(Path(sys.argv[1] if len(sys.argv)>1 else 'wer-fixtures.json').read_text()):
        r=score(f['reference'],f['hypothesis']);assert r['errors']==f['expectedErrors'];rows.append({'id':f['id'],**r})
    print(json.dumps({'scope':'Invented text pairs; no speech recognizer or provider executed','normalization':'Unicode casefold; word regex retaining internal ASCII apostrophe; punctuation discarded','tieBreak':'substitution, deletion, insertion among equal-error alignments','fixtures':rows,'fixtureCount':len(rows),'providerOperations':0},sort_keys=True,indent=2))
