"""Assemble the bounded public study materials and web-only evidence directory."""
import argparse
import json
from pathlib import Path
import shutil

from provider import dump
from publish_evidence import make_manifest,zip_tree,h,SUSPICIOUS

ROOT=Path(__file__).resolve().parent
FILES=['.gitattributes','requirements.lock.txt','pytest.ini','experiment.py','provider.py','a2a_harness.py','agent-instructions.txt','analysis.py','replication_analysis.py','outcomes_detail.py','verify_evidence.py','check_adjudication.py','review_inventory.py','reproduce.py','rebuild_analysis.py','figures.py','report_generator.py','render_manuscript.py','publish_evidence.py','split_evidence.py','download_evidence.py','package_materials.py','test_research.py','test_evidence.py','test_distribution.py','probe_models.py','RESEARCH-PLAN.md','PILOT-PROTOCOL.md','REPLICATION-PROTOCOL.md','RESEARCH-JOURNAL.md','harness-provenance.json']
FILES+=['runtime_followup.py','followup_analysis.py','test_runtime_followup.py','FOLLOWUP-PROTOCOL.md','record_review.py','audit_release.py','read_host_power.ps1','capture_environment.py']


def copy_checked(src,dst):
 data=src.read_bytes()
 if any(pattern.search(data) for pattern in SUSPICIOUS):raise RuntimeError('Potential credential in materials: '+str(src))
 dst.parent.mkdir(parents=True,exist_ok=True);dst.write_bytes(data)


def materials(export):
 export=Path(export);folder=export/'packages'/'study-materials';folder.mkdir(parents=True,exist_ok=False)
 for name in FILES:copy_checked(ROOT/name,folder/name)
 for src in ROOT.glob('engineering-*.xml'):copy_checked(src,folder/src.name)
 for directory in ['protocols','analysis','adjudications','publication']:
  for src in sorted((ROOT/directory).rglob('*')):
   if src.is_file() and '__pycache__' not in src.parts:
    copy_checked(src,folder/src.relative_to(ROOT))
 copy_checked(ROOT/'output/pdf/a2a-capability-asymmetry.pdf',folder/'publication/manuscript.pdf')
 guide=(ROOT/'publication/evidence-README.md').read_text(encoding='utf-8')
 guide+='\n\n## Rebuild all derived tables and figures\n\nUnpack this materials archive and both raw-evidence archives into separate directories. Then, from the materials directory, run:\n\n```sh\npython reproduce.py\npython -m pip install -r requirements.lock.txt\npython rebuild_analysis.py --pilot ../pilot/runs/pilot --replication ../replication/runs/replication --out rebuilt-analysis\n```\n\nAdjust the two paths to your extracted bundles. This recomputes episode tables, primary contrasts, detailed accounting, mechanical checks of the published analyst annotations, and figures; it makes no model calls. It does not independently reproduce the semantic judgment of proposal/acceptance. The PDF renderer additionally uses ReportLab 4.4.9; its output is supplied, while all scientific estimates are in the machine-readable tables. Files in protocols/*/source preserve the prospectively frozen engine; top-level publication and analysis helpers document subsequent analysis and export work. The unexecuted pilot-v1 plan and unsuccessful test-collection report are intentionally retained.\n'
 guide=guide.replace('both raw-evidence archives','the pilot, replication and followup raw-evidence archives').replace('--replication ../replication/runs/replication --out','--replication ../replication/runs/replication --followup ../followup/runs/followup --out').replace('Adjust the two paths','Adjust the three paths')
 (folder/'README.md').write_text(guide,encoding='utf-8')
 dump(folder/'MANIFEST.json',make_manifest(folder))
 archive=export/'study-materials.zip';zip_tree(folder,archive)
 index=json.loads((export/'experiment-index.json').read_text(encoding='utf-8'))
 if any(b['phase']=='study-materials' for b in index['bundles']):raise RuntimeError('Materials already indexed')
 index['bundles'].append({'phase':'study-materials','filename':archive.name,'sha256':h(archive),'bytes':archive.stat().st_size})
 dump(export/'experiment-index.json',index)
 print(json.dumps(index['bundles'][-1]))


def web_assets(export,out):
 export=Path(export);out=Path(out);out.mkdir(parents=True,exist_ok=False)
 downloads=json.loads((export/'DOWNLOADS.json').read_text(encoding='utf-8'))
 names=['experiment-index.json','DOWNLOADS.json','download_evidence.py']+[f['filename'] for b in downloads['bundles'] for f in b['download_files']]
 for name in names:copy_checked(export/name,out/name)
 for src in (export/'episodes').glob('*.json'):copy_checked(src,out/'episodes'/src.name)
 for directory in ['analysis','adjudications']:
  for src in (ROOT/directory).rglob('*'):
   if src.is_file():copy_checked(src,out/src.relative_to(ROOT))
 for src in (ROOT/'publication/figures').glob('*'):
  if src.is_file():copy_checked(src,out/'figures'/src.name)
 for name in ['publication-data.json','manuscript.md','report-ja.md','source-ledger.md']:copy_checked(ROOT/'publication'/name,out/name)
 for name in ['RESEARCH-PLAN.md','PILOT-PROTOCOL.md','REPLICATION-PROTOCOL.md','FOLLOWUP-PROTOCOL.md','RESEARCH-JOURNAL.md']:copy_checked(ROOT/name,out/name)
 copy_checked(ROOT/'publication/evidence-README.md',out/'README.md')
 copy_checked(ROOT/'output/pdf/a2a-capability-asymmetry.pdf',out/'manuscript.pdf')
 if any(p.stat().st_size>25*1024*1024 for p in out.rglob('*') if p.is_file()):raise RuntimeError('Cloudflare individual asset limit exceeded')
 # Only actual served files belong here, never private packages or full oversized ZIPs.
 dump(out/'FILE-HASHES.json',make_manifest(out))
 print(json.dumps({'files':sum(p.is_file() for p in out.rglob('*')),'bytes':sum(p.stat().st_size for p in out.rglob('*') if p.is_file())}))


if __name__=='__main__':
 ap=argparse.ArgumentParser();ap.add_argument('export');ap.add_argument('--web-out');args=ap.parse_args()
 if args.web_out:web_assets(args.export,args.web_out)
 else:materials(args.export)
