from ops import *
baseline=json.loads((HERE/'baseline.json').read_text())
image=json.loads((HERE/'image.json').read_text())['id']
assert inspect('contextra-analytics-1')['Image']==image
expected=json.loads((PRIVATE/'compose-before.json').read_text());actual=json.loads(cmd(compose()+['config','--format','json']))
expected['services']['analytics']['image']=image
assert actual==expected
assert hashlib.sha256(Path('/data/contextra/runtime-state/streams_runtime.yaml').read_bytes()).hexdigest()==json.loads((HERE/'config-fingerprints.json').read_text())['original']
rows=api('/api/v1/streams')['streams']
assert all(r['state']=='stopped' and not r.get('child_pid') and not r.get('cleanup_pending') for r in rows)
cmd(['docker','start','contextra-ai-gateway-1'],timeout=20)
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))))'''
deadline=time.monotonic()+45
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()>deadline:break
    time.sleep(3)
for name,old in baseline['containers'].items():
    if name in ('contextra-analytics-1','contextra-ai-gateway-1'):continue
    c=inspect(name);assert c['Id']==old['id'] and c['Image']==old['image'] and c['State']['StartedAt']==old['started']
a=api('/api/v1/metadata/status')['artifacts']
models=json.loads(cmd(['docker','exec','contextra-analytics-1','python3','-B','-c',
 'import urllib.request,json;print(json.dumps({m:urllib.request.urlopen("http://127.0.0.1:8000/v2/models/"+m+"/ready",timeout=3).status for m in ["RFDETRMedium","RFDETRKeypointPreview","RFDETRFireSmoke","Awiros_person_and_head_detection"]}))']))
rows=api('/api/v1/streams')['streams'];assert all(r['state']=='stopped' and not r.get('child_pid') and not r.get('cleanup_pending') for r in rows)
env=dict(s.split('=',1) for s in inspect('contextra-analytics-1')['Config']['Env'])
assert env.get('CONTEXTRA_PIPELINE_DIAGNOSTICS')!='true'
assert env.get('STREAMS_RUNTIME_PATH')!='/compare/runtime.yaml'
for p,h in json.loads((HERE/'build-intent.json').read_text())['hashes'].items():
    assert hashlib.sha256((REPO/p).read_bytes()).hexdigest()==h
    remote=cmd(['docker','exec','contextra-analytics-1','sha256sum','/opt/contextra/'+p]).split()[0]
    assert remote==h
final=dict(image=image,models=models,wss=bridge['wss']['connected'],artifact={k:a[k] for k in ('enabled','http_enabled')},
 stopped=len(rows),original_config_exact=True,compose_only_image_changed=True,non_target_preserved=True,
 diagnostics_enabled=False,source_hashes_match=True,artifact_fix_applied=False,crowd_test='BLOCKED_CHILD_EXIT')
save('final-state.json',final);print(json.dumps(final))
