"""Standard-library check of extraction -> display; does not verify original MAT."""
import bisect, gzip, json, statistics
from pathlib import Path

def verify(folder):
    p=Path(folder)
    data=json.loads(gzip.decompress((p/'plotted-records.json.gz').read_bytes()))
    raw=json.loads(gzip.decompress((p/'retained-archive.json.gz').read_bytes()))
    claims=json.loads((p/'claim-values.json').read_bytes())
    assert data['claims']==claims and data['record']==raw['record'] and data['start_ms']==raw['start_ms']
    expected=[{'rack_id':m['rack_id'],**{ch:[r for r in m[ch] if r[3]=='DISPLAYED'] for ch in ('current','voltage')}} for m in raw['members']]
    assert data['members']==expected
    byid={m['rack_id']:m for m in expected}
    count=0
    for ch in ('current','voltage'):
        for ids,sets in [(['1','4'],data['pair'][ch]),(list('123456789'),{'5':data['nine'][ch]})]:
            series=[sorted(byid[i][ch],key=lambda r:(r[1],r[0])) for i in ids]
            times=[[r[1] for r in rows] for rows in series]
            union=sorted(set(t for ts in times for t in ts))
            for a,stored in sets.items():
                rebuilt=[];last=None
                for t in union:
                    at=[bisect.bisect_right(ts,t)-1 for ts in times]
                    if min(at)<0:continue
                    rows=[s[j] for s,j in zip(series,at)]
                    if any(t-r[1]>int(a)*1000 for r in rows):continue
                    ids_now=tuple(r[0] for r in rows)
                    if ids_now==last:continue
                    last=ids_now
                    rebuilt.append([t,[r[2] for r in rows],list(ids_now),[r[1] for r in rows]])
                assert stored==rebuilt,(ch,ids,a)
                count+=len(stored)
    start=data['start_ms']
    for row in claims['rows']:
        a,b=row['bin_start_min'],row['bin_end_min']
        def select(ns):return [n for n in ns if a<=(n[0]-start)/60000<b]
        nodes=select(data['pair']['current']['5']);same=select(data['pair']['current']['0'])
        ds=[n[1][0]-n[1][1] for n in nodes]
        assert len(nodes)==row['pair_nodes_age5'] and len(same)==row['exact_timestamp_nodes']
        assert abs(statistics.median(ds)-row['D_median_A'])<1e-6
        assert abs(statistics.median([statistics.median(n[1]) for n in select(data['nine']['current'])])-row['C_median_A'])<1e-6
        for ns in (nodes,same):
            assert all(v<0 for n in ns for v in n[1]),'charge interpretation requires both negative'
            assert all((n[1][0]<n[1][1]) if a in (90,115) else (n[1][0]>n[1][1]) for n in ns)
    voltage=[n for n in data['pair']['voltage']['5'] if 80<=(n[0]-start)/60000<120]
    assert len(voltage)==114 and all(n[1][0]<n[1][1] for n in voltage)
    assert not any(85<=(n[0]-start)/60000<90 for n in voltage)
    for a in range(80,120,5):
        med=[]
        for screen in ('5','10'):
            ds=[n[1][0]-n[1][1] for n in data['pair']['current'][screen] if a<=(n[0]-start)/60000<a+5]
            med.append(round(statistics.median(ds),5))
        assert med[0]==med[1]
    return {'status':'PASS','node_sets_rebuilt':8,'nodes_verified':count,'table_rows':4,'basis':'record arithmetic, not physics or upstream extraction'}

if __name__=='__main__':print(json.dumps(verify(Path(__file__).resolve().parent)))
