from secret.achievements.utils import achievements_response


class Chart:
    """
    Chart base class
    """
    
    
    def __init__(self, id_, url, name):
        """
        Initializes a new chart.

        :param id_: chart id. Currently known values are 'beatmap' and 'overall'
        :param url: URL to open when clicking on the chart title.
        :param name: chart name displayed in the game client
        """
        self.id_ = id_
        self.url = url
        self.name = name

    def items(self):
        """
        `items()` method that allows this class to be used as a iterable dict

        :return:
        """
        return self.output_attrs.items()

    @property
    def output_attrs(self):
        """
        An unzingonified dict containing the stuff that will be sent to the game client

        :return: dict
        """
        return {
            "chartId": self.id_,
            "chartUrl": self.url,
            "chartName": self.name
        }

    @staticmethod
    def before_after_dict(name, values, none_value="0"):
        """
        Turns a tuple with two elements in a dict with two elements.

        :param name: prefix of the keys
        :param values: (value_before, value_after). value_before and value_after can be None.
        :param none_value: value to use instead of None (None, when zingonified, is not recognized by the game client)
        :return: { XXXBefore -> first element, XXXAfter -> second element }, where XXX is `name`
        """
        return {
            f"{name}{'Before' if i == 0 else 'After'}": x if x is not None else none_value for i, x in enumerate(values)
        }


class BeatmapChart(Chart):
    """
    Beatmap ranking chart
    """
    def __init__(self, old_score, new_score, beatmap_id):
        """
        Initializes a new BeatmapChart object.

        :param old_score: score object of the old score
        :param new_score: score object of the currently submitted score
        :param beatmap_id: beatmap id, for the clickable link
        """
        super(BeatmapChart, self).__init__("beatmap", f"https://akatsuki.pw/b/{beatmap_id}", "Beatmap Ranking")
        self.rank = (old_score.rank if old_score is not None else None, new_score.rank)
        self.max_combo = (old_score.maxCombo if old_score is not None else None, new_score.maxCombo)
        self.accuracy = (old_score.accuracy * 100 if old_score is not None else None, new_score.accuracy * 100)
        self.ranked_score = (old_score.score if old_score is not None else None, new_score.score)
        self.pp = (old_score.pp if old_score is not None else None, new_score.pp)
        self.score_id = new_score.scoreID

    @property
    def output_attrs(self):
        return {
            **super(BeatmapChart, self).output_attrs,
            **self.before_after_dict("rank", self.rank, none_value=""),
            **self.before_after_dict("maxCombo", self.max_combo),
            **self.before_after_dict("accuracy", self.accuracy),
            **self.before_after_dict("rankedScore", self.ranked_score),
            **self.before_after_dict("totalScore", self.ranked_score),
            **self.before_after_dict("pp", self.pp),
            "onlineScoreId": self.score_id
        }


class OverallChart(Chart):
    """
    Overall ranking chart  achievements
    """
    def __init__(self, user_id, old_user_stats, new_user_stats, bi, score, new_achievements, old_rank, new_rank):
        """
        Initializes a new OverallChart object.
        This constructor sucks because LETS itself sucks.

        :param user_id: id of the user
        :param old_user_stats: user stats dict before submitting the score
        :param new_user_stats: user stats dict after submitting the score
        :param score: score object of the scores that has just been submitted
        :param new_achievements: achievements unlocked list
        :param old_rank: global rank before submitting the scpre
        :param new_rank: global rank after submitting the score
        """
        super(OverallChart, self).__init__("overall", f"https://akatsuki.pw/u/{user_id}", "Overall Ranking")
        self.rank = (old_rank, new_rank)
        self.ranked_score = (old_user_stats["rankedScore"], new_user_stats["rankedScore"])
        self.total_score = (old_user_stats["totalScore"], new_user_stats["totalScore"])
        self.max_combo = (bi.maxCombo, bi.maxCombo)
        self.accuracy = (old_user_stats["accuracy"], new_user_stats["accuracy"])
        self.pp = (old_user_stats["pp"], new_user_stats["pp"])
        self.new_achievements = new_achievements
        self.score_id = score.scoreID

    @property
    def output_attrs(self):
        return {
            **super(OverallChart, self).output_attrs,
            **self.before_after_dict("rank", self.rank),
            **self.before_after_dict("rankedScore", self.ranked_score),
            **self.before_after_dict("totalScore", self.total_score),
            **self.before_after_dict("maxCombo", self.max_combo),
            **self.before_after_dict("accuracy", self.accuracy),
            **self.before_after_dict("pp", self.pp),
            "achievements-new": achievements_response(self.new_achievements),
            "onlineScoreId": self.score_id
        }
