"""Small explicit-schema demonstration; creates a new output bundle, never overwrites."""
import argparse, csv, hashlib, io, json, sys
from pathlib import Path
def unique(pairs):
    result={}
    for k,v in pairs:
        if k in result: raise ValueError('duplicate object key')
        result[k]=v
    return result
def constant(value): raise ValueError('nonstandard JSON constant')
def export(source, target):
    with Path(source).open('rb') as f: raw=f.read(1000001)
    if len(raw)>1000000: raise ValueError('demo input exceeds 1000000 bytes')
    rows=json.loads(raw.decode('utf-8'),object_pairs_hook=unique,parse_constant=constant)
    if not isinstance(rows,list): raise ValueError('top-level array required')
    matrix=[]
    for r in rows:
        if not isinstance(r,dict) or set(r)!={'id','text'}: raise ValueError('exact id/text schema required')
        values=[r['id'],r['text']]
        if not all(isinstance(v,str) for v in values): raise ValueError('string fields required')
        for v in values: v.encode('utf-8',errors='strict')
        matrix.append(values)
    stream=io.StringIO(newline=''); w=csv.writer(stream,lineterminator='\r\n')
    w.writerow(['id','text']); w.writerows(matrix)
    data=stream.getvalue().encode('utf-8')
    folder=Path(target); folder.mkdir() # existing path raises, including existing empty directory
    (folder/'source.json').write_bytes(raw)
    (folder/'values.csv').write_bytes(data)
    with (folder/'values.csv').open(encoding='utf-8',newline='') as f: recovered=list(csv.reader(f,strict=True))
    if recovered!=[['id','text']]+matrix: raise ValueError('field read-back mismatch')
    if (folder/'source.json').read_bytes()!=raw: raise ValueError('source copy mismatch')
    receipt={'python':sys.version.split()[0],'schema':['id','text'],'data_records':len(rows),'exact_field_readback':True,'files':{}}
    for name in ['source.json','values.csv']:
        b=(folder/name).read_bytes(); receipt['files'][name]={'bytes':len(b),'sha256':hashlib.sha256(b).hexdigest()}
    # Written last: a missing receipt means the bundle is incomplete.
    (folder/'receipt.json').write_text(json.dumps(receipt,indent=2),encoding='utf-8')
    return receipt
if __name__=='__main__':
    p=argparse.ArgumentParser(); p.add_argument('source'); p.add_argument('new_bundle_directory'); a=p.parse_args()
    try: print(json.dumps(export(a.source,a.new_bundle_directory)))
    except (ValueError,OSError,csv.Error,RecursionError) as e: p.exit(1,type(e).__name__+': '+str(e)+'\n')
