"""Prepare complete ordinary component assets and a browsable local source/notice index."""
from pathlib import Path
import hashlib,json,shutil,html
from urllib.parse import quote
b=Path(__file__).parent;u=json.loads((b/'unit-content-manifest.json').read_text());paths=set()
for row in u['records']:
 p=b/row['path']
 if not p.name.endswith(('.wasm','.wasm.gz')):paths.add(p)
for name in ['unit-identity.js','unit-content-manifest.json','CONTRACT-0.3.md','README-CURRENT.md','freeze_identity.py','build_source_notices.py','make_runtime_gzip.py']:paths.add(b/name)
for folder in ['vendor/6over3-zeroperl-ts','vendor/uswriting-exiftool','runtime-build']:
 for p in (b/folder).rglob('*'):
  if not p.is_file() or p.is_symlink() or p.name.endswith(('.wasm','.wasm.gz')) or '__pycache__' in p.parts:continue
  if folder=='runtime-build' and ('stage' in p.relative_to(b/'runtime-build').parts or 'debs' in p.relative_to(b/'runtime-build').parts or p.name in ['wasi-sdk-27.0-arm64-linux.tar.gz','binaryen-version_124-aarch64-linux.tar.gz','source-notices-bundle-proof.json','source-distribution-proof.json'] or p.name.endswith('.partial')):continue
  paths.add(p)
rows=[{'path':p.relative_to(b).as_posix(),'bytes':p.stat().st_size,'sha256':hashlib.sha256(p.read_bytes()).hexdigest()}for p in sorted(paths)]
manifest=json.dumps({'schema':1,'version':'0.3.7','unitId':u['unitId'],'purpose':'Complete ordinary corresponding-source/license/attribution assets; no publication, host route choice or legal certification','excluded':'Runtime binaries, official compiler executables and Debian .debs; exact source/input/reproduction receipts retained. No source/license/attribution material from the previous version is dropped.','files':rows},indent=2)+'\n'
out=b.parent/'photo-engine-source-notices-0.3.7';out.mkdir(exist_ok=False)
for p in sorted(paths):
 dest=out/p.relative_to(b);dest.parent.mkdir(parents=True,exist_ok=True);shutil.copyfile(p,dest)
(out/'FILE-MANIFEST.json').write_text(manifest)
links='\n'.join('<tr><td><a href="'+quote(r['path'])+'">'+html.escape(r['path'])+'</a></td><td>'+str(r['bytes'])+'</td><td><code>'+r['sha256']+'</code></td></tr>'for r in rows)
index='<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Photo engine 0.3.7 source and notices</title><body><h1>Photo engine 0.3.7 — source and notices</h1><p>Complete versioned component distributions, declared terms, attribution, readable modified sources and reproduction material. Prepared locally for review; public availability remains the deployment owner’s release step. No legal certification.</p><p><a href="FILE-MANIFEST.json">Exact byte/hash manifest</a> · <a href="runtime-build/SOURCE-NOTICES-SHIPPING.md">Shipping requirements</a> · <a href="runtime-build/COMPONENTS.md">Component inventory</a></p><p>Unit '+html.escape(u['unitId'])+'</p><table><thead><tr><th>Material</th><th>Bytes</th><th>SHA-256</th></tr></thead><tbody>'+links+'</tbody></table></body></html>\n'
(out/'index.html').write_text(index)
proof={'path':str(out.resolve()),'fileManifestSha256':hashlib.sha256(manifest.encode()).hexdigest(),'indexSha256':hashlib.sha256(index.encode()).hexdigest(),'files':len(rows),'largestFile':max(rows,key=lambda r:r['bytes']),'unitId':u['unitId']}
(b/'runtime-build/source-distribution-proof.json').write_text(json.dumps(proof,indent=2)+'\n');print(json.dumps(proof,indent=2))
