from core.explanations.utils import bitmask_to_list


class BaseExplanationAnalyzer:

    @staticmethod
    def calc_feature_importance(explanations, sample_size):
        feature_importance = {n: 0.0 for n in range(sample_size)}

        if len(explanations) == 0:
            return {k: feature_importance[k] for k in sorted(feature_importance)}

        for explanation_bitmask in explanations:
            if explanation_bitmask == 0:
                continue

            explanation = bitmask_to_list(explanation_bitmask, sample_size)

            for feature in explanation:
                # The importance of each feature is relative to the size of the explanation
                feature_importance[feature] += 1.0 / len(explanation)

        # Normalize the feature importance
        total_importance = sum(feature_importance.values())
        for feature in feature_importance:
            feature_importance[feature] /= total_importance

        return {k: feature_importance[k] for k in sorted(feature_importance)}

    @staticmethod
    def calc_feature_ranking(feature_importance):
        """
        Returns a tuple:
        - permutation: list of feature indices sorted by importance (descending)
        - ranks: list where the i-th entry is the rank of feature i
        """
        permutation = sorted(feature_importance, key=feature_importance.get, reverse=True)
        ranks = BaseExplanationAnalyzer.permutation_to_ranks(permutation)
        return ranks

    @staticmethod
    def permutation_to_ranks(perm):
        """
        Converts a permutation (list of feature indices in order of importance) to a rank vector.
        The i-th entry in the output is the rank of feature i.
        """
        perm = list(map(int, perm))
        ranks = [0 for _ in range(len(perm))]
        for rank, feature in enumerate(perm):
            ranks[feature] = rank
        return ranks
