from __future__ import annotations
import json,sys
from pathlib import Path
from gate_rules import inspect,expected_decision,dependency_closure
REQ=['content_id','base_revision_id','base_digest','regeneration_request_id','target_node_ids','protected_node_ids','affected_derived_artifacts','precondition_state','structural_validation_state','claim_diff_state','human_edit_preservation_state','review_state','promotion_state','rollback_ref','audit_event_id','evidence_refs','rationale','minimal_repair']

def check(fixture,submission):
    errors=[]
    for k in REQ:
        if k not in submission or submission[k] in (None,'') or (isinstance(submission[k],list) and not submission[k]): errors.append('MISSING:'+k)
    c=fixture.get('canonical') or {}; q=fixture.get('request') or {}; d=fixture.get('diff') or {}; p=fixture.get('promotion') or {}; rv=fixture.get('review') or {}
    binds={
      'content_id':fixture.get('content_id'),'base_revision_id':c.get('revision_id'),'base_digest':c.get('digest'),'regeneration_request_id':q.get('id'),
      'target_node_ids':sorted(q.get('target_node_ids') or []),'protected_node_ids':sorted(q.get('protected_node_ids') or []),'affected_derived_artifacts':sorted(d.get('affected_derived_artifacts') or []),
      'structural_validation_state':d.get('structural_validation_state'),'claim_diff_state':d.get('claim_diff_state'),'human_edit_preservation_state':d.get('human_edit_preservation_state'),
      'review_state':rv.get('state'),'rollback_ref':p.get('rollback_ref'),'audit_event_id':p.get('audit_event_id')}
    for k,v in binds.items():
        got=submission.get(k); got=sorted(got) if isinstance(got,list) else got
        if got!=v: errors.append('BINDING:'+k)
    issues=inspect(fixture); decision=expected_decision(fixture)
    expected_pre='STALE_BASE' if 'STALE_BASE' in issues or 'PRECONDITION_FAILURE' in issues else 'PASS'
    if submission.get('precondition_state')!=expected_pre: errors.append('STATE:precondition_state')
    expected_promotion='HOLD' if decision=='HOLD' else ('HOLD_PENDING_REVIEW' if decision=='REVIEW_REQUIRED' else 'PROMOTE_ELIGIBLE_AFTER_REVIEW')
    if submission.get('promotion_state')!=expected_promotion: errors.append('STATE:promotion_state')
    refs=submission.get('evidence_refs') or []
    if not all(isinstance(x,str) and x.startswith('/') for x in refs): errors.append('EVIDENCE_REFS_MUST_BE_JSON_POINTERS')
    return errors,issues,decision,dependency_closure(fixture)

def main(argv):
    if len(argv)!=3:
        print('usage: python run_checks.py <fixture.json> <submission.json>',file=sys.stderr); return 2
    f=json.loads(Path(argv[1]).read_text()); s=json.loads(Path(argv[2]).read_text())
    errors,issues,decision,dep=check(f,s)
    print(json.dumps({'status':'PASS' if not errors else 'FAIL','submission_errors':errors,'deterministic_fixture_issues':issues,'bounded_decision':decision,'computed_dependency_impact':dep,'scope':'SYNTHETIC_ONLY'},indent=2))
    return 0 if not errors else 1
if __name__=='__main__': raise SystemExit(main(sys.argv))
