import pandas as pd
import numpy as np


def rga(y, yhat):
        """
        RANK GRADUATION ACCURACY (RGA) MEASURE 
        Function for the RGA measure computation

        Inputs:
        y    : Actual values of the target variable 
        yhat : Predicted values generated by the model 
        
        Returns:
        RGA  : Calculated RGA measure
        """
        # Convert inputs to DataFrames and concatenate them
        y = pd.DataFrame(y).reset_index(drop=True)
        yhat = pd.DataFrame(yhat).reset_index(drop=True)

        if y.shape != yhat.shape:
                raise ValueError("y and yhat should have the same shape.")

        df = pd.concat([y, yhat], axis=1)
        df.columns = ["y", "yhat"]

        if df.isna().sum().sum() > 0:
                raise ValueError("There are missing values.")
              
        # Rank yhat values
        df['ryhat'] = df['yhat'].rank(method="min")

        # Group by ryhat and calculate mean of y (support)
        support = df.groupby('ryhat')['y'].mean().reset_index(name='support')

        # Merge support back to the original dataframe
        df = pd.merge(df, support, on="ryhat", how="left")

        # Create the rord column by directly assigning 'support' where ryhat matches
        df['rord'] = df['support']
        
        # Sort df by yhat to get correct ordering for ystar
        df = df.sort_values(by="yhat").reset_index(drop=True)

        # Get ystar in the same order as rord in the sorted dataframe
        ystar = df['rord'].values

        # Create the index array I
        I = np.arange(len(df))

        # Calculate conc, dec (descending order of y) and inc (ascending order of y)
        conc = np.sum(I * ystar)
        sorted_y = np.sort(df['y'])  # y sorted in ascending order
        dec = np.sum(I * sorted_y[::-1])  # y sorted in descending order
        inc = np.sum(I * sorted_y)

        # Compute the RGA
        RGA = (conc - dec) / (inc - dec)

        return RGA