#!/usr/bin/env python3
"""Rebuild the exact archived source inputs of this distribution. Python >=3.12, Docker, npm.
Run in this directory after downloading both source/ archives and provenance.json.
Outputs go to a new directory, never into Agent Zoo's application or live assets.
"""
import hashlib
import importlib.util
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tarfile
import tempfile

HERE = Path(__file__).resolve().parent
manifest = json.loads((HERE / 'provenance.json').read_text())
work = Path(tempfile.mkdtemp(prefix='libavoid-rebuild-'))
for name in ['libavoid-js-5062a42.tar.gz', 'adaptagrams-e611668.tar.gz']:
    path = HERE / 'source' / name
    assert hashlib.sha256(path.read_bytes()).hexdigest() == manifest['sha256']['source/' + name], name
    with tarfile.open(path) as archive:
        archive.extractall(work, filter='data')
source = work / ('libavoid-js-' + manifest['bindingCommit'])
(source / 'build').mkdir(exist_ok=True)
shutil.move(str(work / ('adaptagrams-' + manifest['adaptagramsCommit'])), source / 'build/adaptagrams')
patch = HERE / 'source/embind-route-validation.patch'
assert hashlib.sha256(patch.read_bytes()).hexdigest() == manifest['sha256']['source/embind-route-validation.patch']
subprocess.run(['patch', '-p1', '-i', str(patch)], cwd=source, check=True)
# Use upstream production compiler options with a pinned image, not its full-rebuild
# entry point (which would download a moving tag and also build debug/node).
sys.path.insert(0, str(source / 'tools'))
spec = importlib.util.spec_from_file_location('generate', source / 'tools/generate.py')
generate = importlib.util.module_from_spec(spec)
spec.loader.exec_module(generate)
execute = generate.execute_command
def pinned_compiler(command, *args, **kwargs):
    command = command.replace('docker run', 'docker run --platform linux/amd64')
    command = command.replace('emscripten/emsdk:4.0.7', manifest['toolchainImage'])
    return execute(command, *args, **kwargs)
generate.execute_command = pinned_compiler
os.chdir(source / 'build')
generate.compile(None, 'dist_web', debug=False, environment='web')
for name in ['libavoid.js', 'libavoid.wasm']:
    shutil.copyfile(source / 'build/dist_web' / name, source / 'src/generated' / name)
subprocess.run(['npm', 'ci', '--ignore-scripts', '--no-audit', '--no-fund'], cwd=source, check=True)
subprocess.run(['npx', '--no-install', 'esbuild', 'src/index.js', '--bundle', '--sourcemap', '--minify', '--splitting', '--format=esm', '--platform=browser', '--external:module', '--outdir=replacement'], cwd=source, check=True)
shutil.copyfile(source / 'src/generated/libavoid.wasm', source / 'replacement/libavoid.wasm')
for name in ['index.js', 'index.js.map', 'libavoid.wasm']:
    actual = hashlib.sha256((source / 'replacement' / name).read_bytes()).hexdigest()
    print(name, actual, 'matches distributed library:', actual == manifest['sha256'][name])
print('Replacement library:', source / 'replacement')
