"""Deterministic classroom controller. Local only; no external actions or AI calls."""
import argparse,json,pathlib,sys
ALLOWED={'lookup_policy','create_local_draft'}
class DraftLedger:
    def __init__(self): self.entries={}
    def create(self,request_id,text,source_id):
        key=request_id+':draft:v1'
        if key not in self.entries:self.entries[key]={'draft_id':'D-'+request_id+'-v1','text':text,'source_id':source_id}
        return self.entries[key]
def run_case(request,ledger):
    state='RECEIVED';events=[];draft=None
    def event(action,result):events.append({'sequence':len(events)+1,'action':action,'result':result})
    event('receive',state)
    if request.get('action','lookup_policy') not in ALLOWED:
        event('permission_check','DENIED');return {'id':request['id'],'state':'DENIED','events':events,'draft':None}
    route=request['route']
    if route not in ('FAQ','BILLING','UNKNOWN'):route='UNKNOWN'
    event('route',route)
    if route!='FAQ':
        event('escalate','NEEDS_REVIEW');return {'id':request['id'],'state':'NEEDS_REVIEW','events':events,'draft':None}
    event('transition','ROUTED');source=None
    for attempt in range(1,3):
        fails=request.get('timeout')=='always' or (request.get('timeout')=='once' and attempt==1)
        if fails:event('lookup_policy',{'attempt':attempt,'error':'timeout'});continue
        source={'source_id':'P-V1','text':'The workshop takes place in Room 2.'}
        if request.get('malformed'):source.pop('source_id')
        event('lookup_policy',{'attempt':attempt,'source_id':source.get('source_id')});break
    if not source or not isinstance(source.get('source_id'),str) or not source['source_id']:
        event('validate_source','NEEDS_REVIEW');return {'id':request['id'],'state':'NEEDS_REVIEW','events':events,'draft':None}
    draft=ledger.create(request['id'],source['text'],source['source_id']);event('create_local_draft',draft['draft_id']);event('transition','DRAFTED');state='WAITING_APPROVAL';event('transition',state)
    approved=request.get('approved_draft_id')
    if approved==draft['draft_id']:state='COMPLETE';event('approve_exact_draft',state)
    return {'id':request['id'],'state':state,'events':events,'draft':draft}
def main():
    parser=argparse.ArgumentParser();parser.add_argument('--output',default='sandbox_results.json');args=parser.parse_args()
    fixtures=[{'id':'normal','route':'FAQ','approved_draft_id':'D-normal-v1'}, {'id':'waiting','route':'FAQ'}, {'id':'billing','route':'BILLING'}, {'id':'unknown','route':'UNKNOWN'}, {'id':'denied','route':'FAQ','action':'send_email'}, {'id':'recover_once','route':'FAQ','timeout':'once','approved_draft_id':'D-recover_once-v1'}, {'id':'timeout_always','route':'FAQ','timeout':'always'}]
    ledger=DraftLedger();out=[run_case(x,ledger) for x in fixtures]
    before=len(ledger.entries);a=ledger.create('dedup','Example','P-V1');b=ledger.create('dedup','Example','P-V1');dedup={'id':'dedup','same_id':a['draft_id']==b['draft_id'],'new_ledger_entries':len(ledger.entries)-before}
    expected={'normal':'COMPLETE','waiting':'WAITING_APPROVAL','billing':'NEEDS_REVIEW','unknown':'NEEDS_REVIEW','denied':'DENIED','recover_once':'COMPLETE','timeout_always':'NEEDS_REVIEW'}
    checks=[{'case':x['id'],'pass':x['state']==expected[x['id']]} for x in out]
    checks.append({'case':'dedup','pass':dedup['same_id'] and dedup['new_ledger_entries']==1})
    assert all(x['pass'] for x in checks)
    for x in out:
        if x['state'] in ('DENIED','NEEDS_REVIEW'):assert x['draft'] is None
    assert sum(e['action']=='lookup_policy' for e in out[-1]['events'])==2
    assert sum(e['action']=='lookup_policy' for e in out[-2]['events'])==2
    result={'scope':'deterministic local teaching controller; no external sends; in-memory ledger','fixtures':fixtures,'results':out,'deduplication':dedup,'checks':checks}
    pathlib.Path(args.output).write_text(json.dumps(result,indent=2)+'\n');print(json.dumps({'checks_passed':len(checks),'checks_total':len(checks),'output':args.output}))
if __name__=='__main__':main()
