"""Task-owned package builder and explicit stage runner; never auto-deploy."""
import ast
import base64
import difflib
import hashlib
import importlib.util
import io
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tarfile

ROOT=Path(__file__).resolve().parent
REPO=Path('/workspace/contextra-analytics-runtime-lifecycle-refactor')
PRIOR=ROOT.parent/'2026-11-01_icerti-fall-r2_r01'
REMOTE='/storage/contextra/maintenance/fall-r2-public-config-20261102-r01'
os.umask(0o077)
sp=importlib.util.spec_from_file_location('remote',ROOT.parent/'2026-11-01_icerti-fight-r5_r01/remote.py')
r=importlib.util.module_from_spec(sp);sp.loader.exec_module(r)


def site_source(name,text):
    if name=='app/fall_runtime.py':
        text=text.replace('direct_down_cooldown_seconds=None, contains=None):','direct_down_cooldown_seconds=None):')
        text=text.replace('        self.contains = contains\n','')
        text=text.replace('self.config=config;self.contains=contains;self._events={}','self.config=config;self._events={}')
        text=text.replace('R2Runtime(config,event_id_factory,wall_ns,contains)','R2Runtime(config,event_id_factory,wall_ns)')
        text=text.replace('selected = tuple(i for i, point in enumerate(points)\n                         if (self.contains(point) if self.contains else inside(point, self.config.roi)))',
                          'selected = tuple(i for i, point in enumerate(points) if inside(point, self.config.roi))')
    elif name=='app/stream_settings.py':
        block="    if spec.get('multi_roi') and set(changes) & {'intrusion','loitering','fall','fight','crowd','fire','pose'}:\n        from app.multi_roi.errors import RoiError\n        raise RoiError('MULTI_ROI_SETTINGS_OWNED')\n"
        assert text.count(block)==1;text=text.replace(block,'')
    return text


def package():
    data=json.loads((ROOT/'preflight.json').read_text());pkg=ROOT/'package';pkg.mkdir(mode=0o700)
    before={};after={};diffs=[];source_sha={}
    for name,encoded in data['files'].items():
        raw=base64.b64decode(encoded);old=raw.decode()
        head=subprocess.check_output(['git','show','HEAD:'+name],cwd=REPO,text=True)
        assert site_source(name,head)==old,name
        src=(REPO/name).read_text();text=site_source(name,src);ast.parse(text)
        dest=pkg/'payload'/name;dest.parent.mkdir(parents=True,exist_ok=True);dest.write_text(text)
        before[name]=hashlib.sha256(raw).hexdigest();after[name]=hashlib.sha256(dest.read_bytes()).hexdigest()
        source_sha[name]=hashlib.sha256((REPO/name).read_bytes()).hexdigest()
        diffs.extend(difflib.unified_diff(old.splitlines(True),text.splitlines(True),fromfile=name+'.before',tofile=name))
    manifest=dict(server='icerti-ai2',images=data['images'],before=before,after=after,guards=data['guards'],
                  config_sha256={k:v['sha256'] for k,v in data['configs'].items()},development_source_sha256=source_sha)
    (pkg/'manifest.json').write_text(json.dumps(manifest,indent=2));(ROOT/'site.patch').write_text(''.join(diffs))
    for name in ('artifact_install.py','trace_install.py'):shutil.copy2(REPO/'tools/icerti_offline'/name,pkg/name)
    p=pkg/'artifact_install.py';text=p.read_text();old="['docker','run','--rm','--pull=never','--name'"
    assert text.count(old)==1;p.write_text(text.replace(old,"['docker','run','--rm','--runtime=runc','--pull=never','--name'"))
    shutil.copy2(PRIOR/'install.py',pkg/'prior_install.py')
    for name in ('install.py','settings_migrate.py','test_migration.py','test_runner.py','replay.py'):
        shutil.copy2(ROOT/name,pkg/name)
    shutil.copy2(ROOT/'settings_migrate.py',pkg/'fall_r2_settings.py')
    for name in ('app','tests','control_sidecar','contextra_trace','configs/control_templates'):
        shutil.copytree(REPO/name,pkg/'source'/name,ignore=shutil.ignore_patterns('__pycache__','*.pyc'))
    shutil.copytree(REPO/'tests',pkg/'tests',ignore=shutil.ignore_patterns('__pycache__','*.pyc'))
    runtime=Path('/data/codex-artifacts/contextra/action-model-eval/2026/2026-11-01_contextra-fall-r2-runtime_r01')
    for name in ('specs.json','self_maps.json'):shutil.copy2(runtime/name,pkg/name)
    stream=io.BytesIO()
    with tarfile.open(fileobj=stream,mode='w:gz') as archive:archive.add(pkg,arcname='.')
    blob=stream.getvalue();digest=hashlib.sha256(blob).hexdigest();incoming='/home/si/fall-r2-public-config-20261102-r01.tar.gz'
    r.run(['python3','-c','import sys;from pathlib import Path;p=Path('+repr(incoming)+');assert not p.exists();p.write_bytes(sys.stdin.buffer.read());p.chmod(0o600)'],payload=blob)
    r.python('import hashlib,tarfile;from pathlib import Path;p=Path('+repr(incoming)+');assert hashlib.sha256(p.read_bytes()).hexdigest()=='+repr(digest)+';d=Path('+repr(REMOTE)+');assert not d.exists();d.mkdir(mode=0o700);tarfile.open(p).extractall(d,filter="data")',sudo=True)
    (ROOT/'transfer.json').write_text(json.dumps(dict(sha256=digest,bytes=len(blob),remote=REMOTE),indent=2))
    print('PACKAGE_TRANSFER_PASS',len(after),len(blob))


if __name__=='__main__':
    action=sys.argv[1]
    if action=='package':package()
    elif action=='send-baseline':
        blob=subprocess.check_output(['git','archive','HEAD','app','tests','control_sidecar','contextra_trace','configs/control_templates'],cwd=REPO)
        incoming='/home/si/fall-r2-config-baseline-20261102-r01.tar'
        r.run(['python3','-c','import sys;from pathlib import Path;p=Path('+repr(incoming)+');assert not p.exists();p.write_bytes(sys.stdin.buffer.read());p.chmod(0o600)'],payload=blob)
        r.python('import hashlib,tarfile;from pathlib import Path;p=Path('+repr(incoming)+');assert hashlib.sha256(p.read_bytes()).hexdigest()=='+repr(hashlib.sha256(blob).hexdigest())+';d=Path('+repr(REMOTE+'/baseline-dev')+');assert not d.exists();d.mkdir(mode=0o700);tarfile.open(p).extractall(d,filter="data")',sudo=True)
        print('BASELINE_HEAD_TRANSFER_PASS')
    elif action=='sync-helpers':
        files={name:base64.b64encode((ROOT/name).read_bytes()).decode() for name in ('install.py','test_runner.py','baseline_tests.py')}
        for target in ('tests/test_fall_r2_config.py','source/tests/test_fall_r2_config.py'):
            files[target]=base64.b64encode((REPO/'tests/test_fall_r2_config.py').read_bytes()).decode()
        code='''import base64,json,shutil,time,hashlib
from pathlib import Path
root=Path(ROOT);files=FILES;changes=[];archive=root/'helper-revisions'/str(time.time_ns())
for name,value in files.items():
 p=root/name;raw=base64.b64decode(value)
 if p.exists() and p.read_bytes()==raw:continue
 if p.exists():
  old=archive/name;old.parent.mkdir(parents=True,exist_ok=True);shutil.copy2(p,old)
 p.write_bytes(raw)
 changes.append(dict(path=name,sha256=hashlib.sha256(raw).hexdigest()))
print(json.dumps(changes))
'''.replace('Path(ROOT)','Path('+repr(REMOTE)+')').replace('files=FILES','files='+repr(files))
        out=r.python(code,sudo=True,timeout=30);(ROOT/'helper-sync.json').write_bytes(out);print(out.decode())
    elif action=='pull':
        code='''import tarfile,io,sys
from pathlib import Path
root=Path(ROOT);buffer=io.BytesIO()
with tarfile.open(fileobj=buffer,mode='w:gz') as a:
 for p in sorted(root.iterdir()):
  if p.is_file() and (p.suffix in ('.json','.log') or p.name=='site.patch'):a.add(p,arcname=p.name)
 for name in ('baseline','settings-before','settings-after','replay-results','test-history','helper-revisions'):
  p=root/name
  if p.exists():a.add(p,arcname=name)
sys.stdout.buffer.write(buffer.getvalue())
'''.replace('Path(ROOT)','Path('+repr(REMOTE)+')')
        blob=r.python(code,sudo=True,timeout=60);dest=ROOT/'evidence';dest.mkdir(mode=0o700,exist_ok=True)
        archive=ROOT/'evidence.tar.gz'
        if archive.exists():raise ValueError('PRESERVE_EXISTING_EVIDENCE')
        archive.write_bytes(blob)
        with tarfile.open(fileobj=io.BytesIO(blob),mode='r:gz') as a:a.extractall(dest,filter='data')
        print('EVIDENCE_TRANSFER_SHA256',hashlib.sha256(blob).hexdigest())
    else:
        assert action in ('prepare','dev','baseline','build','test','replay','activate','verify')
        try:
            out=r.run(['python3',REMOTE+'/install.py',REMOTE,'icerti-ai2',action],sudo=True,timeout=750)
            (ROOT/(action+'.log')).write_bytes(out);print(out.decode()[-3000:])
        except Exception as error:
            path=ROOT/(action+'-failed.log');path.write_text(str(error));raise
