"""Two-pass flat-record exporter. Requires ijson; input must remain unchanged.
python stream-json-csv.py input.json data.records.item new-output-directory
"""
import csv, hashlib, json, os, sys
from pathlib import Path
from decimal import Decimal
import ijson

def digest(path):
    h=hashlib.sha256()
    with path.open('rb') as f:
        for block in iter(lambda:f.read(1024*1024), b''): h.update(block)
    return h.hexdigest()

def records(path,prefix):
    with path.open('rb') as f:
        for row in ijson.items(f,prefix,use_float=False):
            if not isinstance(row,dict): raise ValueError('selected items must be objects')
            if any(isinstance(v,(dict,list)) for v in row.values()):
                raise ValueError('flat records only; choose a nested-data policy first')
            yield row

def cell(value):
    if value is None: return ''
    if isinstance(value,bool): return 'true' if value else 'false'
    return str(value)

def export(source,prefix,out):
    source=Path(source); out=Path(out)
    before=digest(source)
    columns={}; count=0
    for row in records(source,prefix):
        count+=1
        for key in row: columns.setdefault(key,None)
    if not count or not columns: raise ValueError('no exportable records; check prefix and input')
    out.mkdir(exist_ok=False)
    partial=out/'records.csv.partial'; written=0
    try:
        with partial.open('w',encoding='utf-8',newline='') as f:
            writer=csv.writer(f); writer.writerow(columns)
            for row in records(source,prefix):
                if not row.keys()<=columns.keys(): raise ValueError('schema changed between passes')
                writer.writerow([cell(row.get(key)) for key in columns]); written+=1
        after=digest(source)
        if before!=after or written!=count: raise ValueError('input changed; export not finalized')
        report={'status':'complete','records':written,'columns':list(columns),
                'source_sha256':after,'prefix':prefix,'ijson_version':ijson.__version__,
                'backend':ijson.backend,'policy':'flat values; missing/null -> empty; no spreadsheet sanitization'}
        os.replace(partial,out/'records.csv')
        (out/'manifest.json').write_text(json.dumps(report,indent=2)+'\n',encoding='utf-8')
        return report
    except Exception:
        # Keep partial output for diagnosis. Never treat it as a completed export.
        raise

if __name__=='__main__':
    print(json.dumps(export(*sys.argv[1:4])))
