import copy, fcntl, hashlib, json, math, os, shutil, signal, subprocess, sys, tarfile, tempfile, time, traceback
from pathlib import Path
from urllib.parse import quote
import yaml
os.umask(0o077)
R=Path(__file__).parent;R.chmod(0o700)
REPO=Path('/workspace/contextra-analytics-runtime-lifecycle-refactor');sys.path.insert(0,str(REPO))
from tools.stream_benchmark import load_config, preflight, Benchmark
from tools.stream_benchmark_runtime import Runtime, file_hash
OLD=Path('/workspace/contextra-runtime-config/test-run/medium8-tracking-intrusion.yaml')
NEW=Path('/workspace/contextra-runtime-config/test-run/pose8-fp16-tracking.yaml')
SOURCE=Path('/tmp/codex/ltb1021/2026-09-13_contextra-pose_r01/export/rfdetr-keypoint-preview.onnx')
TARGET=Path('/data/contextra/model-artifacts/deployments/pose-fp16-e0c4e77/RFDETRKeypointPreview')
ACTIVE=Path('/workspace/contextra-runtime-config/metadata-active/compose.yaml')
ENV=Path('/workspace/contextra-runtime-config/runtime.env')
def save(n,v):
    p=R/n;p.write_text(json.dumps(v,ensure_ascii=False,indent=2,allow_nan=False));p.chmod(0o600)
def read(n):return json.loads((R/n).read_text())
def cmd(a,t=30):
    p=subprocess.run(a,capture_output=True,text=True,timeout=t)
    if p.returncode:
        save('command-error-'+str(time.time_ns())+'.json',dict(command=a,code=p.returncode,stderr=p.stderr[-4000:]))
        raise RuntimeError('Command failure; private evidence retained')
    return p.stdout
def gate():
    assert not (R/'plan.json').exists() and not NEW.exists() and not TARGET.exists()
    cfg=load_config(OLD);rt=Runtime(cfg,R);p=preflight(rt)
    assert len(p['rows'])==16
    assert file_hash(SOURCE)=='66ebb0386fefc400d4bd89fe74cd840d526f179b13ca73cd73850993ceb4aba5'
    inspect=rt.inspect();model_configs={n:rt.triton('v2/models/'+n+'/config') for n in ['RFDETRMedium','RFDETRKeypointPreview','RFDETRFireSmoke']}
    model_files={}
    for m in inspect['Mounts']:
        if m['Destination'].startswith('/opt/contextra/models/triton/'):
            root=Path(m['Source']);model_files.update({str(f):file_hash(f) for f in root.rglob('*') if f.is_file()})
    for path,name in ((ACTIVE,'active.before'),(ENV,'env.before'),(Path(cfg['registration_file']),'registry.before'),(OLD,'benchmark.before')):shutil.copy2(path,R/name)
    p.update(config=cfg,inspect=inspect,head=cmd(['git','-C',str(REPO),'rev-parse','HEAD']).strip(),started=time.time(),
        active_hash=file_hash(ACTIVE),env_hash=file_hash(ENV),model_configs=model_configs,model_files=model_files,onnx_hash=file_hash(SOURCE),
        sender=json.loads(cmd(['python3',str(REPO/'tools/rtsp_test.py'),'list'])),redis_id=json.loads(cmd(['docker','inspect','contextra-redis-1']))[0]['Id'],
        caps=dict(engine_seconds=900,image_seconds=900,free_disk_gib=15,conversion_cpu=4,conversion_ram_gib=12,quality_checks=False),
        presets={str(f):file_hash(f) for f in Path('/workspace/contextra-runtime-config/test-run/presets').rglob('*.yaml')})
    save('plan.json',p);print('Gate PASS; original model artifacts preserved',flush=True)
def bounded(a,name,seconds):
    save(name+'-start.json',dict(command=a,at=time.time()))
    with (R/(name+'.log')).open('x') as log:
        p=subprocess.Popen(a,stdout=log,stderr=log,start_new_session=True);start=time.monotonic()
        while p.poll() is None:
            if time.monotonic()-start>seconds or shutil.disk_usage('/var/lib/docker').free<15*1024**3:
                if name=='engine':cmd(['docker','stop','-t','5','codex-pose-fp16-20260916'])
                else:os.killpg(p.pid,signal.SIGTERM)
                p.wait(20);raise RuntimeError('Resource/time bound')
            time.sleep(2)
    assert p.returncode==0,'Build/convert failed'
    return time.monotonic()-start
def engine():
    assert not (R/'engine-start.json').exists()
    a=['docker','run','--rm','--pull','never','--name','codex-pose-fp16-20260916','--network','none','--gpus','device=0',
       '--cpus','4','--memory','12g','--memory-swap','12g','--ulimit','core=0',
       '-v',str(SOURCE)+':/input/model.onnx:ro','-v',str(R)+':/evidence','--entrypoint','timeout',read('plan.json')['image'],
       '900','/usr/bin/trtexec','--onnx=/input/model.onnx','--saveEngine=/evidence/pose-fp16.plan','--fp16',
       '--inputIOFormats=fp16:chw','--outputIOFormats=fp32:chw,fp32:chw,fp32:chw',
       '--minShapes=input:1x3x576x576','--optShapes=input:4x3x576x576','--maxShapes=input:4x3x576x576',
       '--memPoolSize=workspace:1024','--skipInference']
    elapsed=bounded(a,'engine',920)
    save('engine.json',dict(sha256=file_hash(R/'pose-fp16.plan'),elapsed=elapsed,profile=[1,4,4],input='FP16',output='FP32',quality='not evaluated'))
    print('Pose engine ready',flush=True)
def image():
    assert not (R/'image-start.json').exists()
    paths=cmd(['git','-C',str(REPO),'diff','--name-only']).splitlines()+cmd(['git','-C',str(REPO),'ls-files','--others','--exclude-standard']).splitlines()
    hashes={p:file_hash(REPO/p) for p in paths};digest=hashlib.sha256(json.dumps(hashes,sort_keys=True).encode()).hexdigest()[:8]
    tag='contextra-analytics:pose-fp16-e0c4e77-'+digest;snapshot=R/'snapshot';snapshot.mkdir()
    child=subprocess.Popen(['git','-C',str(REPO),'archive',read('plan.json')['head']],stdout=subprocess.PIPE)
    with tarfile.open(fileobj=child.stdout,mode='r|') as t:t.extractall(snapshot,filter='data')
    assert child.wait()==0
    for p in paths:(snapshot/p).parent.mkdir(parents=True,exist_ok=True);shutil.copy2(REPO/p,snapshot/p)
    save('snapshot.json',dict(tag=tag,hashes=hashes))
    cwd=os.getcwd();os.chdir(snapshot)
    try:elapsed=bounded(['docker','build','--pull=false','--network=default','-f','docker/Dockerfile','--target','app','-t',tag,'.'],'image',900)
    finally:os.chdir(cwd)
    ident=json.loads(cmd(['docker','image','inspect',tag]))[0]['Id']
    save('image.json',dict(image=ident,tag=tag,hashes=hashes,elapsed=elapsed));print('Image ready',tag,flush=True)
if __name__=='__main__':globals()[sys.argv[1]]()
