"""Read actual saved SMF and references; check the draft's named arithmetic.
Does not certify browser behavior, competitor-wide uniqueness, or a release.
"""
import pathlib,json,sys,hashlib
E=pathlib.Path(__file__).parent
sys.path.insert(0,str(E))
from midi_reader import parse,max_polyphony
load=lambda name:json.loads((E/name).read_text(encoding='utf-8-sig'))
summary=load('quality-results.json');diagnostics=load('quality-diagnostics.json');notes={};verified={}
for r in summary['conditions']:
 cid=r['id'];m=parse((E/(cid+'.mid')).read_bytes());out=m['notes'];notes[cid]=out;refs=load(cid+'-reference.json')['notes'];used=set();pairs=[]
 for ri,ref in enumerate(refs):
  eligible=[(abs(o['start']-ref['start']),i) for i,o in enumerate(out) if i not in used and o['pitch']==ref['pitch'] and abs(o['start']-ref['start'])<=.05]
  if eligible:
   _,i=min(eligible);used.add(i);pairs.append((ri,i))
 assert (len(refs),len(out),len(pairs),len(refs)-len(pairs),len(out)-len(pairs))==(r['referenceNotes'],r['outputNotes'],r['matchedNotes'],r['missedNotes'],r['extraNotes'])
 assert max_polyphony(out)==r['outputMaxSimultaneous']==1
 assert max_polyphony(refs)==r['referenceMaxSimultaneous']
 exact=octave=0
 for o in out:
  overlaps=[ref for ref in refs if min(o['start']+o['duration'],ref['start']+ref['duration'])>max(o['start'],ref['start'])]
  if any(ref['pitch']==o['pitch'] for ref in overlaps):exact+=1
  elif any((ref['pitch']-o['pitch'])%12==0 for ref in overlaps):octave+=1
 d=next(x for x in diagnostics['conditions'] if x['id']==cid)
 assert (exact,octave)==(d['exactPitchOverlappingOutputs'],d['octaveOnlyOverlappingOutputs'])
 wider_used=set()
 for ref in refs:
  eligible=[(abs(o['start']-ref['start']),i) for i,o in enumerate(out) if i not in wider_used and o['pitch']==ref['pitch'] and abs(o['start']-ref['start'])<=.15]
  if eligible:_,i=min(eligible);wider_used.add(i)
 assert len(wider_used)==d['exploratory150msMatched'],cid+' actual SMF wider-window count differs'
 verified[cid]={'reference':len(refs),'output':len(out),'strictMatches':len(pairs),'exactIntervalOverlap':exact,'octaveOnlyIntervalOverlap':octave,'midiSha256':hashlib.sha256((E/(cid+'.mid')).read_bytes()).hexdigest()}
assert [x['pitch'] for x in notes['plucked']]==[52,57,33,57,38,62,58,34]
assert [x['pitch'] for x in notes['plucked']]==[x['pitch'] for x in notes['vibrato']]==[x['pitch'] for x in notes['white-noise']]
assert notes['vibrato']!=notes['plucked']
vibrato_shifts=[1000*(notes['vibrato'][i]['start']-notes['plucked'][i]['start']) for i in [2,5]]
assert round(vibrato_shifts[0])==46 and abs(vibrato_shifts[1]+325)<1e-8
saved_vibrato=load('vibrato-timing-diagnostic.json')
assert all(abs(a-b['startDifferenceMs'])<1e-8 for a,b in zip(vibrato_shifts,saved_vibrato['rows']))
assert notes['reverb'][5]['pitch']-notes['plucked'][5]['pitch']==-24
delta=(notes['reverb'][5]['start']-notes['plucked'][5]['start'])*1000
assert round(-delta)==140
n=next(r for r in summary['conditions'] if r['id']=='white-noise')['matchedPairs'][0]
assert n['pitch']==58 and round(-1000*n['onsetErrorSeconds'])==47 and round(-1000*n['durationErrorSeconds'])==587
assert summary['overallAccuracyPercent'] is None
assert all(x['clippedSamples']==0 for x in load('input-generation.json')['cases'])
assert load('offline-reproduction.json')['filesMatched']==50 and load('offline-reproduction.json')['browserValidated'] is False
report={'result':'PASS_OFFLINE_PROSE_ARITHMETIC_ONLY','conditions':verified,'reverbOrdinal6':{'plucked':notes['plucked'][5],'reverb':notes['reverb'][5],'startDifferenceMs':delta,'roundedEarlierMs':round(-delta),'pitchDifferenceSemitones':-24,'scope':'Actual exported SMF quantized timing, not pre-export floating note positions; ordinal pairing not performed-note identity'},'browserValidated':False,'published':False}
(E/'prose-claim-check.json').write_text(json.dumps(report,indent=2)+'\n',encoding='utf-8')
print(json.dumps(report))
