import copy, hashlib, json, os, pathlib, subprocess, sys
here = pathlib.Path(__file__).resolve().parent
root = here.parent
samples = root / 'step1-contract-smoke/samples.jsonl'
source = (root / 'step1-contract-smoke/confirmed.log').read_text().splitlines()
results = []

def marked(row, raw=20, processing=280):
    begin = row['capture_begin_mono_ms']
    row.update(capture_timing='raw-copy-resume-v1', capture_end_mono_ms=begin+raw,
               processing_begin_mono_ms=begin+raw, processing_end_mono_ms=begin+raw+processing,
               processing_duration_ms=processing, total_duration_ms=raw+processing)
    delta = row['processing_end_mono_ms'] - row['mono_ms']
    row['mono_ms'] += delta
    row['wall_ms'] += delta

def mutate(row, case):
    if case == 'legacy': return
    if case == 'legacy_slow':
        row['capture_end_mono_ms'] = row['capture_begin_mono_ms'] + 101
        return
    marked(row, raw=100 if case == 'raw_at_limit' else 101 if case == 'raw_over_limit' else 20,
           processing=600 if case == 'overlap' else 280)
    if case.startswith('missing_'): row.pop(case.removeprefix('missing_'))
    if case == 'unknown_marker': row['capture_timing'] = 'future-unapproved-mode'
    if case == 'processing_gap': row['processing_begin_mono_ms'] += 1
    if case == 'processing_reverse': row['processing_end_mono_ms'] = row['processing_begin_mono_ms']-1
    if case == 'duration_mismatch': row['processing_duration_ms'] += 1
    if case == 'total_mismatch': row['total_duration_ms'] += 1
    if case == 'resume_error': row['workers'][0]['error'] = 'ResumeThread failed'
    if case == 'symbol_error': row['workers'][1]['error'] = 'SymFromAddr failed: Win32 487'
    if case == 'unmarked_still_total':
        row.pop('capture_timing')
        row['capture_end_mono_ms'] = row['capture_begin_mono_ms'] + 101

def run(case, analyzer, expected, prefix):
    label = prefix + '-' + case
    lines=[]
    for line in source:
        if 'NET_DIAG_V1:' not in line:
            lines.append(line); continue
        lead, payload = line.split('NET_DIAG_V1:', 1)
        row = json.loads(payload)
        if row['event'] == 'NET_WORKERS_SNAPSHOT': mutate(row, case)
        lines.append(lead+'NET_DIAG_V1:'+json.dumps(row))
    logfile=here/(label+'.log')
    logfile.write_text('\n'.join(lines)+'\n',encoding='utf-8')
    env = dict(os.environ, PYTHONPATH=str(root))
    out=here/label
    proc=subprocess.run([sys.executable,str(analyzer),'--samples',str(samples),'--log',str(logfile),'--out',str(out)],capture_output=True,text=True,env=env,timeout=10)
    assert proc.returncode == expected, (label,proc.returncode,proc.stdout,proc.stderr)
    summary=json.loads(proc.stdout)
    intervals=[json.loads(s) for s in (out/'intervals.jsonl').read_text().splitlines()]
    stacks=[json.loads(s) for s in (out/'stacks.jsonl').read_text().splitlines()]
    if expected == 0: assert summary['coverage']=='PASS' and summary['mechanism']=='CONFIRMED', (label,summary)
    if expected == 2: assert summary['coverage']=='INSUFFICIENT_EVIDENCE', (label,summary)
    if prefix == 'successor' and case in ('marked_good','raw_at_limit'):
        assert summary['processing_duration_ms'] == {'reported_count':2,'missing_or_invalid_count':0,'min':280,'max':280,'sum':560}
        assert all(s['processing_duration_ms']==280 for s in stacks)
        assert all(s['timing']['processing_duration_ms']==280 for i in intervals for s in i['stacks']['accepted'])
    if prefix == 'successor' and case=='overlap':
        epochs=json.loads((out/'epochs.json').read_text())
        assert any('capture_overlaps_previous_processing' in e['issues'] for e in epochs)
    results.append({'label':label,'exit':proc.returncode,'coverage':summary['coverage'],'mechanism':summary['mechanism'],'processing_duration_ms':summary.get('processing_duration_ms')})

# Predecessor accepts these malformed marked records: the newly required contract is not enforced.
for case in ('unknown_marker','missing_processing_duration_ms'):
    run(case,here/'baseline-analyze.py',0,'baseline')
cases = ('legacy','legacy_slow','marked_good','raw_at_limit','raw_over_limit',
         'missing_processing_begin_mono_ms','missing_processing_end_mono_ms','missing_processing_duration_ms',
         'missing_total_duration_ms','unknown_marker','processing_gap','processing_reverse',
         'duration_mismatch','total_mismatch','resume_error','symbol_error','overlap','unmarked_still_total')
for case in cases:
    run(case,root/'step1-analyze.py',0 if case in ('legacy','marked_good','raw_at_limit') else 2,'successor')
(here/'verification.json').write_text(json.dumps({'cases':results,'successor_cases':len(cases),'baseline_controls':2},indent=2),encoding='utf-8')
print(json.dumps({'successor_cases':len(cases),'baseline_controls':2,'all_expected':True}))
