#!/usr/bin/env python3
"""Replay synthetic incident evidence. This validates a teaching record,not production authority."""
import argparse,json
from pathlib import Path

def replay(events):
    proposal=None;checks={};authorized=False;execution=None;outcome={};notes=[]
    for event in events:
        kind=event.get('kind')
        if kind=='proposal':
            proposal=event;checks={};authorized=False;execution=None;outcome={}
        elif kind=='check':checks[event['name']]=event['result']
        elif kind=='authorization':
            if not proposal or event.get('proposal_id')!=proposal.get('id') or event.get('scope')!=proposal.get('scope'):
                return {'state':'invalid record','reason':'Authorization does not match the current proposal and scope.'}
            authorized=True
        elif kind=='execution':
            if not authorized or not proposal or event.get('proposal_id')!=proposal.get('id'):
                return {'state':'invalid record','reason':'Execution lacks matching recorded authorization.'}
            missing=[name for name in proposal.get('required_checks',[]) if checks.get(name)!='pass']
            if missing:return {'state':'invalid record','reason':'Execution proceeded without required passing checks:'+','.join(missing)}
            execution=event.get('result');outcome={}
        elif kind=='verification':
            if execution is None:return {'state':'invalid record','reason':'Outcome was attached before an execution record.'}
            outcome.update(event.get('observations',{}))
        else:raise ValueError('Unknown event kind:'+str(kind))
    if not proposal:return {'state':'no proposal','reason':'No action is proposed in the record.'}
    missing=[name for name in proposal.get('required_checks',[]) if checks.get(name)!='pass']
    if missing:return {'state':'blocked on evidence','reason':'Required checks are not established:'+','.join(missing)}
    if not authorized:return {'state':'awaiting authorization','reason':'A proposal does not create permission.'}
    if execution is None:return {'state':'awaiting execution','reason':'Approval does not establish that the change ran.'}
    if execution=='timeout':return {'state':'execution unknown','reason':'Reconcile destination state before repeating the action.'}
    if execution!='accepted':return {'state':'execution failed','reason':'The operation did not report acceptance.'}
    if any(v=='fail' for v in outcome.values()):return {'state':'not recovered','reason':'At least one recorded service outcome fails.'}
    required=proposal.get('required_outcomes',['user_requests','backlog'])
    if all(outcome.get(k)=='pass' for k in required):return {'state':'verified in fixture','reason':'All required synthetic outcome checks pass;this is not a real recovery result.'}
    return {'state':'outcome unverified','reason':'Command acceptance leaves at least one required service result unknown.'}

if __name__=='__main__':
    parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('fixture_file');parser.add_argument('--self-test',action='store_true');args=parser.parse_args()
    fixtures=json.loads(Path(args.fixture_file).read_text())
    for fixture in fixtures:
        result=replay(fixture['events'])
        if args.self_test:assert result['state']==fixture['expected'],(fixture['name'],result)
        print(json.dumps({'case':fixture['name'],**result}))
    if args.self_test:print('All synthetic replay expectations passed.')
