from datetime import datetime
MISSING={None,"","MISSING","UNKNOWN","N/A"}
VALID_DEDUPE={"NEW","DUPLICATE_IGNORED"}
VALID_RECON={"MATCHED","REVIEW_REQUIRED","MISMATCH","AMBIGUOUS","DUPLICATE_IGNORED"}
VALID_INVOICE_SEM={"AWAITING_PAYMENT","PAID","VOID","UNCOLLECTIBLE"}
VALID_PAYMENT_SEM={"NOT_FINAL","SUCCESS_FINAL","OUT_OF_BAND_VERIFIED","FAILURE_RETRYABLE","FAILURE_ACTION_REQUIRED","CANCELED_FINAL"}

def missing(v): return v in MISSING

def dt(v):
    try: return datetime.fromisoformat(v)
    except Exception: return None

def evaluate(x):
    required=["billing_adapter_id","provider_id","internal_invoice_id","provider_invoice_id","internal_payment_id","provider_payment_ref","business_state","provider_invoice_status","provider_payment_status","event_id","idempotency_key","dedupe_state","mapping_version","amount_expected","amount_observed","currency","reconciliation_state","reconciliation_reason","manual_review_required","audit_ref"]
    for f in required:
        if missing(x.get(f)): return "HOLD_REQUIRED_EVIDENCE_MISSING:"+f
    aux=["provider_api_version","event_type","event_created_at","event_received_at","current_mapping_version","provider_invoice_internal_target","provider_payment_internal_target","provider_status_mapping_ref","provider_invoice_semantic","provider_payment_semantic","business_state_authority","source_of_truth_rule_ref","currency_observed","status_mapping_verified","transfer_variant","provider_neutral_transfer","transfer_recomputed","baseline_decision_reused","baseline_status_mapping_reused","provider_reference_collision"]
    for f in aux:
        if missing(x.get(f)): return "HOLD_AUX_EVIDENCE_MISSING:"+f
    if x.get("business_state_authority")!="INTERNAL_CANONICAL_POLICY" or not str(x.get("source_of_truth_rule_ref","")).startswith("SOTR-INTERNAL"):
        return "HOLD_PROVIDER_STATUS_CANONICAL_SHORTCUT"
    if x.get("dedupe_state") not in VALID_DEDUPE: return "HOLD_DEDUPE_STATE_INVALID"
    if x.get("reconciliation_state") not in VALID_RECON: return "HOLD_RECONCILIATION_STATE_INVALID"
    if x.get("provider_invoice_semantic") not in VALID_INVOICE_SEM: return "HOLD_PROVIDER_INVOICE_SEMANTIC_INVALID"
    if x.get("provider_payment_semantic") not in VALID_PAYMENT_SEM: return "HOLD_PROVIDER_PAYMENT_SEMANTIC_INVALID"
    if x.get("status_mapping_verified") is not True: return "HOLD_PROVIDER_STATUS_MAPPING_UNVERIFIED"
    if x.get("provider_reference_collision") is True: return "HOLD_PROVIDER_REFERENCE_COLLISION"
    ec,er=dt(x.get("event_created_at")),dt(x.get("event_received_at"))
    if ec is None or er is None: return "HOLD_EVENT_TIME_INVALID"
    if er<ec: return "HOLD_EVENT_TIME_ORDER_INVALID"
    if not isinstance(x.get("amount_expected"),(int,float)) or not isinstance(x.get("amount_observed"),(int,float)) or x["amount_expected"]<0 or x["amount_observed"]<0:
        return "HOLD_AMOUNT_INVALID"
    if x.get("provider_invoice_internal_target")!=x.get("internal_invoice_id"):
        return "HOLD_INVOICE_MAPPING_CONFLICT"
    if x.get("provider_payment_internal_target")!=x.get("internal_payment_id"):
        return "HOLD_PAYMENT_MAPPING_CONFLICT"
    if x.get("amount_expected")!=x.get("amount_observed"):
        return "HOLD_AMOUNT_MISMATCH"
    if x.get("currency_observed")!=x.get("currency"):
        return "HOLD_CURRENCY_MISMATCH"
    if x.get("same_provider_event_replayed") is True:
        if x.get("dedupe_state")!="DUPLICATE_IGNORED": return "HOLD_DUPLICATE_EVENT_NOT_DEDUPED"
        if x.get("state_transition_applied") is True: return "HOLD_DUPLICATE_STATE_TRANSITION"
    elif x.get("dedupe_state")=="DUPLICATE_IGNORED":
        return "HOLD_FALSE_DUPLICATE_CLASSIFICATION"
    # Current event mapping cannot silently lag current mapping.
    if x.get("mapping_version")!=x.get("current_mapping_version"):
        if x.get("entitlement_effect_ref") not in {None,"NONE"}: return "HOLD_STALE_MAPPING_ENTITLEMENT_SHORTCUT"
        return "HOLD_CURRENT_EVENT_MAPPING_STALE"
    # Aggregate stale evidence from an older event must remain review-visible.
    if x.get("stale_mapping_event_present") is True:
        if x.get("manual_review_required") is not True or x.get("reconciliation_state")!="REVIEW_REQUIRED":
            return "HOLD_STALE_MAPPING_UNREVIEWED"
        if x.get("entitlement_effect_ref") not in {None,"NONE"}: return "HOLD_STALE_MAPPING_ENTITLEMENT_SHORTCUT"
    # A provider-declared failure can never coexist with a matched paid business state.
    if x.get("provider_payment_semantic") in {"FAILURE_RETRYABLE","FAILURE_ACTION_REQUIRED","CANCELED_FINAL"} and x.get("reconciliation_state")=="MATCHED" and x.get("business_state")=="PAID":
        return "HOLD_PROVIDER_FAILURE_MATCHED_PAID_CONFLICT"
    # Other non-final provider states also cannot justify a paid internal business state.
    if x.get("business_state") in {"PAID","PAID_REVIEW"} and x.get("provider_payment_semantic") not in {"SUCCESS_FINAL","OUT_OF_BAND_VERIFIED"}:
        return "HOLD_NONFINAL_PROVIDER_PAYMENT_BUSINESS_PAID"
    # Reconciliation state must not hide known mismatches.
    if x.get("reconciliation_state")=="MATCHED" and x.get("manual_review_required") is True:
        return "HOLD_MATCHED_WITH_MANUAL_REVIEW_CONFLICT"
    if x.get("reconciliation_state") in {"MISMATCH","AMBIGUOUS","REVIEW_REQUIRED"} and x.get("manual_review_required") is not True:
        return "HOLD_REVIEW_STATE_WITHOUT_MANUAL_REVIEW"
    if x.get("reconciliation_state")=="DUPLICATE_IGNORED" and x.get("dedupe_state")!="DUPLICATE_IGNORED":
        return "HOLD_DUPLICATE_RECONCILIATION_CONFLICT"
    # Transfer cannot copy provider-specific meaning or baseline decision.
    tv=x.get("transfer_variant")
    if tv not in {"BASELINE","NONE",None}:
        if x.get("provider_neutral_transfer") is not True: return "HOLD_TRANSFER_NOT_PROVIDER_NEUTRAL"
        if x.get("transfer_recomputed") is not True: return "HOLD_TRANSFER_NOT_RECOMPUTED"
        if x.get("baseline_decision_reused") is True: return "HOLD_TRANSFER_BASELINE_ORACLE_REUSE"
        if x.get("baseline_status_mapping_reused") is True: return "HOLD_TRANSFER_BASELINE_STATUS_MAPPING_REUSE"
    # Decision states.
    if tv not in {"BASELINE","NONE",None} and x.get("reconciliation_state")=="MATCHED":
        return "TRANSFER_RECONCILIATION_REVIEW_READY"
    if x.get("stale_mapping_event_present") is True:
        return "RECONCILIATION_REVIEW_REQUIRED"
    if x.get("dedupe_state")=="DUPLICATE_IGNORED":
        return "DUPLICATE_IGNORED_REVIEW_READY"
    if x.get("reconciliation_state")=="MATCHED":
        return "RECONCILIATION_MATCHED_REVIEW_READY"
    return "RECONCILIATION_REVIEW_REQUIRED"
