from common import *
import hashlib
import signal
import sys
import time
import traceback
sys.path.insert(0,str(REPO/'tools'))
from rtsp_test_manager import Manager
path='/api/v1/streams/rtsp-test-01'
assert json.loads((R/'applied.json').read_text())['stage']=='PASS'
assert not (R/'live.json').exists()
sender=next(s for s in Manager().status() if s['name']=='sample01')
assert sender['state']=='STREAMING' and sender['anchor']
old=api(path+'/settings')['configured']
patch=dict(expected_revision=old['revision'],frame_time_anchor=sender['anchor']['frame_time_anchor'],
           analysisFpsTarget=10,display_score=.25,display_categories=['person'],debug_all_candidates=False,
           intrusion=dict(enabled=True,confidence=.5,dwell_seconds=.5,roi_name='Test center-right',
                          roi=[[.35,.3],[.85,.3],[.85,1],[.35,1]]))
settings=api(path+'/settings','PATCH',patch)
state=dict(stage='prepared',settings=settings['configured'],sender=sender,start_attempts=0,stop_attempts=0,
           caps=dict(total_seconds=90,first_result_seconds=35,warmup_seconds=3,measurement_seconds=15,stored_frames=90),samples=[])
save('live.json',state)
def alarm(*_):raise TimeoutError('LIVE_CAP')
signal.signal(signal.SIGALRM,alarm);signal.alarm(90)
key='contextra:metadata:v1:camera:'+hashlib.sha256(b'rtsp-test-source-01').hexdigest()+':frames'
frames={}
try:
    state['start_attempts']=1;save('live.json',state)
    api(path+'/start','POST');deadline=time.monotonic()+35
    while time.monotonic()<deadline:
        status=api(path)
        assert not status.get('last_error') and not status.get('cleanup_error')
        if status.get('metadata_path',{}).get('processed',0)>0:break
        time.sleep(.3)
    else:raise TimeoutError('FIRST_RESULT_TIMEOUT')
    state['run_id']=status['run_id'];state['generation']=status['run_generation']
    time.sleep(3)
    before=api(path);t0=time.monotonic();end=t0+15
    while time.monotonic()<end:
        status=api(path)
        assert status['state']=='running' and not status.get('last_error')
        entries=redis('reader','XREVRANGE',key,'+','-','COUNT','30') or []
        for entry,fields in entries:
            if isinstance(fields,list):fields=dict(zip(fields[::2],fields[1::2]))
            v=json.loads(fields['json'])
            if v['runId']!=state['run_id']:continue
            if len(frames)<90 or v['frameSeq'] in frames:frames[v['frameSeq']]=v
        time.sleep(.3)
    after=api(path);elapsed=time.monotonic()-t0
    state.update(before=before,after=after,elapsed_s=elapsed,queue=after['metadata_path']['queued'],
        result_fps=(after['metadata_path']['processed']-before['metadata_path']['processed'])/elapsed,
        publisher=api('/api/v1/metadata/status'))
    values=list(frames.values());assert values,'NO_REDIS_FRAMES'
    raw=[x for x in values if x['frameTime']['rtpTimestamp'] is not None]
    state['rtp_present']=len(raw);state['redis_samples']=len(values)
    state['events']=len({e['eventId'] for x in values for e in x.get('events',[])})
    state['red_objects']=sum(o.get('color')=='#FF3333' for x in values for o in x.get('objects',[]))
    state['colors']=sorted({o.get('color') for x in values for o in x.get('objects',[])})
    for v in raw:
        t=v['frameTime']
        if t['syncStatus']=='ESTIMATED':
            assert t['detectedAtWallMs']==t['startWallTimeMs']+t['rtpTimestamp']*1000//t['rtpClockRate'],'TIME_ARITHMETIC'
    state['rtp_statuses']=sorted({v['frameTime']['syncStatus'] for v in values})
    save('frames.json',values)
    state['stage']='PASS' if len(raw)==len(values) else 'RTP_UNAVAILABLE'
except Exception:
    state['stage']='FAIL';state['error']=traceback.format_exc()
finally:
    signal.alarm(0)
    if state['start_attempts']:
        state['stop_attempts']=1
        try:
            state['stop_response']=api(path+'/stop','POST')
            end=time.monotonic()+45
            while time.monotonic()<end:
                final=api(path)
                if final['state']=='stopped' and not final.get('cleanup_pending'):break
                time.sleep(.3)
            state['final']=final
            assert final['state']=='stopped' and not final.get('cleanup_error'),'CLEANUP_FAILED'
        except Exception:
            state['cleanup_error']=traceback.format_exc()
            subprocess.run(['docker','update','--restart=no',g.NAME],capture_output=True,timeout=10)
            subprocess.run(['docker','stop','-t','15',g.NAME],capture_output=True,timeout=30)
    save('live.json',state)
    ledger=json.loads((R/'ledger.json').read_text());ledger.update(ai_start=state['start_attempts'],ai_stop=state['stop_attempts']);save('ledger.json',ledger)
print(json.dumps({k:state.get(k) for k in ('stage','result_fps','queue','rtp_present','redis_samples','rtp_statuses','events','colors','error','cleanup_error')}))
