import pandas as pd
import copy
from sklearn.linear_model import LogisticRegression
debug=False

def get_combination(lst,tuplelst):
    i=0
    new_tuplelst=[]
    if len(tuplelst)==0:
        l=lst[0]
        for v in l:
            new_tuplelst.append([v])
        if len(lst)>1:
            return get_combination(lst[1:],new_tuplelst)
        else:
            return new_tuplelst
    

    currlst=lst[0]
    for l in tuplelst:
        
        for v in currlst:
            newl=copy.deepcopy(l)
            newl.append(v)
            new_tuplelst.append(newl)
        
    if len(lst)>1:
        return get_combination(lst[1:],new_tuplelst)
    else:
        return new_tuplelst
      
def get_C_set(df,C):
    lst=[]
    for Cvar in C:
        lst.append(list(set(list(df[Cvar]))))
        
    combination_lst= (get_combination(lst,[]))
    
    return combination_lst

def get_scores_regression(df,z_attr,z,zprime,klst,kvallst,C,target):
    for v in klst:
        if v in C:
            C.remove(v)
        

    #print (z,zprime,"scores for")
    sample=df
    if debug:
        print ("Given k number of data points",sample.shape)
      
    if len(C)>0:
        Clst=get_C_set(df,C)
    else:
        Clst=['']
    
    
    snum=0
    nnum=0
    snnum=0
    #print ((Clst))
    #print (C,Clst)
    #uniq_values=(df[C].values)#.ravel())
    if len(C)>1:
        unique_values=list(df.groupby(C).groups)
        #print (unique_values)
        #print (len(unique_values))
        Clst=unique_values
    model_map={}
    for cval in Clst:
        #print("cval is ",cval,C)
        if Clst[0]=='':
            Clst=[]
            
        
        #print (C,klst,z_attr)
        conditional_lst=copy.deepcopy(klst)
        conditional_lst.extend(C)
        conditional_lst.extend(z_attr)
        
        conditional_val=copy.deepcopy(kvallst)
        conditional_val.extend(cval)
        
        conditional_valzp=copy.deepcopy(conditional_val)
        conditional_val.extend(z)
        conditional_valzp.extend(zprime)
        
        
        
        #print (conditional_lst,conditional_val)
        pogivenczk,model_map=get_prob_o_regression(df,conditional_lst,conditional_val,[target],[1],model_map)
        if pogivenczk>0:        
            pogivenczpk,model_map=get_prob_o_regression(df,conditional_lst,conditional_valzp,[target],[1],model_map)
        else:
            pogivenczpk=0
            continue
        #print (pogivenczk,pogivenczpk,'probs')
        if len(C)>0:
            #if (len(klst)>0):
            pck,model_map=get_prob_o_regression(df,klst,kvallst,C,cval,model_map)#get_prob_c(sample,cval,C)#get_prob_o_regression(df,conditional_lst,conditional_valzp,C,cval)#Change
            #else:
            #    pck=
            
            conditional=copy.deepcopy(klst)
            conditional_val=copy.deepcopy(kvallst)
            conditional.extend(z_attr)
            conditional_val.extend(z)
            #print (cval,C)
            pcgivenzk,model_map=get_prob_o_regression(df,conditional,conditional_val,C,cval,model_map)#get_prob_c(sample,cval,C)#get_prob_o_regression(df,conditional_lst,conditional_valzp,C,cval)#Change
            
            conditional_val=copy.deepcopy(kvallst)
            conditional_val.extend(zprime)
            pcgivenzpk,model_map=get_prob_o_regression(df,conditional,conditional_val,C,cval,model_map)#get_prob_c(sample,cval,C)#get_prob_o_regression(df,conditional_lst,conditional_valzp,C,cval)#Change
        else:
            pck=1
            pcgivenzpk=1
            pcgivenzk=1
        #
        #if debug:
        #    print ("P[o|czk]",pogivenczk)
        #    print ("P[o|cz'k]",pogivenczpk,pck)
        popgivenczpk=1-pogivenczpk
        snum+=pogivenczk*pcgivenzpk ##P[o|do(z),k]
        nnum+=popgivenczpk*pcgivenzk ##P[o|do(z'),k]
        snnum+=(pogivenczk-pogivenczpk)*pck ##P[o|do(z),k]-P[o|do(z'),k]
        
        #print ("P[o|czk]",pogivenczk)
        #print ("P[o|cz'k]",pogivenczpk,pck)
        
        #if debug:
        #    print ("numerators",snum,nnum,snnum)
    
    if len(klst)>0:
        pogivenk,model_map=get_prob_o_regression(df,klst,kvallst,[target],[1],model_map)
    else:
        pogivenk=df[df[target]==1].shape[0]*1.0/df.shape[0]
    conditional=copy.deepcopy(klst)
    conditional.extend(z_attr)
    conditional_val=copy.deepcopy(kvallst)
    conditional_val.extend(z)
    pogivenzk,model_map=get_prob_o_regression(df,conditional,conditional_val,[target],[1],model_map)
    
    
    conditional_valzp=copy.deepcopy(kvallst)
    conditional_valzp.extend(zprime)
    #sample_target_zp=get_count(sample_zp[target])
    pogivenzpk,model_map=get_prob_o_regression(df,conditional,conditional_valzp,[target],[1],model_map)
    #sample_target_zp[2]*1.0/(sample_target_zp[1]+sample_target_zp[2])
    popgivenzpk=1-pogivenzpk
    
    popgivenzk=1-pogivenzk
    if pogivenzk==0:
        n=0
    else:
        n=((-popgivenzk+nnum)*1.0/pogivenzk)
    sn=(snnum)
    if popgivenzpk==0:
        s=0
    else:
        s=((snum-pogivenzpk)*1.0/popgivenzpk)
    return (n,s,sn)#,nlb,slb,newlb)#,sn_ub,n_ub,s_ub)
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_regression

def get_val(row,target,target_val):
    i=0
    while i<len(target):
        #print (row[target[i]],target_val[i])
        if not int(row[target[i]])==int(target_val[i]):
            return 0
        i+=1
    return 1
def get_count(lst):
    count={}
    uniq=list(set(lst))
    for v in uniq:
        count[v]=0
    for v in lst:
        count[v]+=1
    if 1 not in count.keys():
        count[1]=0
    if 2 not in count.keys():
        count[2]=0
    return count
    
def get_prob_o_regression(df,conditional,conditional_values,target,target_val,model_map):
    #print (target_val,df.size)
    if str(conditional)+str(target)+str(target_val) in model_map.keys():
        regr=model_map[str(conditional)+str(target)+str(target_val)]
        return  (regr.predict([conditional_values])[0],model_map)
    
    #print (df[conditional[0]].value_counts())
    new_lst=[]
    count=0
    for index,row in df.iterrows():
        new_lst.append(get_val(row,target,target_val))
        if new_lst[-1]==1:
            count+=1
    #print (conditional,conditional_values,count,df.shape)
    if len(conditional)==0 :
        return count*1.0/df.shape[0],model_map
    #pcgivenk=df[df[target]==1].shape[0]*1.0/df.shape[0]
    if len(list(set(new_lst)))==1:
        if new_lst[0]==1:
            return 1,model_map
        else:
            return 0,model_map
    if len(conditional)>0:
        X=df[conditional]
        #print (df[df[''==c[i]])
        #print (df[df[conditional[0]]==conditional_values[0]].shape)
        #df=df[df[conditional[0]]==conditional_values[0]]
        #c=(get_count(df['credit']))
        #return c[1]*1.0/(c[0]+c[1])
    else:
        X=df

    X=X[conditional]
    #regr = LogisticRegression(random_state=0)
    regr = RandomForestRegressor(random_state=0)

    regr.fit(X, new_lst)
    model_map[str(conditional)+str(target)+str(target_val)]=regr
    return (regr.predict([conditional_values])[0],model_map)
    
  

