import pygame
import random

WIDTH = 400
HEIGHT = 400

pygame.init()
window = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Clicker')
pygame.font.init()
font = pygame.font.SysFont('Verdana', 24)
clock = pygame.time.Clock()

# Game Data
game_data = {"score": 0,  # tracks the player's score
             "stones": 0,  # tracks how many stones we have displayed
             "spawn_chance": 0.05,  # chance of a stone spawning on the screen
             "end_time": 0,  # the time when the game should end. this will be set automatically
             "duration": 10,  # the duration of the game
             "game_over": False,  # whether or not the game is over
             "app_is_running": True}  # whether or not the app is running

# Generic Gem Info
all_stones = ['blue_crystal', 'blue_gem', 'blue_jewel',
              'green_crystal', 'green_gem', 'green_jewel',
              'red_crystal', 'red_gem', 'red_jewel',
              'yellow_crystal', 'yellow_gem', 'yellow_jewel']
images = {"blue_crystal": pygame.image.load("images/blueCrystal.png"),
          "blue_gem": pygame.image.load("images/blueGem.png"),
          "blue_jewel": pygame.image.load("images/blueJewel.png"),
          "green_crystal": pygame.image.load("images/greenCrystal.png"),
          "green_gem": pygame.image.load("images/greenGem.png"),
          "green_jewel": pygame.image.load("images/greenJewel.png"),
          "red_crystal": pygame.image.load("images/redCrystal.png"),
          "red_gem": pygame.image.load("images/redGem.png"),
          "red_jewel": pygame.image.load("images/redJewel.png"),
          "yellow_crystal": pygame.image.load("images/yellowCrystal.png"),
          "yellow_gem": pygame.image.load("images/yellowGem.png"),
          "yellow_jewel": pygame.image.load("images/yellowJewel.png")}
points = {'blue_crystal': 1,  # feel free to set these point values for each stone
          'blue_gem': 1,
          'blue_jewel': 1,
          'green_crystal': 1,
          'green_gem': 1,
          'green_jewel': 1,
          'red_crystal': 1,
          'red_gem': 1,
          'red_jewel': 1,
          'yellow_crystal': 1,
          'yellow_gem': 1,
          'yellow_jewel': 1}

# Current Gem Info
objects = []  # list of object names
x_positions = {}  # x positions of the objects
y_positions = {}  # y positions of the objects
types = {}  # types of the object (red_gem, yellow_jewel, etc)

# Helpers
def get_image(object):
    # Takes an object name and returns the image associated with it
    # We do this using the type dictionary
    #   - object: the name of the object that we want to get the image for
    #   - returns: the image of that object
    stone_type = types[object]
    return images[stone_type]

def get_dimensions(object):
    # Takes an object name and returns the dimensions of its image
    #   - object: the name of the object that we want to get the dimensions of
    #   - returns: the dimensions of the given object as a pair (width, height)
    image = get_image(object)
    w = image.get_width()
    h = image.get_height()
    return (w, h)

def seconds_remaining():
    # Calculates the seconds remaining in the game
    # Use game_data["end_time"] to get the end time in milliseconds
    # Use pygame.time.get_ticks() to get the current time in milliseconds
    # return their difference in seconds

    end_time = game_data["end_time"]
    current_time = pygame.time.get_ticks()
    seconds = (end_time - current_time) / 1000
    return seconds

def calculate_end_time():
    # Calculates and sets the end time of the game
    # Take the durations of the game (game_data["duration"]) and convert it
    # to milliseconds
    # Use pygame.time.get_ticks() to get the current time in milliseconds
    # Set the game_data["end_time"] to be the sum of these two

    duration = game_data["duration"] * 1000
    current_time = pygame.time.get_ticks()
    game_data["end_time"] = duration + current_time

# Game Management
def calculate_points(clicked):
    # Updates the number of points that a player has earned (game_data["score"])
    # using a list of clicked objects and the points dictionary.
    #   - clicked: a list of stones that were clicked

    # You have to fill this in.
    pass

def check_game_over():
    # Checks whether or not the game is over.
    # If the number of seconds remaining is less than or equal to 0, then the
    # game is over. Otherwise, it is not.

    # You have to fill this in.
    if seconds_remaining() <= 0:
        game_data["game_over"] = True

def reset():
    # Resets the game data (game_data["score"] and game_data["stones"])

    # You have to fill this in.
    pass

# Draw functions
def draw_background():
    # Draws the background
    window.fill((0, 0, 0))

def draw_objects():
    # Draws all objects
    for object in objects:
        x = x_positions[object]
        y = y_positions[object]
        image = get_image(object)
        window.blit(image, (x, y))

def draw_timer():
    # Draws the timer
    seconds = seconds_remaining()
    text = f"Time: {seconds}"
    message = font.render(text, True, (255, 255, 255))
    window.blit(message, (0, 0))

def draw_score():
    # Draws the score
    score = game_data["score"]
    text = f"Score: {score}"
    message = font.render(text, True, (255, 255, 255))
    window.blit(message, (0, 30))

def redraw():
    # Redraws the window
    draw_background()
    draw_objects()
    draw_timer()
    draw_score()
    pygame.display.update()

def draw_times_up():
    # Draws the time's up message
    message = font.render("Time's up!", True, (255, 255, 255))
    window.blit(message, (0, 0))

def draw_end_screen():
    # Draws the end screen
    draw_background()
    draw_times_up()
    draw_score()
    pygame.display.update()

# Stone Management
def was_object_clicked(mx, my, object):
    # Determines if the given object was clicked
    #   - mx: the x position the mouse clicked
    #   - my: the y position the mouse clicked
    #   - object: the name of the object that we want to test

    # To do this, you will need the (x, y) of the object and the (w, h) of
    # its image (see get_dimensions()). From there, you need to make sure that
    # the x <= mx <= x + w AND y <= my <= y + h.

    # You have to fill this in.
    x = x_positions[object]
    y = y_positions[object]
    (w, h) = get_dimensions(object)
    return x <= mx <= x + w and y <= my <= y + h

def handle_click(mx, my):
    # Determines what to update when a click is done.
    #   - mx: the x position the mouse clicked
    #   - my: the y position the mouse clicked

    # This function does several things:
    #   1. Define a clicked list
    #   2. Loop through every object and do the following
    #       a. check if it was clicked (see was_object_clicked())
    #       b. if it was clicked, add it to the clicked list
    #   3. Update the points using the clicked list (see calculate_points())
    #   4. Remove the clicked stones from the list (see remove_objects())

    clicked = []
    for object in objects:
        was_clicked = was_object_clicked(mx, my, object)
        if was_clicked:
            print(object, "was clicked")
            clicked.append(object)

    calculate_points(clicked)
    remove_objects(clicked)

def remove_objects(clicked):
    # Removes the clicked objects from the list and the dictionaries
    #   - clicked: the names of the objects that were clicked

    # To write this function, loop through all of the clicked objects and do
    # the following:
    #   1. remove the current object from the objects list (.remove())
    #   2. remove the current object from the dictionaries (.pop())
    #      the relevant dictionaries are: x_positions, y_positions, and types

    # You have to fill this in.
    pass

def spawn_stones():
    if random.random() < game_data["spawn_chance"]:
        game_data["stones"] = game_data["stones"] + 1
        key = game_data["stones"]
        type = random.choice(all_stones)
        image = images[type]
        w = image.get_width()
        h = image.get_height()
        x = random.randint(0, WIDTH - w)
        y = random.randint(0, HEIGHT - h)
        objects.append(key)
        x_positions[key] = x
        y_positions[key] = y
        types[key] = type

def clear_stones():
    # Clears all stones
    objects.clear()
    x_positions.clear()
    y_positions.clear()
    types.clear()

def run_game():
    # Runs the game
    calculate_end_time()
    while game_data["app_is_running"] == True and game_data["game_over"] == False:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_q:
                    game_data["app_is_running"] = False
            if event.type == pygame.MOUSEBUTTONDOWN:
                (mx, my) = pygame.mouse.get_pos()
                handle_click(mx, my)

        spawn_stones()
        redraw()
        check_game_over()
        clock.tick(30)

def game_over():
    # Runs the game over screen
    while game_data["app_is_running"] == True and game_data["game_over"] == True:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_q:
                    game_data["app_is_running"] = False
                elif event.key == pygame.K_r:
                    game_data["game_over"] = False

        draw_end_screen()
        clock.tick(10)

def run_app():
    # Runs the whole app and manages switching between screens
    while game_data["app_is_running"] == True:
        run_game()
        clear_stones()
        game_over()
        reset()

    pygame.quit()

run_app()
