import json,os,subprocess,time,urllib.request
from pathlib import Path
os.umask(0o077)
ROOT=Path('/backup/contextra/deployment-inbox/icerti-provider-20260927-r01')
def cmd(args,timeout=90):return subprocess.check_output(args,text=True,timeout=timeout)
def api(path,body=None):
    r=urllib.request.Request('http://127.0.0.1:35000'+path,data=json.dumps(body).encode() if body is not None else None,headers={'Content-Type':'application/json'})
    return json.load(urllib.request.urlopen(r,timeout=15))
def save(n,v):
    with (ROOT/n).open('x') as f:json.dump(v,f,indent=2)
cmd(['docker','stop','--signal=SIGTERM','--timeout=-1','contextra-icerti-ai-gateway-1'])
rows=api('/api/v1/streams')['streams']
targets=[r['stream_id'] for r in rows if r['state']!='stopped' or r.get('child_pid') or r.get('cleanup_pending')]
save('stop-intent.json',dict(targets=targets,gateway_stopped=True,automatic_restart=False))
for sid in targets:api('/api/v1/streams/'+sid+'/stop',{})
until=time.monotonic()+120
while True:
    rows=api('/api/v1/streams')['streams']
    if all(r['state']=='stopped' and not r.get('child_pid') and not r.get('cleanup_pending') for r in rows):break
    if time.monotonic()>until:raise RuntimeError('STOP_REAP_BOUNDARY')
    time.sleep(1)
save('channels-stopped.json',dict(count=len(rows),stopped=len(rows),children=0))
# Previously admitted work is allowed its existing finite delivery lifetime.
until=time.monotonic()+135
while True:
    art=api('/api/v1/metadata/status')['artifacts']
    if not art.get('active') and not art.get('ledger',{}).get('pending') and not art.get('ledger',{}).get('storage',{}).get('reserved_jobs'):break
    if time.monotonic()>until:raise RuntimeError('ARTIFACT_DRAIN_BOUNDARY')
    time.sleep(2)
save('artifact-drained.json',art)
for name in ('ai-control-sidecar','analytics'):
    cid='contextra-icerti-'+name+'-1'
    cmd(['docker','stop','--signal=SIGTERM','--timeout=-1',cid])
    state=json.loads(cmd(['docker','inspect','--format','{{json .State}}',cid]))
    assert not state['Running'] and state['ExitCode']==0,(name,'STOP_EXIT')
sql="SELECT json_build_object('count',count(*),'attempts',sum(attempts),'reservations',sum(reservation),'fingerprint',md5(string_agg(md5(t::text),'' ORDER BY event_id))) FROM contextra_event_artifacts t;"
r=subprocess.run(['docker','exec','-i','contextra-icerti-postgresql-1','sh','-c','exec psql -X -qAt -U "$POSTGRES_USER" -d "$POSTGRES_DB"'],input=sql,capture_output=True,text=True,check=True,timeout=15)
save('ledger-quiescent.json',json.loads(r.stdout))
assert not cmd(['nvidia-smi','--query-compute-apps=pid','--format=csv,noheader,nounits']).strip(),'GPU_BUSY'
save('maintenance-stopped.json',dict(channels=len(rows),services=['analytics','ai-control-sidecar','ai-gateway'],gpu_released=True))
print(json.dumps(dict(stopped=len(rows),targeted=len(targets),gpu_released=True,gateway='stopped')))
