from math import isfinite

def _num(x): return isinstance(x,(int,float)) and not isinstance(x,bool) and isfinite(x)
def _r(x): return round(float(x)+0.0,2)

def _calc(c):
    nums=['recognized_revenue','credits_refunds','direct_usage_cost','payment_cost','customer_support_cost','other_variable_cost','allocated_shared_cost']
    if any(not _num(c.get(k)) for k in nums): return None
    if any(c[k] < 0 for k in nums): return None
    net=_r(c['recognized_revenue']-c['credits_refunds'])
    cc=_r(c['direct_usage_cost']+c['payment_cost']+c['customer_support_cost']+c['other_variable_cost'])
    cp=_r(net-cc)
    margin=None if net<=0 else _r(cp/net*100)
    flc=_r(cc+c['allocated_shared_cost'])
    flp=_r(net-flc)
    return net,cc,cp,margin,flc,flp

def _out(state,vals,reason):
    if vals is None: return {'decision_state':state,'net_revenue':None,'contribution_profit':None,'contribution_margin_pct':None,'fully_loaded_profit':None,'reason_code':reason}
    net,cc,cp,margin,flc,flp=vals
    return {'decision_state':state,'net_revenue':net,'contribution_profit':cp,'contribution_margin_pct':margin,'fully_loaded_profit':flp,'reason_code':reason}

def evaluate(c):
    decisive=['client_id','period','recognized_revenue','credits_refunds','direct_usage_cost','payment_cost','customer_support_cost','other_variable_cost','allocated_shared_cost','cost_scope','allocation_version','variance_driver','evidence_ref']
    if any(c.get(k) in (None,'',[]) for k in decisive): return _out('HOLD',None,'DECISIVE_EVIDENCE_MISSING')
    vals=_calc(c)
    if vals is None: return _out('HOLD',None,'INVALID_NUMERIC_EVIDENCE')
    scope=c.get('cost_scope')
    if not isinstance(scope,dict): return _out('HOLD',vals,'COST_SCOPE_INVALID')
    expected={'direct_usage_cost':'CONTRIBUTION','payment_cost':'CONTRIBUTION','customer_support_cost':'CONTRIBUTION','other_variable_cost':'CONTRIBUTION','allocated_shared_cost':'FULLY_LOADED_ONLY'}
    if any(scope.get(k)!=v for k,v in expected.items()):
        if scope.get('customer_support_cost')!='CONTRIBUTION' and c.get('customer_support_cost',0)>0:
            return _out('DISPUTED',vals,'CUSTOMER_SUPPORT_MISCLASSIFIED')
        return _out('DISPUTED',vals,'COST_SCOPE_DEFINITION_MISMATCH')
    if c.get('period_closed') and c.get('post_close_adjustment') and not c.get('restatement_version'):
        return _out('HOLD',vals,'POST_CLOSE_ADJUSTMENT_REQUIRES_RESTATEMENT')
    prior=c.get('comparison_allocation_version')
    if prior and prior!=c.get('allocation_version') and not c.get('comparison_restated'):
        return _out('HOLD',vals,'ALLOCATION_VERSION_CHANGED_COMPARISON_NOT_RESTATED')
    if c.get('comparison_cost_scope_match') is False:
        return _out('DISPUTED',vals,'COST_SCOPE_MISMATCH_ACROSS_COMPARISON')
    net,cc,cp,margin,flc,flp=vals
    if cp<=0: return _out('LOSS',vals,'CONTRIBUTION_NON_POSITIVE')
    if flp<0: return _out('MARGINAL',vals,'CONTRIBUTION_POSITIVE_FULLY_LOADED_NEGATIVE')
    return _out('PROFITABLE',vals,'CONTRIBUTION_AND_FULLY_LOADED_POSITIVE')
