import pandas as pd
import numpy as np
import scipy
from .utils.util import _rga_delta_function

def rga(y, yhat):
    """
     ### RANK GRADUATION ACCURACY (RGA) MEASURE ###
     Function for the RGE measure computation
     Inputs: y -> Actual values of the target variable; 
             yhat -> Predictions generated by the applied selected model
    """ 
    y = pd.DataFrame(y).reset_index(drop=True)
    yhat = pd.DataFrame(yhat).reset_index(drop=True)
    df = pd.concat([y,yhat], axis=1)
    df.columns = ["y", "yhat"]
    ryhat = yhat.rank(method="min")
    df["ryhat"] = ryhat
    support = df.groupby('ryhat')['y'].mean().reset_index(name='support')
    rord = list(range(len(y)))
    for jj in range(len(rord)):
        for ii in range(len(support)):
                if df["ryhat"][jj]== support['ryhat'][ii]:
                    rord[jj] = support['support'][ii]
    vals = [[i, values] for i, values in enumerate(df["yhat"])]
    ranks = [x[0] for x in sorted(vals, key= lambda item: item[1])]
    ystar = [rord[i] for i in ranks]
    I = list(range(len(y)))
    conc = 2*sum([I[i]*ystar[i] for i in range(len(I))])
    dec= 2*sum([sorted(df["y"], reverse=True)[i]*I[i] for i in range(len(I))]) 
    inc = 2*sum([sorted(df["y"])[i]*I[i] for i in range(len(I))]) 
    RGA=(conc-dec)/(inc-dec)
    return RGA 

def rga_statistic_test(y, yhat_rm, yhat_cm):
        """
        RGA based test for comparing the predictive accuracy of a reduced model with that of a more complex model
        """
        y = pd.DataFrame(y).reset_index(drop=True)
        yhat_rm = pd.DataFrame(yhat_rm).reset_index(drop=True)
        yhat_cm = pd.DataFrame(yhat_cm).reset_index(drop=True)
        jk_mat = pd.concat([y,yhat_rm, yhat_cm], axis=1)
        jk_mat.columns = ["y", "yhat_rm", "yhat_cm"]
        n = len(jk_mat)
        index = np.arange(n)
        jk_results = []
        for i in range(n):
            jk_sample = jk_mat.drop(labels= i)
            jk_sample.reset_index(drop=True, inplace=True)
            jk_statistic = _rga_delta_function(jk_sample, rga)
            jk_results.append(jk_statistic)
        se = np.sqrt(((n-1)/n)*(sum([(x-np.mean(jk_results))**2 for x in jk_results])))
        z = (rga(y,yhat_cm)-rga(y,yhat_rm))/se
        p_value = 2*scipy.stats.norm.cdf(-abs(z))
        return p_value