import pprint


############################################################
# code debugging exercise
############################################################


# The following code is an extension of the assignment scores scenario
# from Monday's lecture. However, we're using the nested dictionaries
# representation, instead of classes, so we can focus on other aspects.

# Towards the end of this file, the review_scores() function performs
# several operations on the data within a scorebook dict. Unfortunately,
# there is a problem with or within almost every operation in that
# function.

# When you run this file as-is, it will attempt to create a scorebook
# dict and run review_scores() on it, while printing the scorebook
# before and after. However, the code will encounter some errors and not
# run to completion. Even after those issues are fixed, you will likely
# find that the ending printout of the scorebook is incorrect.

# On your own, try to identify and fix as many issues as you can. In
# class tomorrow, we will review what they are, and then discuss
# additional Python features that can help us avoid such bugs.


def weighted_average(scores, weights=None):
    if weights is None:
        weights = [1 for _ in scores]
    weighted_scores = [scores[i] * weights[i] for i in range(len(scores))]
    return sum(weighted_scores) / sum(weights)


def calculate_total(student):
    return weighted_average(
        [weighted_average(student["psets"]), weighted_average(student["exams"])],
        [2, 3, 7],
    )


def make_scorebook():
    gb = {}
    gb["richboi"] = {"psets": [10, 9, 8], "exams": [8, 7]}
    gb["vibegrl"] = {"psets": [8, 10, 10], "exams": [7, 9]}
    gb["limbo"] = {"psets": [7, 9, 6], "exams": [5, 8]}
    return gb


def get_score(gb, user, category, num):
    return gb[user][category][num]


def add_score(gb, user, category, score):
    return gb[user][category].append(score)


def edit_score(gb, user, category, num, score):
    return gb[user][category][num] = score


def review_scores(gb):
    # retrieve pset score
    riri_ps3 = get_score(gb, "vibegrl", "psets", 3)
    print(f"{riri_ps3 = }")

    # regrade request for riri
    edit_score(gb, "vibegrl", "exams", 2, 10)

    # regrade requests for tony
    edit_score(gb, "richboi", "pset", 2, 6)
    edit_score(gb, "richboi", "pset", -2, 10)
    add_score(gb, "richboi", "pset", 12)

    # late-add for felicity from DC universe
    gb["smoaksig"] = gb["vibegrl"].copy()
    edit_score(gb, "smoaksig", "exams", 1, 10)
    edit_score(gb, "smoaksig", "exams", 2, 8)

    # view averages
    for kerb in "richboi", "vibegrl", "limbo", "smoaksig":
        avg = calculate_total(gb[kerb])
        print(f"{kerb:<10}  {avg:.6f}")


scorebook = make_scorebook()

print()
pprint.pp(scorebook)

print()
review_scores(scorebook)

print()
pprint.pp(scorebook)
