from ops import *

rows=api('/api/v1/streams')['streams']
assert all(r['state']=='stopped' and not r.get('child_pid') and not r.get('cleanup_pending') and
           not any(v.get('child_pid') for v in r.get('provider_processes',{}).values()) for r in rows)
saved=json.loads((PRIVATE/'settings-before-trial.json').read_text())
trial=json.loads((HERE/'trial-result.json').read_text())
for camera,old in saved.items():
    sid=next(k for k,v in trial['cleanup']['channels'].items() if k==camera)
    # The original identity is kept in the preserved runtime settings.
    import yaml
    spec=next(s for s in yaml.safe_load((PRIVATE/'streams.yaml').read_text())['added'] if str(s.get('camera_id'))==camera)
    now=api('/api/v1/streams/'+spec['stream_id']+'/settings')['configured']
    a={k:v for k,v in old.items() if k!='revision'}
    b={k:v for k,v in now.items() if k!='revision'}
    if 'scenario' not in a['fire'] and 'scenario' in b['fire']:
        assert b['fire']['scenario']['enabled'] is False
        del b['fire']['scenario']
    assert a==b, 'SETTINGS_RESTORE_'+camera
baseline=json.loads((HERE/'baseline.json').read_text())
non_target=[]
for name,old in baseline['containers'].items():
    if name in ('contextra-analytics-1','contextra-ai-control-sidecar-1','contextra-ai-gateway-1'):
        continue
    current=inspect(name)
    if current['Id']!=old['id'] or current['Image']!=old['image'] or current['State']['StartedAt']!=old['started']:
        non_target.append(name)
env=dict(s.split('=',1) for s in inspect('contextra-analytics-1')['Config']['Env'])
flags=dict(CONTEXTRA_TEST_NO_CAPTURE='false',CONTEXTRA_PIPELINE_DIAGNOSTICS='false',CONTEXTRA_INPUT_TIMING_SECONDS='0',
    CONTEXTRA_SOURCE_LATEST_TRIAL='true',CONTEXTRA_COMPLETED_QUEUE_MAX_AGE_SECONDS='1',
    CONTEXTRA_PROVIDER_LINEAR_TRIAL='true',CONTEXTRA_PROVIDER_FRESHNESS_ENABLED='false',
    CONTEXTRA_EVENT_COOLDOWN_SECONDS='10',CONTEXTRA_METADATA_STREAM_LENGTH='300')
assert all(env.get(k)==v for k,v in flags.items())
expected=json.loads((PRIVATE/'compose.json').read_text())
live=json.loads(cmd(compose()+['config','--format','json']))
images=json.loads((HERE/'reflect-done.json').read_text())['images']
expected['services']['analytics']['image']=images['analytics']['id']
expected['services']['ai-control-sidecar']['image']=images['sidecar']['id']
expected['services']['analytics']['environment'].update(json.loads((HERE/'reflect-done.json').read_text())['flags'])
assert expected==live,'COMPOSE_UNEXPECTED_CHANGE'
models=json.loads(cmd(['docker','exec','contextra-analytics-1','python3','-B','-c',
    'import urllib.request,json; names=["RFDETRMedium","RFDETRKeypointPreview","RFDETRFireSmoke","Awiros_person_and_head_detection"]; print(json.dumps({n:{"ready":urllib.request.urlopen("http://127.0.0.1:8000/v2/models/"+n+"/ready",timeout=3).status,"config":json.load(urllib.request.urlopen("http://127.0.0.1:8000/v2/models/"+n+"/config",timeout=3))} for n in names}))'],timeout=20))
assert all(m['ready']==200 and m['config']['max_batch_size']==8 and m['config']['instance_group'][0]['count']==8 for m in models.values())
old_training=json.loads((PRIVATE/'training.json').read_text())
current_training=training()
assert all(old_training[k]==current_training[k] for k in ('revision','configured','effective'))
cmd(['docker','start','contextra-ai-gateway-1'],timeout=30)
code='''import urllib.request,json,os
from pathlib import Path
r=urllib.request.Request("http://localhost:8080/internal/bridge-status",headers={"Authorization":"Bearer "+Path(os.environ["CONTEXTRA_CONTROL_TOKEN_FILE"]).read_text().strip()})
print(json.dumps(json.load(urllib.request.urlopen(r,timeout=3))))'''
end=time.monotonic()+60
while True:
    bridge=json.loads(cmd(['docker','exec','contextra-ai-control-sidecar-1','python3','-B','-c',code],timeout=6))
    if bridge['wss']['connected'] or time.monotonic()>end:
        break
    time.sleep(2)
time.sleep(3)
rows=api('/api/v1/streams')['streams']
artifact=api('/api/v1/metadata/status')['artifacts']
state=dict(images=images,flags=flags,models=models,states={s:sum(r['state']==s for r in rows) for s in set(r['state'] for r in rows)},
    child_count=sum(bool(r.get('child_pid'))+sum(bool(p.get('child_pid')) for p in r.get('provider_processes',{}).values()) for r in rows),
    settings_restored=True,training_restored=True,persistent_runtime_match=True,non_target_drift=non_target,
    gateway_running=inspect('contextra-ai-gateway-1')['State']['Running'],wss_connected=bridge['wss']['connected'],
    artifact={k:artifact.get(k) for k in ('enabled','http_enabled','active','rendering','error')},root_free_bytes=shutil.disk_usage('/').free)
save('final-state.json',state)
print(json.dumps({k:v for k,v in state.items() if k not in ('models','images')},ensure_ascii=False))
