"""Independent counts on the released CoSER files. Prints counts only, no test-set text."""
import json, subprocess, sys, statistics, hashlib, collections, re
repo=sys.argv[1]; C='624efc5'
def show(p,c=C): return subprocess.run(['git','-C',repo,'show',f'{c}:{p}'],capture_output=True,check=True).stdout
blob=show('data/test/test_set.json'); print('sha256',hashlib.sha256(blob).hexdigest())
T=json.loads(blob); print('scenes',len(T))
ID=json.loads(show('test_data/test_circumstance_id.json')); OOD=json.loads(show('test_data/test_circumstance_ood.json'))
print('id/ood sizes',len(ID),len(OOD))
keys=collections.Counter(); extra=collections.Counter(); diffs=0
for a,b in zip(T,ID+OOD):
    ka,kb=set(a),set(b)
    for k in ka-kb: extra[k]+=1
    for k in kb-ka: extra['-'+k]+=1
    for k in ka&kb:
        if a[k]!=b[k]: diffs+=1; keys[k]+=1
print('fields only in test_set vs test_data',dict(extra),'differing common values',diffs,dict(keys))
print('top-level fields',sorted(T[0].keys()))
print('tag',collections.Counter(t.get('tag') for t in T))
books=[t['book'] for t in T]; print('books',len(set(books)))
idb={t['book'] for t in T[:100]}; oob={t['book'] for t in T[100:]}; print('id books',len(idb),'ood books',len(oob),'both',len(idb&oob))
tagb=collections.defaultdict(set)
for t in T: tagb[t.get('tag')].add(t['book'])
print({k:len(v) for k,v in tagb.items()})
sp=[[c for c in t['speaking_characters_w_env'] if c!='Environment'] for t in T]
print('speaking per scene',min(map(len,sp)),max(map(len,sp)),'total',sum(map(len,sp)),'mean',sum(map(len,sp))/200)
envlisted=sum('Environment' in t['speaking_characters_w_env'] for t in T); print('Environment listed',envlisted,'appended',200-envlisted)
ln=[len(t['dialogues']) for t in T]; print('lines',min(ln),max(ln),'median',statistics.median(ln),'>20',sum(x>20 for x in ln))
# key_characters
kc=sum(len(t['key_characters']) for t in T); print('key_characters entries',kc,'with thought',sum('thought' in c for t in T for c in t['key_characters']),'nonempty thought',sum(bool(c.get('thought')) for t in T for c in t['key_characters']),'with motivation field',sum('motivation' in c for t in T for c in t['key_characters']))
mot=0; nom=0; nopro=0; noprofs=[]
for t,s in zip(T,sp):
    plotc={c['name']:c for c in t['plot']['key_characters']}
    for name in s:
        f=[c.get('thought','') for c in t['key_characters'] if c.get('name','')==name]
        if f and f[0]: mot+=1
        else: nom+=1
        prof=t['character_profiles'].get(name,'')
        if name in plotc and 'description' in plotc[name]:
            prof=plotc[name].get('description','').strip('\n')+'\n\n'+prof.strip('\n')
        if prof.strip(' \n')=='': nopro+=1
print('speaking with motivation',mot,'without',nom,'speaking without profile text',nopro)
major=[len(t['major_characters']) for t in T]; print('major',min(major),max(major))
first_env=sum(t['speaking_characters_w_env'][0]=='Environment' for t in T); print('scenes where first listed speaker is Environment',first_env)
# held out
H=json.loads(show('data/test/held_out_plots.json'))
print('held_out type',type(H).__name__,'len',len(H))
hb=set(H.keys()) if isinstance(H,dict) else {x.get('book') for x in H}
print('held-out books',len(hb),'overlap with test books',len(hb&set(books)))
ov=hb&set(books); print('scenes in overlap books',sum(b in ov for b in books))
# scene key membership in held out
if isinstance(H,dict):
    for b in ov:
        v=H[b]; print('heldout entry type',type(v).__name__, 'len',len(v))
        ips=[p.get('i_p') for p in v] if isinstance(v,list) else None
        sc=[t['plot']['i_p'] for t in T if t['book']==b]
        print('scene i_p',sorted(sc),'heldout i_p range',(min(ips),max(ips)) if ips else None, 'in', sum(i in (ips or []) for i in sc))
# examples
EX=json.loads(show('data/test/example_test_set.json')); print('example scenes',len(EX))
tk={(t['book'],t['plot']['i_p'],t['i_c']) for t in T}
print('example in 200',sum((e['book'],e['plot']['i_p'],e['i_c']) in tk for e in EX),'example books in test',sum(e['book'] in set(books) for e in EX))
for p in ['exp/simulation/test_set_gpt-4o.json','exp/simulation/test_set_gpt-4o-mini_rag=expr3_conv1.json','exp/simulation/test_set_gpt-4o_rag=expr3_conv1.json']:
    S=json.loads(show(p)); 
    keysS=[(r['book_title'],r['i_p'],r['i_c']) for r in S]
    n=sum(1 for r in S for m in r['simulation'] if m['role']!='NSP'); pre=sum(1 for r in S for m in r['simulation'] if m['role']!='NSP' and m['content'].startswith(m['role']+':'))
    pre2=sum(1 for r in S for m in r['simulation'] if m['role']!='NSP' and any(l.strip().startswith(m['role']+':') for l in m['content'].split('\n')))
    print(p,'scenes',len(S),'in 200',sum(k in tk for k in keysS),'speech msgs',n,'prefixed at start',pre,'any line',pre2,'same as example', sum((e['book'],e['plot']['i_p'],e['i_c']) in set(keysS) for e in EX))
E=json.loads(show('exp/evaluation/test_set_gpt-4o.json'))
print('eval keys',list(E.keys()),'cases',len(E['cases']),{k:round(v,4) for k,v in E['scores'].items()})
dims=['Storyline Consistency','Anthropomorphism','Character Fidelity','Storyline Quality']
ok={'5S+1.5R':0,'S+1.5R':0,'5S':0,'5S+1.5all':0,'5S+1.5all_noclip':0,'S_unclipped_ok':0}; total=0; oob_=0; rs=[]
for k,c in E['cases'].items():
    sim=c['simulation']; R=len([m for m in sim if m['role']!='Environment']); A=len(sim); rs.append((R,A))
    for d in dims:
        fl=c['critique'][d]['flaws']; S=sum(f['severity'] for f in fl if isinstance(f['severity'],int)); stored=c['critique'][d]['score']; total+=1
        if abs(stored-max(0,min(100-(S-0.3*R)*5,100)))<1e-9: ok['5S+1.5R']+=1
        if abs(stored-max(0,min(100-S+1.5*R,100)))<1e-9: ok['S+1.5R']+=1
        if abs(stored-max(0,min(100-5*S,100)))<1e-9: ok['5S']+=1
        if abs(stored-max(0,min(100-5*S+1.5*A,100)))<1e-9: ok['5S+1.5all']+=1
        un=100-(S-0.3*R)*5
        if un>100 or un<0: oob_+=1
print('dimension scores',total,ok,'out of bounds before clip',oob_,'R,all per case',rs)
print('rouge',[c['critique']['rouge_l'] for c in E['cases'].values()],'bleu',[c['critique']['bleu'] for c in E['cases'].values()])
# prefix in evaluation sim
print('eval sim prefix',sum(m['content'].startswith(m['role']+':') for c in E['cases'].values() for m in c['simulation']),sum(1 for c in E['cases'].values() for m in c['simulation']))
