from copy import deepcopy
import sys
from evaluator import evaluate

base={
"learner_profile_id":"LP-EXP-01","target_competency_id":"CMP-RETRY-IDEMPOTENCY","prior_evidence_ref":"EV-PRIOR-01","prior_evidence_strength":"STRONG","diagnostic_signal":"SIG-CURRENT-CHALLENGE-READY","route_state":"EXPERIENCED","scaffold_level":"MINIMAL","challenge_level":"HIGH","practice_opportunity":"PRACTICE-01","feedback_signal":"FB-01","transfer_task":"TRANSFER-01","exit_evidence":"EV-EXIT-01","repair_trigger":"NONE_EVIDENCE_CLOSED","review_owner":"OWNER-01","diagnostic_supports_compression":True,"conceptual_evidence_strong":True,"tool_familiarity":"HIGH","conceptual_gap":False,"tool_bridge_required":False,"exit_bar_equivalent":True,"transfer_variant":"BASELINE","baseline_decision_reused":False,"transfer_recomputed":True,"prerequisite_contradiction_open":False}

def t(name,mut,expected):
    x=deepcopy(base); mut(x); got=evaluate(x); ok=(got==expected); print(('PASS' if ok else 'FAIL'),name,got,'expected='+expected); return ok

tests=[]
tests.append(('baseline_experienced',lambda x:None,'INSTRUCTIONAL_ROUTE_REVIEW_READY'))
tests.append(('seniority_contradiction',lambda x:(x.update(prior_evidence_strength='CONTRADICTED',prerequisite_contradiction_open=True)),'HOLD_SENIORITY_NOT_EVIDENCE'))
tests.append(('tool_bridge_transfer',lambda x:x.update(route_state='BRIDGE',scaffold_level='TARGETED_TOOL_BRIDGE',tool_familiarity='LOW',tool_bridge_required=True,transfer_variant='NEW_TOOLCHAIN',transfer_recomputed=True,baseline_decision_reused=False),'TRANSFER_REVIEW_READY'))
tests += [
('missing_profile',lambda x:x.update(learner_profile_id='UNKNOWN'),'HOLD_CORE_IDENTITY_OR_EVIDENCE_MISSING'),
('missing_target',lambda x:x.update(target_competency_id='MISSING'),'HOLD_CORE_IDENTITY_OR_EVIDENCE_MISSING'),
('missing_prior_ref',lambda x:x.update(prior_evidence_ref='UNKNOWN'),'HOLD_CORE_IDENTITY_OR_EVIDENCE_MISSING'),
('missing_strength',lambda x:x.update(prior_evidence_strength='UNKNOWN'),'HOLD_PRIOR_EVIDENCE_STRENGTH_MISSING'),
('invalid_route',lambda x:x.update(route_state='SENIOR'),'HOLD_ROUTE_STATE_INVALID'),
('missing_diagnostic',lambda x:x.update(diagnostic_signal='MISSING'),'HOLD_DIAGNOSTIC_EVIDENCE_MISSING'),
('weak_experienced',lambda x:x.update(prior_evidence_strength='WEAK'),'HOLD_SENIORITY_NOT_EVIDENCE'),
('stale_experienced',lambda x:x.update(prior_evidence_strength='STALE'),'HOLD_SENIORITY_NOT_EVIDENCE'),
('open_contradiction',lambda x:x.update(prerequisite_contradiction_open=True),'HOLD_PREREQUISITE_CONTRADICTION'),
('moderate_experienced',lambda x:x.update(prior_evidence_strength='MODERATE'),'HOLD_EXPERIENCED_ROUTE_UNSUPPORTED'),
('diagnostic_not_compression_ready',lambda x:x.update(diagnostic_supports_compression=False),'HOLD_ROUTE_COMPRESSION_UNJUSTIFIED'),
('tool_gap_false_foundation',lambda x:x.update(route_state='FOUNDATION',scaffold_level='HIGH',tool_familiarity='LOW',tool_bridge_required=True),'HOLD_TOOL_GAP_FALSE_COMPETENCE_FAILURE'),
('tool_bridge_skipped',lambda x:x.update(tool_familiarity='LOW',tool_bridge_required=True),'HOLD_TOOL_BRIDGE_SKIPPED'),
('missing_scaffold',lambda x:x.update(scaffold_level='UNKNOWN'),'HOLD_INSTRUCTIONAL_TREATMENT_INCOMPLETE'),
('missing_challenge',lambda x:x.update(challenge_level='MISSING'),'HOLD_INSTRUCTIONAL_TREATMENT_INCOMPLETE'),
('missing_practice',lambda x:x.update(practice_opportunity='UNKNOWN'),'HOLD_INSTRUCTIONAL_TREATMENT_INCOMPLETE'),
('missing_feedback',lambda x:x.update(feedback_signal='UNKNOWN'),'HOLD_INSTRUCTIONAL_TREATMENT_INCOMPLETE'),
('experienced_over_scaffolded',lambda x:x.update(scaffold_level='FULL'),'HOLD_EXPERIENCED_SCAFFOLD_NOT_COMPRESSED'),
('bridge_unbounded',lambda x:x.update(route_state='BRIDGE',scaffold_level='FULL',tool_familiarity='LOW',tool_bridge_required=True),'HOLD_BRIDGE_NOT_BOUNDED'),
('missing_transfer',lambda x:x.update(transfer_task='MISSING'),'HOLD_TRANSFER_TASK_MISSING'),
('waived_exit',lambda x:x.update(exit_evidence='WAIVED_BY_EXPERIENCE'),'HOLD_COMMON_EXIT_EVIDENCE_MISSING'),
('lower_exit_bar',lambda x:x.update(exit_bar_equivalent=False),'HOLD_EXIT_EVIDENCE_BAR_LOWERED'),
('missing_repair_trigger',lambda x:x.update(repair_trigger='UNKNOWN'),'HOLD_REPAIR_TRIGGER_MISSING'),
('missing_owner',lambda x:x.update(review_owner='MISSING'),'HOLD_REVIEW_OWNER_MISSING'),
('transfer_baseline_reuse',lambda x:x.update(transfer_variant='NEW_CONTEXT',baseline_decision_reused=True,transfer_recomputed=True),'HOLD_TRANSFER_BASELINE_ORACLE_REUSE'),
('transfer_not_recomputed',lambda x:x.update(transfer_variant='NEW_CONTEXT',baseline_decision_reused=False,transfer_recomputed=False),'HOLD_TRANSFER_NOT_RECOMPUTED')]
passed=0
for name,mut,exp in tests:
    try: ok=t(name,mut,exp)
    except Exception as e: print('FAIL',name,e); ok=False
    passed+=int(ok)
print(f'RESULT {passed}/{len(tests)} PASS')
sys.exit(0 if passed==len(tests) else 1)
