import re
DYNAMIC=re.compile(r'(?:^|[._-])(lesson|user|session|attempt)?[-_:]?\d+(?:$|[._-])',re.I)

def missing(x,*keys): return any(x.get(k) in (None,'','MISSING','UNKNOWN') for k in keys)
def inspect(x):
    issues=[]
    name=x.get('event_name','')
    if DYNAMIC.search(name) or x.get('dynamic_value_in_event_name') is True: issues.append('DYNAMIC_EVENT_NAME')
    if missing(x,'event_timestamp','observed_timestamp'): issues.append('TIMESTAMP_EVIDENCE_MISSING')
    if missing(x,'taxonomy_version','schema_version','producer_version'): issues.append('VERSION_EVIDENCE_MISSING')
    if missing(x,'privacy_class'): issues.append('PRIVACY_CLASS_MISSING')
    if x.get('cardinality_class') in ('UNBOUNDED','UNBOUNDED_EVENT_NAME','UNKNOWN','MISSING',None): issues.append('CARDINALITY_POLICY_INVALID')
    if not x.get('provenance'): issues.append('PROVENANCE_MISSING')
    if x.get('semantic_rename') and not x.get('migration_map_ref'): issues.append('MIGRATION_MAP_MISSING')
    if x.get('deprecation_state')=='DEPRECATED' and not x.get('replacement_event') and not x.get('replacement_not_applicable_reason'): issues.append('DEPRECATED_REPLACEMENT_MISSING')
    if x.get('raw_event_used_as_mastery') is True or x.get('mastery_claim_forbidden_without_evidence') is False: issues.append('MASTERY_INFERENCE_FORBIDDEN')
    if x.get('definition_drift_without_version') is True: issues.append('SCHEMA_OR_MEANING_DRIFT')
    if x.get('replay_rewrites_original') is True: issues.append('REPLAY_PROVENANCE_LOST')
    if x.get('derived_metric_overwrites_raw') is True: issues.append('DERIVATION_PROVENANCE_LOST')
    return issues

def expected(x):
    issues=inspect(x)
    order=[('DYNAMIC_EVENT_NAME','HOLD_DYNAMIC_EVENT_NAME'),('TIMESTAMP_EVIDENCE_MISSING','HOLD_TIMESTAMP_EVIDENCE'),('VERSION_EVIDENCE_MISSING','HOLD_VERSION_EVIDENCE'),('PRIVACY_CLASS_MISSING','HOLD_PRIVACY_CLASS'),('CARDINALITY_POLICY_INVALID','HOLD_CARDINALITY_POLICY'),('MIGRATION_MAP_MISSING','HOLD_MIGRATION_MISSING'),('MASTERY_INFERENCE_FORBIDDEN','HOLD_MASTERY_INFERENCE'),('SCHEMA_OR_MEANING_DRIFT','HOLD_SCHEMA_OR_MEANING_DRIFT'),('PROVENANCE_MISSING','HOLD_PROVENANCE'),('DERIVATION_PROVENANCE_LOST','HOLD_DERIVATION_PROVENANCE'),('REPLAY_PROVENANCE_LOST','HOLD_REPLAY_PROVENANCE'),('DEPRECATED_REPLACEMENT_MISSING','HOLD_MIGRATION_MISSING')]
    for issue,state in order:
        if issue in issues: return state
    if x.get('validation_state') in ('UNREVIEWED','REVIEW_REQUIRED','VALID_REVIEW_PENDING','TRANSFER_REVIEW_REQUIRED'): return 'TAXONOMY_REVIEW_REQUIRED'
    return 'TAXONOMY_REVIEW_REQUIRED'

def inspect_transfer(x):
    issues=inspect(x)
    if x.get('baseline_oracle_reused'): issues.append('BASELINE_ORACLE_REUSE_FORBIDDEN')
    if x.get('original_semantics_preserved') is not True: issues.append('ORIGINAL_SEMANTICS_NOT_PRESERVED')
    if x.get('taxonomy_version') != x.get('source_taxonomy_version'): issues.append('SOURCE_VERSION_REWRITTEN')
    return issues

def expected_transfer(x):
    issues=inspect_transfer(x)
    if 'BASELINE_ORACLE_REUSE_FORBIDDEN' in issues: return 'HOLD_BASELINE_ORACLE_REUSE'
    if 'ORIGINAL_SEMANTICS_NOT_PRESERVED' in issues or 'SOURCE_VERSION_REWRITTEN' in issues: return 'HOLD_REPLAY_PROVENANCE'
    base=expected(x)
    if base.startswith('HOLD_'): return base
    return 'TRANSFER_REVIEW_REQUIRED'
