"""Route a supplied report CSV. A CSV alone does not prove live provenance.
No network calls, database calls, external actions or automatic writes.
"""
import csv, hashlib, json, sys
from pathlib import Path

def blank(value):
    return value is None or value.strip().lower() in ('', 'null', '(null)', '<null>')

def optional_int(value):
    if blank(value): return None
    return int(value)

def read_rows(path):
    with Path(path).open(encoding='utf-8-sig', newline='') as f:
        reader=csv.DictReader(f)
        names=reader.fieldnames or []
        normalized=[x.split('.')[-1].strip('" ') for x in names]
        if len(normalized)!=len(set(normalized)) or not set(REQUIRED).issubset(normalized):
            raise ValueError('Missing or ambiguous report columns')
        rows=[]; seen=set()
        for raw in reader:
            if None in raw: raise ValueError('CSV row has extra fields')
            row={new:raw[old] for old,new in zip(names,normalized)}
            if any(row[k] is None for k in REQUIRED): raise ValueError('CSV row has missing fields')
            key=row[KEY]
            if blank(key) or key in seen: raise ValueError('Missing or duplicate report key')
            seen.add(key); rows.append(row)
    if not rows: raise ValueError('Empty report cannot verify this fixture')
    return rows

def route(path):
    path=Path(path)
    return {'input_sha256':hashlib.sha256(path.read_bytes()).hexdigest(),
            'source':'Supplied CSV; link actual console export evidence separately',
            'database_provenance_verified':False, 'external_actions_sent':False,
            'result':transform(read_rows(path))}

REQUIRED=['order_id', 'supplier_id', 'ordered_qty', 'receipt_order_id', 'received_qty', 'registered_supplier', 'receipt_state', 'supplier_state']
KEY='order_id'

def transform(rows):
    result=[]
    owners={'receipt_follow_up':'Receiving','excess_review':'Order owner','short_receipt_review':'Receiving','supplier_validation':'Supplier review'}
    for row in sorted(rows,key=lambda x:x['order_id']):
        qty=optional_int(row['ordered_qty']); received=optional_int(row['received_qty'])
        if qty is None or qty<0: raise ValueError('Ordered quantity must be a nonnegative integer')
        absent=blank(row['receipt_order_id'])
        if absent:
            if received is not None: raise ValueError('Absent receipt has a quantity')
            receipt='receipt_follow_up'
        else:
            if row['receipt_order_id']!=row['order_id'] or received is None or received<0:
                raise ValueError('Receipt grain or quantity does not match the order')
            receipt='excess_review' if received>qty else 'short_receipt_review' if received<qty else 'balanced'
        supplier='supplier_validation' if blank(row['registered_supplier']) else 'recognized'
        if supplier=='recognized' and row['registered_supplier']!=row['supplier_id']:
            raise ValueError('Supplier reference does not match')
        if row['receipt_state']!=receipt or row['supplier_state']!=supplier:
            raise ValueError('Report classification disagrees with source values')
        reasons=[] if receipt=='balanced' else [receipt]
        if supplier=='supplier_validation': reasons.append(supplier)
        if reasons: result.append({'order_id':row['order_id'],'reasons':reasons,'owners':[owners[r] for r in reasons]})
    return result

if __name__=='__main__':
    if len(sys.argv)!=2: raise SystemExit('Usage: python route-export.py report.csv')
    try: print(json.dumps(route(sys.argv[1]),indent=2))
    except (ValueError,KeyError): raise SystemExit('Report failed the declared CSV contract; inspect the source fields.')
