"""Copy reviewed runs to NEW release files. Never overwrite or touch a live catalog."""
import argparse,json,hashlib,shutil
from pathlib import Path
from datetime import datetime
from zoneinfo import ZoneInfo

def sha(p):return hashlib.sha256(p.read_bytes()).hexdigest()
def deliver(runs,out,label):
 entries=[];rows=[];sources=[]
 for d in runs:
  v=json.loads((d/'verdict.json').read_text());e=json.loads((d/'catalog_entry.json').read_text())
  if not(v['shipped'] and v['numeric_pass'] and v['visual_verdict'] in ['GOOD','OK']):raise ValueError('Unapproved run: '+str(d))
  source=d/e['file']
  if sha(source)!=v['sha256'] or v['sha256']!=v['metrics']['candidate_sha256']:raise ValueError('Changed model: '+str(d))
  for name,digest in v['metrics']['evidence'].items():
   if sha(d/name)!=digest:raise ValueError('Changed render: '+name)
  entries.append(e);sources.append(source);rows.append({'file':e['file'],'sha256':v['sha256'],'run':str(d),'visual_verdict':v['visual_verdict'],'visual_note':v['visual_note'],'metrics':v['metrics']})
 names=[s.name for s in sources]+[f'catalog_entries_{label}.json',f'manifest_{label}.json']
 if len(set(names))!=len(names):raise ValueError('Duplicate output names')
 for name in names:
  if (out/name).exists():raise FileExistsError(out/name)
 out.mkdir(parents=True,exist_ok=True)
 for source in sources:
  with source.open('rb') as src,(out/source.name).open('xb') as dst:shutil.copyfileobj(src,dst)
 manifest={'written':datetime.now(ZoneInfo('Europe/Paris')).strftime('%Y-%m-%d %H:%M:%S CET'),'assets':rows,'live_integration':False}
 for name,obj in [(f'catalog_entries_{label}.json',entries),(f'manifest_{label}.json',manifest)]:
  with (out/name).open('x') as f:json.dump(obj,f,indent=2)
 return manifest
if __name__=='__main__':
 p=argparse.ArgumentParser(description=__doc__);p.add_argument('--run',action='append',type=Path,required=True);p.add_argument('--out',type=Path,required=True);p.add_argument('--label',required=True);a=p.parse_args()
 if not a.label.replace('-','').isalnum():p.error('label must be letters, numbers and hyphens')
 result=deliver(a.run,a.out,a.label);print(json.dumps({'released':[r['file'] for r in result['assets']],'out':str(a.out)}))
