from datetime import datetime, timezone
MISSING={None,"","MISSING","N/A"}
REQ=['run_id','request_id','model_id','provider_id','processing_tier','usage_source','input_tokens','output_tokens','total_tokens','price_snapshot_id','price_effective_at','measured_cost','allocation_rule_ref','allocated_cost','unit_of_work','unit_cost','budget_id','budget_limit','budget_consumed','cost_state','missing_usage_state','price_staleness_state','audit_ref']
AUX=['agent_id','workflow_id','owner_id','run_started_at','requests_count','expected_requests_count','cached_input_tokens','reasoning_tokens','tool_usage_units','retry_cost_units','external_provider_usage','model_price_model_id','price_provider_id','price_processing_tier','price_snapshot_currency','currency','input_unit_price','cached_input_unit_price','output_unit_price','tool_unit_price','external_provider_cost','retry_cost','shared_cost_pool','allocation_weight','allocation_basis_total','allocated_shared_cost','unit_count','budget_consumed_before','warning_threshold','stop_threshold','budget_state','escalation_required','usage_detail_state','transfer_variant','transfer_recomputed','baseline_exact_cost_reused']
EPS=1e-8

def missing(v): return v in MISSING

def num(v):
    return isinstance(v,(int,float)) and not isinstance(v,bool)

def close(a,b):
    return num(a) and num(b) and abs(float(a)-float(b))<=EPS

def dt(s):
    return datetime.fromisoformat(str(s).replace('Z','+00:00'))

def evaluate(x):
    for f in REQ:
        if f not in x or missing(x.get(f)): return 'HOLD_REQUIRED_EVIDENCE_MISSING:'+f
    for f in AUX:
        if f not in x or missing(x.get(f)): return 'HOLD_AUX_EVIDENCE_MISSING:'+f
    if x['cost_state'] not in {'EXACT','ESTIMATE','PARTIAL','REVIEW_REQUIRED'}: return 'HOLD_COST_STATE_INVALID'
    if x['missing_usage_state'] not in {'COMPLETE','MISSING_PARTIAL','MISSING_CRITICAL'}: return 'HOLD_MISSING_USAGE_STATE_INVALID'
    if x['price_staleness_state'] not in {'CURRENT','STALE','UNKNOWN'}: return 'HOLD_PRICE_STALENESS_STATE_INVALID'
    if x['budget_state'] not in {'WITHIN','WARNING','STOP'}: return 'HOLD_BUDGET_STATE_INVALID'
    if x['escalation_required'] not in {'YES','NO'}: return 'HOLD_ESCALATION_STATE_INVALID'
    if x['usage_detail_state'] not in {'COMPLETE_NORMALIZED','RAW_PRESERVED','PARTIAL_ADAPTER'}: return 'HOLD_USAGE_DETAIL_STATE_INVALID'
    if x['usage_source'] not in {'SDK_NORMALIZED','PRESERVED_RAW','MULTI_ADAPTER_RECONCILED'}: return 'HOLD_USAGE_SOURCE_INVALID'
    # non-negative usage and price inputs
    for f in ['input_tokens','output_tokens','total_tokens','cached_input_tokens','reasoning_tokens','tool_usage_units','retry_cost_units','external_provider_usage','requests_count','expected_requests_count','input_unit_price','cached_input_unit_price','output_unit_price','tool_unit_price','external_provider_cost','retry_cost','shared_cost_pool','allocation_weight','allocation_basis_total','allocated_shared_cost','unit_count','measured_cost','allocated_cost','unit_cost','budget_limit','budget_consumed','budget_consumed_before','warning_threshold','stop_threshold']:
        if not num(x[f]) or x[f] < 0: return 'HOLD_NEGATIVE_OR_NONNUMERIC:'+f
    if x['unit_count']<=0: return 'HOLD_UNIT_COUNT_INVALID'
    if x['allocation_basis_total']<=0: return 'HOLD_ALLOCATION_BASIS_INVALID'
    # usage identities
    if x['total_tokens'] != x['input_tokens'] + x['output_tokens']: return 'HOLD_TOKEN_TOTAL_MISMATCH'
    if x['cached_input_tokens'] > x['input_tokens']: return 'HOLD_CACHED_INPUT_GT_INPUT'
    if x['reasoning_tokens'] > x['output_tokens']: return 'HOLD_REASONING_GT_OUTPUT'
    if x['requests_count'] > x['expected_requests_count']: return 'HOLD_REQUEST_COUNT_INVALID'
    if x['requests_count'] < x['expected_requests_count'] and x['missing_usage_state']=='COMPLETE': return 'HOLD_USAGE_COUNT_CONTRADICTION'
    if x['usage_detail_state']=='PARTIAL_ADAPTER' and x['missing_usage_state']=='COMPLETE': return 'HOLD_PARTIAL_ADAPTER_MARKED_COMPLETE'
    if x['missing_usage_state']=='MISSING_CRITICAL': return 'HOLD_CRITICAL_USAGE_MISSING'
    if x['missing_usage_state']!='COMPLETE' and x['cost_state']=='EXACT': return 'HOLD_MISSING_USAGE_CANNOT_BE_EXACT'
    # price-context binding
    if x['model_price_model_id'] != x['model_id']: return 'HOLD_PRICE_MODEL_MISMATCH'
    if x['price_provider_id'] != x['provider_id']: return 'HOLD_PRICE_PROVIDER_MISMATCH'
    if x['price_processing_tier'] != x['processing_tier']: return 'HOLD_PRICE_TIER_MISMATCH'
    if x['price_snapshot_currency'] != x['currency']: return 'HOLD_PRICE_CURRENCY_MISMATCH'
    try:
        if dt(x['price_effective_at']) > dt(x['run_started_at']): return 'HOLD_PRICE_EFFECTIVE_AFTER_RUN'
    except Exception:
        return 'HOLD_PRICE_TIME_INVALID'
    if x['price_staleness_state']!='CURRENT' and x['cost_state']=='EXACT': return 'HOLD_STALE_PRICE_CANNOT_BE_EXACT'
    # known direct cost. Reasoning is a detail inside output for this fixture, not double-billed.
    uncached=x['input_tokens']-x['cached_input_tokens']
    model_cost=uncached*x['input_unit_price'] + x['cached_input_tokens']*x['cached_input_unit_price'] + x['output_tokens']*x['output_unit_price']
    tool_cost=x['tool_usage_units']*x['tool_unit_price']
    # retry_cost_units is preserved evidence; retry_cost is the separately calculated monetary charge for it.
    direct=model_cost+tool_cost+x['external_provider_cost']+x['retry_cost']
    if not close(x['measured_cost'],direct): return 'HOLD_DIRECT_COST_MISMATCH'
    # Shared allocation must be explicit and reproducible.
    if x['shared_cost_pool']>0 and x['allocation_rule_ref'] in {'NONE','UNKNOWN','SILENT_EQUAL_SPLIT'}: return 'HOLD_ALLOCATION_RULE_MISSING_OR_SILENT'
    expected_share=x['shared_cost_pool']*(x['allocation_weight']/x['allocation_basis_total'])
    if not close(x['allocated_shared_cost'],expected_share): return 'HOLD_SHARED_ALLOCATION_MISMATCH'
    if not close(x['allocated_cost'],x['measured_cost']+x['allocated_shared_cost']): return 'HOLD_ALLOCATED_COST_MISMATCH'
    if not close(x['unit_cost'],x['allocated_cost']/x['unit_count']): return 'HOLD_UNIT_COST_MISMATCH'
    # budget recomputation
    if x['warning_threshold']>x['stop_threshold'] or x['stop_threshold']>x['budget_limit']: return 'HOLD_BUDGET_THRESHOLD_ORDER_INVALID'
    if not close(x['budget_consumed'],x['budget_consumed_before']+x['allocated_cost']): return 'HOLD_BUDGET_CONSUMPTION_MISMATCH'
    expected_budget='STOP' if x['budget_consumed']>=x['stop_threshold'] else ('WARNING' if x['budget_consumed']>=x['warning_threshold'] else 'WITHIN')
    if x['budget_state']!=expected_budget: return 'HOLD_BUDGET_STATE_MISMATCH'
    if expected_budget in {'WARNING','STOP'} and x['escalation_required']!='YES': return 'HOLD_BUDGET_ESCALATION_REQUIRED'
    if expected_budget=='WITHIN' and x['escalation_required']!='NO': return 'HOLD_UNNEEDED_ESCALATION_STATE'
    # exactness after all computations
    if x['missing_usage_state']=='COMPLETE' and x['price_staleness_state']=='CURRENT' and x['cost_state']!='EXACT': return 'HOLD_COMPLETE_CURRENT_COST_NOT_EXACT'
    # changed-context transfer
    if x['transfer_variant'] not in {'BASELINE','NONE'}:
        if x['transfer_recomputed'] is not True: return 'HOLD_TRANSFER_NOT_RECOMPUTED'
        if x['baseline_exact_cost_reused'] is True: return 'HOLD_TRANSFER_BASELINE_EXACT_REUSE'
        if x['allocation_rule_ref']=='SILENT_EQUAL_SPLIT': return 'HOLD_TRANSFER_SILENT_SPLIT'
        if x['missing_usage_state']!='COMPLETE': return 'TRANSFER_COST_REVIEW_REQUIRED'
        return 'TRANSFER_COST_REVIEW_READY'
    if expected_budget=='STOP': return 'STOP_BUDGET_ESCALATION_REQUIRED'
    if expected_budget=='WARNING': return 'WARNING_BUDGET_REVIEW_REQUIRED'
    return 'COST_LEDGER_REVIEW_READY'
