import datetime
from typing import Union
import os

from sheets import Spreadsheet
from date_validation import ensure_valid_date, date_validate_args, split_into_year_month
import api
import files


JsonFormat = dict[str, dict[str, list[int]]]


class ScoreCompare:
    """Main class responsible for preparing score comparison info to be filled into Google Sheets."""
    def __init__(self, parser_args):
        self.args = parser_args
        self.all_mapset_ids: JsonFormat = files.get_mapset_ids()
        self.user_ids: list[str] = ["7051163", "3172980", "2927048", "7635621", "9217626"]
        self.spreadsheet: Spreadsheet = Spreadsheet()

        self.year: str = ""
        self.month: str = ""

    def main(self):
        """Can someone teach me how to properly use arg parsers?"""
        if self.args.all:
            self.go_through_set_ids()
            return

        date_validate_args(self.args)

        if self.args.year:
            self.year_ids()
        elif self.args.yearmonth:
            self.yearmonth_ids()
        elif self.args.yrange:
            self.year_range_ids()
        elif self.args.ymrange:
            self.yearmonth_range_ids()

    def year_ids(self):
        for year in self.args.year:
            year = int(year)

            month = 1
            if year == 2007:
                month = 10

            self.go_through_set_ids(start_year=year, start_month=month, end_year=year, end_month=12)

    def yearmonth_ids(self):
        for ym in self.args.yearmonth:
            y, m = split_into_year_month(ym)
            self.go_through_set_ids(start_year=y, start_month=m, end_year=y, end_month=m)

    def year_range_ids(self):
        start_year = int(self.args.yrange[0])
        end_year = int(self.args.yrange[1])

        month = 1
        if start_year == 2007:
            month = 10
        self.go_through_set_ids(start_year=start_year, start_month=month, end_year=end_year, end_month=12)

    def yearmonth_range_ids(self):
        y1, m1 = split_into_year_month(self.args.ymrange[0])
        y2, m2 = split_into_year_month(self.args.ymrange[1])
        self.go_through_set_ids(start_year=y1, start_month=m1, end_year=y2, end_month=m2)

    def go_through_set_ids(self, start_year=2007, start_month=10, end_year=None, end_month=None):
        """Iterates through the map ids from a given start month to a given end month."""
        for year, month in year_month_generator(start_year, start_month):
            self.year = year
            self.month = month

            self.go_through_month_set_ids()

            if self.year == str(end_year) and self.month == str(end_month).rjust(2, "0"):
                break

    def go_through_month_set_ids(self):
        """Checks if beatmap info already exists"""
        if self._determine_csv_generation():
            files.generate_csv(self.year, self.month)
            self.fill_in_beatmap_data()

        if self._determine_sheet_fill():
            self.fill_in_scores()

    def _determine_csv_generation(self):
        return (
            (self.args.file and f"beatmaps{self.year}-{self.month}.csv" not in os.listdir("beatmapdata"))
            or self.args.replace
        )

    def _determine_sheet_fill(self):
        return self.args.sheet

    def fill_in_beatmap_data(self):
        """Fills in Google Sheet with beatmap data."""
        beatmaps = files.file_to_beatmap_list(self.year, self.month)
        self.spreadsheet.create_new_worksheet(self.year, self.month, len(beatmaps))
        self.spreadsheet.update_map_data(self.year, self.month, beatmaps)

    def fill_in_scores(self):
        """Fills in Google Sheet with score data."""
        scores = self.get_scores()
        self.spreadsheet.update_score_data(self.year, self.month, scores)

    def get_scores(self) -> dict[str, list]:
        """Retrieves scores for each player and stores them in a dictionary."""
        map_ids = files.file_to_beatmap_ids(self.year, self.month)
        scores_dict = {user_id: [] for user_id in ["dates"] + self.user_ids}

        maps_num = len(map_ids)
        for i, map_id in enumerate(map_ids, start=1):
            print(f"{self.year}-{self.month} Progress: {i}/{maps_num}")
            scores = self._get_scores_from_map(map_id)

            for score, score_list in zip(scores, scores_dict.values()):
                score_list.append(score)

        return scores_dict

    def _get_scores_from_map(self, map_id: str) -> list[Union[int, str]]:
        scores = api.get_top_100_scores(map_id)
        score_dict = {user_id: None for user_id in self.user_ids}

        for score in scores:
            if (user_id := score["user_id"]) in score_dict.keys():
                score_dict[user_id] = (score["score"], score["date"])

        score_list = [
            score_dict[user_id] or api.get_score(map_id, user_id)
            for user_id in self.user_ids
        ]

        return self._get_relevant_data_for_scores(score_list)

    def _get_relevant_data_for_scores(self, scores: list) -> list[str, int]:
        return [
            self._get_date(scores[0][1]),
            int(scores[0][0]),
            int(scores[1][0]),
            int(scores[2][0]),
            int(scores[3][0]),
            int(scores[4][0]),
        ]

    @staticmethod
    def _get_date(date: str) -> str:
        if date:
            return date.split()[0]
        return date


def year_month_generator(start_year: int = 2007, start_month: int = 10) -> tuple[str, str]:
    """Generator which iterates over all the years and months for osu!std maps."""
    ensure_valid_date(start_year, start_month)
    today = datetime.date.today()

    year = start_year
    month = start_month

    while True:
        if year == today.year and month >= today.month:
            break

        yield str(year), str(month).rjust(2, "0")

        if month == 12:
            year += 1
            month = 0

        month += 1


if __name__ == "__main__":
    pass

import datetime
from typing import Union
import os

from sheets import Spreadsheet
from date_validation import ensure_valid_date, date_validate_args, split_into_year_month
import api
import files


JsonFormat = dict[str, dict[str, list[int]]]


class ScoreCompare:
    """Main class responsible for preparing score comparison info to be filled into Google Sheets."""
    def __init__(self, parser_args):
        self.args = parser_args
        self.all_mapset_ids: JsonFormat = files.get_mapset_ids()
        self.user_ids: list[str] = ["7051163", "3172980", "2927048", "7635621", "9217626"]
        self.spreadsheet: Spreadsheet = Spreadsheet()

        self.year: str = ""
        self.month: str = ""

    def main(self):
        """Can someone teach me how to properly use arg parsers?"""
        if self.args.all:
            self.go_through_set_ids()
            return

        date_validate_args(self.args)

        if self.args.year:
            self.year_ids()
        elif self.args.yearmonth:
            self.yearmonth_ids()
        elif self.args.yrange:
            self.year_range_ids()
        elif self.args.ymrange:
            self.yearmonth_range_ids()

    def year_ids(self):
        for year in self.args.year:
            year = int(year)

            month = 1
            if year == 2007:
                month = 10

            self.go_through_set_ids(start_year=year, start_month=month, end_year=year, end_month=12)

    def yearmonth_ids(self):
        for ym in self.args.yearmonth:
            y, m = split_into_year_month(ym)
            self.go_through_set_ids(start_year=y, start_month=m, end_year=y, end_month=m)

    def year_range_ids(self):
        start_year = int(self.args.yrange[0])
        end_year = int(self.args.yrange[1])

        month = 1
        if start_year == 2007:
            month = 10
        self.go_through_set_ids(start_year=start_year, start_month=month, end_year=end_year, end_month=12)

    def yearmonth_range_ids(self):
        y1, m1 = split_into_year_month(self.args.ymrange[0])
        y2, m2 = split_into_year_month(self.args.ymrange[1])
        self.go_through_set_ids(start_year=y1, start_month=m1, end_year=y2, end_month=m2)

    def go_through_set_ids(self, start_year=2007, start_month=10, end_year=None, end_month=None):
        """Iterates through the map ids from a given start month to a given end month."""
        for year, month in year_month_generator(start_year, start_month):
            self.year = year
            self.month = month

            self.go_through_month_set_ids()

            if self.year == str(end_year) and self.month == str(end_month).rjust(2, "0"):
                break

    def go_through_month_set_ids(self):
        """Checks if beatmap info already exists"""
        if self._determine_csv_generation():
            files.generate_csv(self.year, self.month)
            self.fill_in_beatmap_data()

        if self._determine_sheet_fill():
            self.fill_in_scores()

    def _determine_csv_generation(self):
        return (
            (self.args.file and f"beatmaps{self.year}-{self.month}.csv" not in os.listdir("beatmapdata"))
            or self.args.replace
        )

    def _determine_sheet_fill(self):
        return self.args.sheet

    def fill_in_beatmap_data(self):
        """Fills in Google Sheet with beatmap data."""
        beatmaps = files.file_to_beatmap_list(self.year, self.month)
        self.spreadsheet.create_new_worksheet(self.year, self.month, len(beatmaps))
        self.spreadsheet.update_map_data(self.year, self.month, beatmaps)

    def fill_in_scores(self):
        """Fills in Google Sheet with score data."""
        scores = self.get_scores()
        self.spreadsheet.update_score_data(self.year, self.month, scores)

    def get_scores(self) -> dict[str, list]:
        """Retrieves scores for each player and stores them in a dictionary."""
        map_ids = files.file_to_beatmap_ids(self.year, self.month)
        scores_dict = {user_id: [] for user_id in ["dates"] + self.user_ids}

        maps_num = len(map_ids)
        for i, map_id in enumerate(map_ids, start=1):
            print(f"{self.year}-{self.month} Progress: {i}/{maps_num}")
            scores = self._get_scores_from_map(map_id)

            for score, score_list in zip(scores, scores_dict.values()):
                score_list.append(score)

        return scores_dict

    def _get_scores_from_map(self, map_id: str) -> list[Union[int, str]]:
        scores = api.get_top_100_scores(map_id)
        score_dict = {user_id: None for user_id in self.user_ids}

        for score in scores:
            if (user_id := score["user_id"]) in score_dict.keys():
                score_dict[user_id] = (score["score"], score["date"])

        score_list = [
            score_dict[user_id] or api.get_score(map_id, user_id)
            for user_id in self.user_ids
        ]

        return self._get_relevant_data_for_scores(score_list)

    def _get_relevant_data_for_scores(self, scores: list) -> list[str, int]:
        return [
            self._get_date(scores[0][1]),
            int(scores[0][0]),
            int(scores[1][0]),
            int(scores[2][0]),
            int(scores[3][0]),
            int(scores[4][0]),
        ]

    @staticmethod
    def _get_date(date: str) -> str:
        if date:
            return date.split()[0]
        return date


def year_month_generator(start_year: int = 2007, start_month: int = 10) -> tuple[str, str]:
    """Generator which iterates over all the years and months for osu!std maps."""
    ensure_valid_date(start_year, start_month)
    today = datetime.date.today()

    year = start_year
    month = start_month

    while True:
        if year == today.year and month >= today.month:
            break

        yield str(year), str(month).rjust(2, "0")

        if month == 12:
            year += 1
            month = 0

        month += 1


if __name__ == "__main__":
    pass

Main class responsible for preparing score comparison info to be filled into Google Sheets. Can someone teach me how to properly use arg parsers? Iterates through the map ids from a given start month to a given end month. Checks if beatmap info already exists Fills in Google Sheet with beatmap data. Fills in Google Sheet with score data. Retrieves scores for each player and stores them in a dictionary. Generator which iterates over all the years and months for osu!std maps.