from datetime import datetime, timedelta
from .utils import Mode, Playtime


class User:
    """Object representing JSON response from the osu! api plus some helper methods.

    Attributes:
        client: OsuClient that created the instance
        mode: enum representing the osu! gamemode this information is for
        id: id of the player
        username: player's username
        join_date: timestamp of when the player created their account
        num_300: number of 300s player has achieved
        num_100: number of 100s player has achieved
        num_50: number of 50s player has achieved
        play_count: the number of "plays" according to however osu! calculates it
        ranked_score: combination of highest submitted scores on ranked maps
        total_score: combination of highest submitted scores across all online maps
        rank: the position of the player on the global leaderboard based on their pp
        level: the player's level
        pp: the player's pp total (points received from ranked maps)
        accuracy: the player's average accuracy on a map as a percentage
        ss_count: number of SS's
        ssh_count: number of SS's with hidden
        s_count: number of S ranks
        sh_count: number of S ranks with hidden
        a_count: number of A ranks
        country: the country the player is from
        playtime: Playtime object representing how long they have played the game
        recents: dict containing a list of cached recent scores for each mode
        avatar_url: the url for their profile picture
    
    """
    def __init__(self, user_info, osu_client, mode: Mode = Mode.STANDARD):
        self.client = osu_client
        self.mode = mode
        self.id = int(user_info['user_id'])
        self.username = user_info['username']
        self.join_date = datetime.strptime(user_info['join_date'], "%Y-%m-%d %H:%M:%S")
        self.num_300 = int(user_info['count300'])
        self.num_100 = int(user_info['count100'])
        self.num_50 = int(user_info['count50'])
        self.play_count = int(user_info['playcount'])
        self.ranked_score = int(user_info['ranked_score'])
        self.total_score = int(user_info['total_score'])
        self.rank = int(user_info['pp_rank'])
        self.level = float(user_info['level'])
        self.pp = float(user_info['pp_raw'])
        self.accuracy = float(user_info['accuracy'])
        self.ss_count = int(user_info['count_rank_ss'])
        self.ssh_count = int(user_info['count_rank_ssh'])
        self.s_count = int(user_info['count_rank_s'])
        self.sh_count = int(user_info['count_rank_sh'])
        self.a_count = int(user_info['count_rank_a'])
        self.country = user_info['country']
        self.country_rank = int(user_info['pp_country_rank'])
        seconds = int(user_info['total_seconds_played'])
        self.playtime = Playtime(seconds)
        self.recents = {
            Mode.STANDARD: [],
            Mode.TAIKO: [],
            Mode.CTB: [],
            Mode.MANIA: []
        }
        self.avatar_url = f"http://s.ppy.sh/a/{self.id}"

    def fetch_best(self, mode: Mode = Mode.STANDARD, limit: int = 10):
        """Helper for collecting a user's best scores.

        Args:
            mode: enum representing osu! gamemode to request scores for
            limit: number of scores to retrieve (max 100)

        Returns:
            [Score]: List of the player's best scores
        """
        return self.client.fetch_user_best(user_id=self.id, mode=mode, limit=limit)

    def fetch_recent(self, mode: Mode = Mode.STANDARD, limit: int = 10):
        """Helper for collecting a user's recent scores.

        Args:
            mode: enum representing osu! gamemode to request scores for
            limit: number of scores to retrieve (max 100)

        Returns:
            [RecentScore]: List of the player's recent scores
        """
        self.recents[mode] = self.client.fetch_user_recent(user_id=self.id, mode=mode, limit=limit)
        return self.recents[mode]

    def fetch_new_recent(self, mode: Mode = Mode.STANDARD):
        """Retrieve any scores made since the last time this function was called.

        Args:
            mode: enum representing osu! gamemode to request scores for

        Returns:
            [RecentScore]: List of the player's scores since the most recent
        """
        now = datetime.now()
        self.recents[mode] = [score for score in self.recents[mode] if (now - timedelta(hours=24)) <= score.timestamp <= now]
        new_scores = self.client.fetch_user_recent(user_id=self.id, mode=mode, limit=100)
        if new_scores:
            dates = [score.timestamp for score in self.recents[mode]]
            new = [score for score in new_scores if score.timestamp not in dates]
            self.recents[mode] += new
            return new

    def __repr__(self):
        return self.username

