"""
Created on Sep 30, 2022

@author: Robert Duvall

This module represents a template for making Turtle games.
"""
import random
import turtle


# Choose a name for your game to appear in the title bar of the game window
gameName = 'TO BE DETERMINED'
# Choose the size of your game window
screenWidth = 1000
screenHeight = 1000
# Choose how fast player moves
speedIncrement = 0.25
speedMax = 5
# NO NEED TO CHANGE - create the game window based on the choices above
theScreen = turtle.Screen()
theScreen.title(gameName)
theScreen.setup(screenWidth, screenHeight)
# move turtles as fast as possible
theScreen.tracer(False)


class Mover:
    """
    This class represents a user controlled object that moves around the screen.
    """
    def __init__(self, color):
        self.yurtle = turtle.Turtle()
        self.color = color
        self.dx = 0
        self.dy = 0
        # assume the base turtle size
        self.width = 20
        self.height = 20

    def draw(self):
        """
        Draw as a basic circle.
        """
        self.yurtle.speed(0)
        self.yurtle.shape('circle')
        self.yurtle.color(self.color)

    def move(self):
        """
        Move based on current velocity (dx, dy).
        """
        self.yurtle.goto(self.yurtle.xcor() + self.dx, self.yurtle.ycor() + self.dy)

    def reset(self, x, y):
        """
        Reset to given XY coordinate and randomize velocity.
        """
        self.goto(x, y)
        self.dx = random.randint(-2, 2)
        self.dy = random.randint(-2, 2)

    def goto(self, x, y):
        """
        Wrap to other side of the screen without leaving a trail.
        """
        self.yurtle.penup()
        self.yurtle.goto(x, y)
        self.yurtle.pendown()


class Target:
    """
    This class represents a target to try to hit.
    """
    def __init__(self, size):
        self.yurtle = turtle.Turtle()
        # size compared to the base turtle size
        self.size = size
        self.width = size * 20
        self.height = size * 20

    def draw(self):
        """
        Draw as a sized square.
        """
        self.yurtle.speed(0)
        self.yurtle.penup()
        self.yurtle.shape('square')
        self.yurtle.shapesize(self.size)

    def reset(self):
        """
        Reset to a random location and change to a random color.
        """
        self.yurtle.color(random.random(), random.random(), random.random())
        self.yurtle.goto(random.randint(-screenWidth // 2 + self.width // 2, screenWidth // 2 - self.width // 2),
                         random.randint(-screenHeight // 2 + self.height // 2, screenHeight // 2 - self.height // 2))

    def is_a_hit(self, gameObject):
        """
        Return true if the given objects are close enough to intersect.
        """
        x1 = gameObject.yurtle.xcor()
        y1 = gameObject.yurtle.ycor()
        x2 = self.yurtle.xcor()
        y2 = self.yurtle.ycor()
        width = (gameObject.width + self.width) // 2
        height = (gameObject.height + self.height) // 2
        return (x1 - width < x2 < x1 + width) and (y1 - height < y2 < y1 + height)


#
# Functions for interacting with the keyboard or mouse
# Since these are called by the turtle module (not you directly), you must accept these exact parameters (or none)
#
def move_up_on_key():
    theMover.dy = min(theMover.dy + speedIncrement, speedMax)
    theScreen.update()
    print(theMover.dx, theMover.dy)

def move_down_on_key():
    theMover.dy = max(theMover.dy - speedIncrement, -speedMax)
    theScreen.update()
    print(theMover.dx, theMover.dy)

def move_left_on_key():
    theMover.dx = max(theMover.dx - speedIncrement, -speedMax)
    theScreen.update()
    print(theMover.dx, theMover.dy)

def move_right_on_key():
    theMover.dx = min(theMover.dx + speedIncrement, speedMax)
    theScreen.update()
    print(theMover.dx, theMover.dy)

def reset_on_click(x, y):
    theMover.reset(x, y)
    theScreen.update()


def setup_interaction(screen):
    """
    Sets up the keyboard and/or mouse interaction in the game

    Note, the function NAME is the parameter, not the result of calling it
    """
    # listen for interaction from user
    screen.listen()
    screen.onkeypress(move_up_on_key, 'w')
    screen.onkeypress(move_down_on_key, 's')
    screen.onkeypress(move_left_on_key, 'a')
    screen.onkeypress(move_right_on_key, 'd')
    screen.onclick(reset_on_click)


#
# Functions for drawing or positioning the game objects
#
def draw_scene():
    """
    Draw the game's setting and its objects.
    """
    theScreen.bgcolor('lightblue')

    theMover.draw()
    theTarget.draw()

    theMover.reset(0, 0)
    theTarget.reset()


#
# The main game "loop"
#
def game_step():
    """
    Handle game "rules" for every step (i.e., frame or "moment"):
     - movement: move the game objects each step
     - collisions: check if the game objects collided with each other or the sides and respond appropriately
    """
    gameIsOver = False

    # move game object based on its speed
    theMover.move()

    # check if mover hits left or right side, wrap it to the other side
    if theMover.yurtle.xcor() < -screenWidth // 2:
        theMover.goto(screenWidth // 2, theMover.yurtle.ycor())
    elif theMover.yurtle.xcor() > screenWidth // 2:
        theMover.goto(-screenWidth // 2, theMover.yurtle.ycor())

    # check if mover hits top or bottom side, wrap it to the other side
    if theMover.yurtle.ycor() < -screenHeight // 2:
        theMover.goto(theMover.yurtle.xcor(), screenHeight // 2)
    elif theMover.yurtle.ycor() > screenHeight // 2:
        theMover.goto(theMover.yurtle.xcor(), -screenHeight // 2)

    # check if mover hits target, move target to new random location and "bounce" mover
    if theTarget.is_a_hit(theMover):
        theMover.reset(theMover.yurtle.xcor(), theMover.yurtle.ycor())
        theTarget.reset()

    # NO NEED TO CHANGE - required to see the changes made to the turtles and keep the game running
    theScreen.update()
    if not gameIsOver:
        theScreen.ontimer(game_step, 10)


#
# Create the classes and call the functions defined above
#

# Create the game objects
theMover = Mover('orchid')
theTarget = Target(2)
# Draw the game objects
draw_scene()

# NO NEED TO CHANGE - typical code to get the game started
# Make the game interactive
setup_interaction(theScreen)
# Show the results
theScreen.update()
# Start game's mainloop
theScreen.ontimer(game_step, 10)
# Play the game forever
theScreen.mainloop()
