#!/usr/bin/env python3
import json, sys

def validate(read, submitted):
    offered = read.get('ack_cursor')
    if not isinstance(offered, dict) or not all(k in offered for k in ('version','timestamp','comments','mentions')):
        return False, 'missing_or_malformed_offer'
    if submitted is None:
        return True, 'no_ack_requested'
    if submitted != offered:
        return False, 'submitted_cursor_is_not_this_read_offer'
    return True, 'accepted_exact_singleton_offer'

def batch_validate(reads, submitted):
    offers=[]
    for r in reads:
        o=r.get('ack_cursor')
        if not isinstance(o,dict) or not all(k in o for k in ('version','timestamp','comments','mentions')):
            return False, 'missing_or_malformed_offer'
        offers.append(o)
    if submitted is None: return True, 'no_ack_requested'
    expected={k:min(o[k] for o in offers) for k in ('version','timestamp','comments','mentions')}
    # version is not a watermark; all processed reads must agree on it.
    if len({o['version'] for o in offers}) != 1: return False, 'offer_versions_disagree'
    if submitted != expected: return False, 'submitted_cursor_is_not_minimum_of_processed_offers'
    return True, 'accepted_batch_minimum_offer'

def main():
    cases=json.load(open(sys.argv[1]))
    out=[]
    for c in cases:
        if c['kind']=='singleton': ok,reason=validate(c['read'],c.get('submitted'))
        else: ok,reason=batch_validate(c['reads'],c.get('submitted'))
        out.append({'name':c['name'],'ok':ok,'reason':reason,'expected': (c['read'].get('ack_cursor') if c['kind']=='singleton' else {k:min(r['ack_cursor'][k] for r in c['reads']) for k in ('version','timestamp','comments','mentions')})})
    print(json.dumps({'cases':out,'passed':sum(x['ok'] for x in out),'total':len(out)},sort_keys=True))
    return 0 if all(x['ok'] for x in out) else 1
if __name__=='__main__': raise SystemExit(main())
