from ops import *
import hashlib
import traceback

assert not (R/'trial-started.json').exists()
plan=json.loads((R/'plan.json').read_text())
assert prior.prev.sender()['executionId']==plan['sender']['executionId']
state=dict(stage='prepared',commands=[])
save('trial-started.json',dict(at=time.time(),caps=plan['caps'],preset_hash=base.g.sha(PRESET)))
def run(action):
    state['commands'].append(action);save('trial.json',state)
    p=subprocess.run(CLI+[action,str(PRESET)],cwd=REPO,capture_output=True,text=True,timeout=105)
    save('cli-'+action+'.json',dict(returncode=p.returncode,stdout=p.stdout,stderr=p.stderr))
    assert p.returncode==0,'CLI_'+action.upper()+'_FAILED'
    return json.loads(p.stdout)
try:
    state['stop']=run('stop')
    assert state['stop']['state']=='stopped' and not state['stop']['cleanup_pending']
    state['start']=run('start')
    assert state['start']['state']=='running'
    time.sleep(4)
    key='contextra:metadata:v1:camera:'+hashlib.sha256(plan['registration']['source_id'].encode()).hexdigest()+':frames'
    a=api('/api/v1/streams/rtsp-test-01');xa=base.m.query('reader','XINFO','STREAM',key);t0=time.monotonic()
    queues=[];frames=[];ttls=[];lengths=[]
    for i in range(15):
        time.sleep(1)
        row=api('/api/v1/streams/rtsp-test-01');assert row['state']=='running' and not row.get('last_error')
        queues.append(row['metadata_path']['queued'])
        lengths.append(base.m.query('reader','XLEN',key));ttls.append(base.m.query('reader','PTTL',key))
        if i in (0,5,10,14):
            values=base.m.query('reader','XREVRANGE',key,'+','-','COUNT','2')
            for _,v in values:
                if isinstance(v,list):v=dict(zip(v[::2],v[1::2]))
                frame=json.loads(v['json']);assert frame['runId']==row['run_id'] and frame['sourceId']==plan['registration']['source_id']
                assert frame['frameTime']['rtpTimestamp'] is not None
                assert frame['frameTime']['syncStatus']=='ESTIMATED'
                frames.append(frame)
    xb=base.m.query('reader','XINFO','STREAM',key);elapsed=time.monotonic()-t0;b=api('/api/v1/streams/rtsp-test-01')
    result_fps=(b['metadata_path']['processed']-a['metadata_path']['processed'])/elapsed
    redis_fps=(xb['entries-added']-xa['entries-added'])/elapsed
    assert result_fps>9 and redis_fps>9 and max(queues)<=2
    assert min(lengths)==max(lengths)==30 and min(ttls)>0
    assert not b['metadata_path']['performance']['detail'] and b['metadata_path'].get('visual') is None
    assert b['scenarios']['active']==['INTRUSION']
    state.update(stage='PASS',result_fps=result_fps,redis_fps=redis_fps,elapsed_seconds=elapsed,queue_range=[min(queues),max(queues)],ttl_range=[min(ttls),max(ttls)],length=30,queue_drop=b['metadata_path'].get('queue_drop',0),publisher=api('/api/v1/metadata/status'),final=b)
    save('frames.json',frames)
except Exception:
    state['stage']='FAIL';state['error']=traceback.format_exc()
    try:
        rows=api('/api/v1/streams')['streams']
        assert all(x['stream_id']=='rtsp-test-01' or x['state']=='stopped' for x in rows)
        row=api('/api/v1/streams/rtsp-test-01')
        if row['state']=='running' and state['commands'][-1]=='start':
            api('/api/v1/streams/rtsp-test-01/stop','POST');time.sleep(2);row=api('/api/v1/streams/rtsp-test-01')
        if row['state']!='stopped' or row.get('cleanup_pending'):
            subprocess.run(['docker','update','--restart=no','contextra-analytics-1'],capture_output=True,timeout=10)
            subprocess.run(['docker','stop','-t','15','contextra-analytics-1'],capture_output=True,timeout=25)
            state['safe_stopped']=True
    except Exception:state['cleanup_error']=traceback.format_exc()
finally:
    save('trial.json',state)
    ledger=json.loads((R/'ledger.json').read_text());ledger.update(cli_stop=state['commands'].count('stop'),cli_start=state['commands'].count('start'));save('ledger.json',ledger)
print(json.dumps({k:state.get(k) for k in ['stage','result_fps','redis_fps','queue_range','queue_drop','error','cleanup_error']},ensure_ascii=False))
