"""Bind actual deployed before/after captures to immutable, unscaled reviewer inputs."""
import datetime, hashlib, json
from pathlib import Path
from PIL import Image, ImageDraw

root = Path(__file__).resolve().parents[1]
fresh = json.loads((root/'evidence/inspection-post-v2/inspection-manifest.json').read_text())
before = json.loads((root/'evidence/daily-visual-fix-before-inventory.json').read_text())
original = json.loads((root/'evidence/inspection-post/inspection-manifest.json').read_text())['records']
media = json.loads((root/'manifests/media.json').read_text())['assets']
def sha(file): return hashlib.sha256(Path(file).read_bytes()).hexdigest()
def key(row): return (row['asset_id'],row['viewport']['width'],row['source_kind'],row.get('state'),row['name'])

for tag, days in [('b1',[7,9]),('b2',[12,13])]:
    dest=root/'evidence'/f'luna-recovery-{tag}-inputs'
    assert not (dest/'fresh-fix-READY.json').exists()
    ids={f'day-{n:02d}' for n in days}|{f'rita-{n:02d}' for n in days}
    after=[dict(r,capture_build='b3f6da18',comparison_revision='deployed-after') for r in fresh['records'] if r['asset_id'] in ids]
    old=[]
    for r in before['capture_contexts']:
        if r['asset_id'] not in ids: continue
        source=original[r['record_index']]
        assert source['sha256']==r['sha256']
        old.append(dict(source,capture_build='384162de',comparison_revision='deployed-before'))
    records=old+after
    unique={}
    for r in records:
        assert sha(r['file'])==r['sha256']
        unique.setdefault(r['sha256'],[]).append(r)
    entries=list(unique.items()); sheets=[]
    for start in range(0,len(entries),4):
        batch=entries[start:start+4]
        images=[Image.open(rows[0]['file']).convert('RGB') for h,rows in batch]
        width=max(im.width for im in images); height=max(im.height for im in images)
        canvas=Image.new('RGB',(2*width,2*height+64),'#172638'); draw=ImageDraw.Draw(canvas); tiles=[]
        for pos,((h,rows),im) in enumerate(zip(batch,images)):
            x=pos%2*width; y=64+pos//2*height; box=[x,y,x+im.width,y+im.height]
            canvas.paste(im,(x,y)); draw.text((pos%2*width+5,5+pos//2*24),rows[0]['asset_id']+' '+h[:12],fill='white')
            assert canvas.crop(box).tobytes()==im.tobytes()
            tiles.append(dict(sha256=h,bbox=box,source_file=rows[0]['file'],aliases=rows))
        file=dest/f'fresh-fix-sheet-{len(sheets)+1:04d}.png'; canvas.save(file)
        decoded=Image.open(file).convert('RGB')
        for tile in tiles: assert decoded.crop(tile['bbox']).tobytes()==Image.open(tile['source_file']).convert('RGB').tobytes()
        sheets.append(dict(file=str(file),pixels=list(canvas.size),native_pixels_unscaled=True,tiles=tiles))
    native=[]
    for asset in media:
        correction=asset.get('correction')
        if asset['category']!='daily' or asset['day'] not in days or not isinstance(correction,dict) or correction.get('revision')!='daily-visual-v2': continue
        for revision,file,url,h in [
            ('source-before',root/'private/daily-visual-v2-restore'/Path(asset['file']).name,correction['original_public_path'],correction['old_sha256']),
            ('source-after',root/'site'/asset['file'],asset['file'],asset['sha256'])]:
            assert sha(file)==h
            im=Image.open(file)
            native.append(dict(asset_id=asset['id'],revision=revision,source_file=str(file),url='https://review.clientsflow.hu/komplex-journey-2026-10-02-v1/'+url,sha256=h,pixels=dict(width=im.width,height=im.height),capture_basis='Native imagegen source original, not a customer CSS viewport screenshot',module=asset['module'],source_binding=asset['source']))
    lookup={key(r):r for r in after}; pairs=[]
    for r in old:
        if key(r) not in lookup: continue
        a=lookup[key(r)]
        pairs.append(dict(asset_id=r['asset_id'],viewport=r['viewport'],state=r.get('state'),section=r.get('sectionLabel'),before_sha256=r['sha256'],after_sha256=a['sha256'],before_file=r['file'],after_file=a['file'],before_url=r['url'],after_url=a['url'],before_build='384162de',after_build='b3f6da18',before_scroll=r.get('actualScroll',r.get('actual_scroll')),after_scroll=a.get('actualScroll',a.get('actual_scroll'))))
    value=dict(generated_at=datetime.datetime.now(datetime.timezone.utc).isoformat(),phase='Fresh actual published post-correction captures. Blind notes before source/rubric comparison. No expected verdict supplied.',days=days,published_build='b3f6da18',actual_after_capture_contexts=len(after),actual_before_capture_contexts=len(old),records=records,unique_pixel_hashes=len(unique),mobile_sheets=sheets,native_visual_source_references=native,comparison_pairs=pairs,full_page_references=[r for r in fresh['full_page_references'] if r['asset_id'] in ids],full_references_are_not_readable_evidence=True,archives=fresh['archives'],actual_independent_observations_attached=False)
    temp=dest/'fresh-fix-inputs.tmp'; temp.write_text(json.dumps(value,ensure_ascii=False,indent=2)+'\n'); temp.replace(dest/'fresh-fix-inputs.json')
    ready=dict(ready_at=datetime.datetime.now(datetime.timezone.utc).isoformat(),manifest_sha256=sha(dest/'fresh-fix-inputs.json'),all_source_hashes_verified=True,actual_after_contexts=len(after),actual_before_contexts=len(old),unique_pixel_hashes=len(unique),native_source_references=len(native),blind_phase_expected_verdict_supplied=False)
    temp=dest/'fresh-fix-READY.tmp'; temp.write_text(json.dumps(ready,indent=2)+'\n'); temp.replace(dest/'fresh-fix-READY.json')
    print(json.dumps(dict(partition=tag,**ready)))
