import copy
import hashlib
import json
import os
import time
import urllib.request
from prepare import HERE, REPO, api, cmd, compose, inspect, ledger, save, stopped

os.umask(0o077)
name = 'contextra-analytics-1'
sid = 'camera-c093c7f66edf595e953970de788efbaa'
before = json.loads((HERE/'before.json').read_text())
image = json.loads((HERE/'image.json').read_text())
intent = json.loads((HERE/'build-intent.json').read_text())
for p, h in intent['hashes'].items():
    assert hashlib.sha256((REPO/p).read_bytes()).hexdigest() == h
original = json.loads((HERE/'compose-before.json').read_text())
candidate = json.loads(cmd(compose()+['config', '--format', 'json']))
expected = copy.deepcopy(original)
expected['services']['analytics']['image'] = image['id']
assert candidate == expected, 'Unexpected compose change'
stopped()
assert inspect(name)['Id'] == before['containers'][name]['Id']
assert ledger() == before['ledger']
assert not before['ledger']['reservations']
save('reflect-intent.json', dict(target=name, image=image, channels='all stopped'))
try:
    cmd(['docker', 'stop', '--signal=SIGTERM', '--timeout=-1', name], timeout=90)
    assert not inspect(name)['State']['Running']
    print('ANALYTICS_STOPPED', flush=True)
    cmd(compose()+['up', '-d', '--no-deps', '--no-build', '--pull', 'never', 'analytics'], timeout=150)
    deadline = time.monotonic()+120
    while time.monotonic() < deadline:
        try:
            ready = api('/ready')
            break
        except Exception:
            time.sleep(2)
    else:
        raise RuntimeError('ANALYTICS_READINESS_TIMEOUT')
    stopped()
    url = 'http://127.0.0.1:35000/api/v1/streams/'+sid+'/settings'
    settings = api('/api/v1/streams/'+sid+'/settings')['configured']
    assert settings['fall']['person_score'] == .3
    assert settings['fall']['test_skip_down_hold'] is False
    request = urllib.request.Request(url, method='PATCH',
        data=json.dumps(dict(expected_revision=settings['revision'],
                             fall=dict(test_skip_down_hold=True))).encode(),
        headers={'Content-Type': 'application/json'})
    with urllib.request.urlopen(request, timeout=10) as response:
        assert response.status == 200
    configured = api('/api/v1/streams/'+sid+'/settings')['configured']
    expected_settings = copy.deepcopy(settings)
    expected_settings['fall']['test_skip_down_hold'] = True
    expected_settings.pop('revision')
    comparable = copy.deepcopy(configured)
    comparable.pop('revision')
    assert expected_settings == comparable
    model_script = 'import urllib.request;print(urllib.request.urlopen("http://localhost:8000/v2/models/RFDETRKeypointPreview/ready",timeout=3).status)'
    assert cmd(['docker','exec',name,'python3','-c',model_script]).strip() == '200'
    bridge_script = '''import os,json,urllib.request
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))))'''
    bridge = json.loads(cmd(['docker','exec','contextra-ai-control-sidecar-1','python3','-c',bridge_script]))
    assert bridge['wss'].get('connected') or bridge['wss'].get('active')
    artifacts = api('/api/v1/metadata/status')['artifacts']
    assert artifacts['enabled'] and artifacts['http_enabled']
    states = stopped()
    preservation = {}
    for n, old in before['containers'].items():
        if n == name:
            continue
        new = inspect(n)
        preservation[n] = (new['Id'] == old['Id'] and new['Image'] == old['Image']
                           and new['State']['StartedAt'] == old['State']['StartedAt'])
    assert all(preservation.values())
    assert ledger() == before['ledger']
    assert inspect(name)['Image'] == image['id']
    save('reflected.json', dict(image=image, channels_stopped=len(states), pose_ready=True,
         fall=configured['fall'], revision=configured['revision'], bridge=bridge,
         artifacts=artifacts, non_target_preserved=preservation, ledger_unchanged=True))
    print(json.dumps(dict(prepared=True, channels_stopped=len(states),
                          fall_score=configured['fall']['person_score'], option=True,
                          pose_ready=True, wss=True, artifact_on=True)), flush=True)
except Exception as exc:
    save('reflection-failed.json', dict(error=type(exc).__name__, reason=str(exc)[:160]))
    if inspect(name)['State']['Running']:
        cmd(['docker','stop','--signal=SIGTERM','--timeout=-1',name],timeout=90)
    raise
