from copy import deepcopy
import sys
from evaluator import evaluate

base={
"architecture_decision_id":"AD-BASE-001","demand_snapshot_id":"DS-2026Q3-A","tenant_count_current":12,"tenant_count_forecast":24,"growth_trigger":"NOT_CLEARED","cost_pressure_signal":"LOW","operational_capacity_signal":"LIMITED","compliance_isolation_requirement":"STANDARD_TENANT_ISOLATION","tenant_context_propagation_ref":"CTX-AUTH-API-JOB-01","isolation_requirement_ref":"ISO-BASE-01","isolation_model":"SILO","resource_sharing_model":"DEDICATED_PER_TENANT","deployment_model":"AUTOMATED_SILO","tenant_to_deployment_map_ref":"MAP-BASE-01","noisy_neighbor_risk":"LOW","blast_radius":"SINGLE_TENANT","per_tenant_quota_ref":"QUOTA-NOT_REQUIRED-SILO","onboarding_automation_state":"PARTIAL","tenant_aware_observability_ref":"OBS-TENANT-01","unit_cost_estimate":"120.00","migration_cost_estimate":"42000.00","decision_option":"DEFER_SHARED_MULTI_TENANCY","decision_state":"DEFERRED","revisit_trigger":"FORECAST_OR_COST_PRESSURE_TRIGGER","owner_approval_ref":"APPROVAL-ARCH-01","audit_ref":"AUDIT-AGN015-BASE","transfer_variant":"BASELINE","baseline_decision_reused":False,"transfer_recomputed":True,"regulated_tier_requires_dedicated":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_defer',lambda x:None,'DEFER_REVIEW_READY'))
tests.append(('transfer_hybrid',lambda x:x.update(tenant_count_current=420,tenant_count_forecast=900,growth_trigger='CLEARED',cost_pressure_signal='HIGH',operational_capacity_signal='READY',compliance_isolation_requirement='REGULATED_TIER_DEDICATED',tenant_context_propagation_ref='CTX-END-TO-END-22',isolation_requirement_ref='ISO-TIERED-22',isolation_model='HYBRID_STAMP',resource_sharing_model='SHARED_STANDARD_DEDICATED_REGULATED',deployment_model='DEPLOYMENT_STAMPS',tenant_to_deployment_map_ref='MAP-TIER-STAMP-22',noisy_neighbor_risk='MANAGED',blast_radius='STAMP_BOUNDED',per_tenant_quota_ref='QUOTA-TENANT-22',onboarding_automation_state='AUTOMATED',tenant_aware_observability_ref='OBS-TENANT-22',unit_cost_estimate='22.50',migration_cost_estimate='155000.00',decision_option='HYBRID_STAMP',decision_state='PROMOTE_HYBRID_STAMP',transfer_variant='NEW_PRODUCT',baseline_decision_reused=False,transfer_recomputed=True,regulated_tier_requires_dedicated=True),'TRANSFER_HYBRID_REVIEW_READY'))
tests += [
('missing_decision_id',lambda x:x.update(architecture_decision_id='UNKNOWN'),'HOLD_DECISION_IDENTITY_MISSING'),
('missing_demand_snapshot',lambda x:x.update(demand_snapshot_id='MISSING'),'HOLD_DECISION_IDENTITY_MISSING'),
('invalid_current_count',lambda x:x.update(tenant_count_current='12'),'HOLD_TENANT_COUNT_INVALID'),
('forecast_below_current',lambda x:x.update(tenant_count_forecast=2),'HOLD_FORECAST_BELOW_CURRENT'),
('missing_growth_trigger',lambda x:x.update(growth_trigger='UNKNOWN'),'HOLD_GROWTH_TRIGGER_MISSING'),
('missing_cost_pressure',lambda x:x.update(cost_pressure_signal='UNKNOWN'),'HOLD_COST_PRESSURE_MISSING'),
('missing_ops_capacity',lambda x:x.update(operational_capacity_signal='MISSING'),'HOLD_OPERATIONAL_CAPACITY_MISSING'),
('missing_compliance',lambda x:x.update(compliance_isolation_requirement='UNKNOWN'),'HOLD_COMPLIANCE_ISOLATION_MISSING'),
('forecast_growth_without_context',lambda x:x.update(tenant_count_forecast=500,growth_trigger='CLEARED',cost_pressure_signal='HIGH',operational_capacity_signal='READY',tenant_context_propagation_ref='UNKNOWN',isolation_model='POOL',resource_sharing_model='SHARED',deployment_model='SHARED_POOL',decision_option='POOL',decision_state='PROMOTE_POOL'),'HOLD_TENANT_CONTEXT_MISSING'),
('missing_isolation_requirement',lambda x:x.update(isolation_requirement_ref='UNKNOWN'),'HOLD_ISOLATION_REQUIREMENT_MISSING'),
('invalid_isolation_model',lambda x:x.update(isolation_model='SHARED'),'HOLD_ISOLATION_MODEL_INVALID'),
('missing_resource_sharing',lambda x:x.update(resource_sharing_model='UNKNOWN'),'HOLD_RESOURCE_SHARING_MODEL_MISSING'),
('missing_deployment_model',lambda x:x.update(deployment_model='MISSING'),'HOLD_DEPLOYMENT_MODEL_MISSING'),
('missing_tenant_map',lambda x:x.update(tenant_to_deployment_map_ref='UNKNOWN'),'HOLD_TENANT_DEPLOYMENT_MAP_MISSING'),
('missing_noisy_neighbor',lambda x:x.update(noisy_neighbor_risk='UNKNOWN'),'HOLD_NOISY_NEIGHBOR_RISK_MISSING'),
('missing_blast_radius',lambda x:x.update(blast_radius='UNKNOWN'),'HOLD_BLAST_RADIUS_MISSING'),
('missing_quota_ref',lambda x:x.update(per_tenant_quota_ref='UNKNOWN'),'HOLD_PER_TENANT_QUOTA_EVIDENCE_MISSING'),
('missing_onboarding',lambda x:x.update(onboarding_automation_state='UNKNOWN'),'HOLD_ONBOARDING_STATE_MISSING'),
('missing_observability',lambda x:x.update(tenant_aware_observability_ref='UNKNOWN'),'HOLD_TENANT_OBSERVABILITY_MISSING'),
('invalid_unit_cost',lambda x:x.update(unit_cost_estimate='UNKNOWN'),'HOLD_UNIT_COST_INVALID'),
('invalid_migration_cost',lambda x:x.update(migration_cost_estimate='?'),'HOLD_MIGRATION_COST_INVALID'),
('invalid_option',lambda x:x.update(decision_option='MULTITENANT'),'HOLD_DECISION_OPTION_INVALID'),
('invalid_state',lambda x:x.update(decision_state='APPROVED'),'HOLD_DECISION_STATE_INVALID'),
('missing_revisit_trigger',lambda x:x.update(revisit_trigger='UNKNOWN'),'HOLD_REVISIT_TRIGGER_MISSING'),
('missing_owner',lambda x:x.update(owner_approval_ref='MISSING'),'HOLD_OWNER_APPROVAL_MISSING'),
('missing_audit',lambda x:x.update(audit_ref='UNKNOWN'),'HOLD_AUDIT_REFERENCE_MISSING'),
('option_state_mismatch',lambda x:x.update(decision_option='POOL',decision_state='DEFERRED',isolation_model='POOL'),'HOLD_DECISION_OPTION_STATE_MISMATCH'),
('option_model_mismatch',lambda x:x.update(decision_option='POOL',decision_state='PROMOTE_POOL'),'HOLD_OPTION_ISOLATION_MODEL_MISMATCH'),
('hybrid_without_stamps',lambda x:x.update(decision_option='HYBRID_STAMP',decision_state='PROMOTE_HYBRID_STAMP',isolation_model='HYBRID_STAMP',deployment_model='SHARED_POOL'),'HOLD_HYBRID_STAMP_DEPLOYMENT_MISSING'),
('pool_compliance_conflict',lambda x:x.update(decision_option='POOL',decision_state='PROMOTE_POOL',isolation_model='POOL',compliance_isolation_requirement='DEDICATED_REQUIRED'),'HOLD_COMPLIANCE_ISOLATION_CONFLICT'),
('noisy_neighbor_without_quota',lambda x:x.update(noisy_neighbor_risk='HIGH',per_tenant_quota_ref='NONE'),'HOLD_NOISY_NEIGHBOR_CONTROL_MISSING'),
('unbounded_blast_radius',lambda x:x.update(blast_radius='UNBOUNDED'),'HOLD_BLAST_RADIUS_UNBOUNDED'),
('promote_without_demand_gate',lambda x:x.update(decision_option='SILO',decision_state='PROMOTE_SILO',isolation_model='SILO'),'HOLD_DEMAND_GATE_NOT_CLEARED'),
('promote_ops_not_ready',lambda x:x.update(growth_trigger='CLEARED',decision_option='SILO',decision_state='PROMOTE_SILO',isolation_model='SILO',operational_capacity_signal='LIMITED'),'HOLD_OPERATIONAL_CAPACITY_NOT_READY'),
('promote_onboarding_not_ready',lambda x:x.update(growth_trigger='CLEARED',decision_option='SILO',decision_state='PROMOTE_SILO',isolation_model='SILO',operational_capacity_signal='READY',onboarding_automation_state='MANUAL'),'HOLD_ONBOARDING_AUTOMATION_NOT_READY'),
('transfer_baseline_reuse',lambda x:x.update(transfer_variant='NEW_PRODUCT',baseline_decision_reused=True,transfer_recomputed=True),'HOLD_TRANSFER_BASELINE_ORACLE_REUSE'),
('transfer_not_recomputed',lambda x:x.update(transfer_variant='NEW_PRODUCT',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)
