"""Fetch bounded named originals on the reader computer; never redistribute them."""
from pathlib import Path
import argparse
import hashlib
import json
import urllib.request
from prepare_profiles import prepare_profiles


def fetch(output):
    manifest = json.loads(Path('source-manifest.json').read_text()); output.mkdir(parents=True, exist_ok=True)
    receipts = []
    for source in manifest['sources']:
        destination = output/source['name']; cached = destination.exists()
        if not cached:
            headers = {'User-Agent': 'SandboxPhysics-AC29-science/1', **source.get('headers', {})}
            request = urllib.request.Request(source['url'], headers=headers)
            with urllib.request.urlopen(request, timeout=60) as response:
                if int(response.headers.get('Content-Length', '0')) > source['bytes']:
                    raise ValueError('Origin response exceeds exact named size')
                if 'Range' in headers:
                    requested = headers['Range'].split('=', 1)[1]
                    if response.status != 206 or not response.headers.get('Content-Range', '').startswith('bytes '+requested+'/'):
                        raise ValueError('Origin ignored or changed the named byte range; refusing full archive')
                body = response.read(source['bytes']+1)
            if len(body) != source['bytes'] or hashlib.sha256(body).hexdigest() != source['sha256']:
                raise ValueError('Original response size/hash changed; review the source version')
            destination.write_bytes(body)
        body = destination.read_bytes()
        if len(body) != source['bytes'] or hashlib.sha256(body).hexdigest() != source['sha256']:
            raise ValueError('Corrupt original cache; refusing silent replacement')
        receipts.append({'name': source['name'], 'url': source['url'], 'bytes': len(body), 'sha256': source['sha256'],
                         'cached': cached, 'response_body_bytes': 0 if cached else len(body),
                         'role': source['role']})
    members = prepare_profiles(output)
    (output/'download-receipt.json').write_text(json.dumps({'responses': receipts, 'native_members': members}, indent=2)+'\n')
    print(json.dumps({'responses': receipts, 'native_members': members}, indent=2))


if __name__ == '__main__':
    parser = argparse.ArgumentParser(); parser.add_argument('--output', type=Path, default=Path('inputs')); arguments = parser.parse_args(); fetch(arguments.output)
