class GameView(arcade.View):
    def __init__(self):
        """
		Sets up the initial conditions of the game
		:param width: Screen width
		:param height: Screen height
		"""
        super().__init__()
        self.background = arcade.load_texture("images/space1.png")
        self._keys = set()
        self.score = 0
        self.lives = PLAYER_LIVES

        self.delay = START_DELAY

        self.window.set_mouse_visible(False)
        #Objects
        self.dashboard = Dashboard()
        self.ship = Ship()

        # bullet Sprites
        self.bullets = SpriteList()
        # how many bullets you're allowed to make
        self.ammo = 5

        self.meteors = SpriteList()
        self.animations = SpriteList()
        self.lifeList = SpriteList()

        #Explosion Frames
        self.explosion_texture_list = createExplosionTextureList()
        self.animationsLoaded = False
        self.load_animantion_frames()

        # Load sounds. Sounds from kenney.nl
        self.gun_sound = arcade.sound.load_sound(
            ":resources:sounds/laser2.wav")
        self.hit_sound = arcade.sound.load_sound(
            ":resources:sounds/explosion2.wav")

        arcade.set_background_color(arcade.color.ARSENIC)

        #This is for the lives
        start_x = 20
        x = 0
        start_y = SCREEN_HEIGHT - 125
        for life in range(self.lives):
            heart = Sprite('images/heart.png')
            heart.scale = 0.1
            x = start_x + (life * (heart.width / 2) + 10)
            heart.center_x = x
            heart.center_y = start_y

            self.lifeList.append(heart)

    def on_draw(self):
        """
		Called automatically by the arcade framework.
		Handles the responsiblity of drawing all elements.
		"""
        # clear the screen to begin drawing
        arcade.start_render()
        arcade.draw_lrwh_rectangle_textured(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
                                            self.background)
        self.dashboard.draw()
        self.draw_score()
        self.bullets.draw()
        self.meteors.draw()
        #Check if the ship is still alive
        if (self.ship.alive):
            self.ship.draw()

        #Render current animations
        self.animations.draw()

        #Verify if animations have been loaded else display a "get ready" message
        if (not self.animationsLoaded):
            self.draw_get_ready()

        #Draw the hearts on the screen
        self.lifeList.draw()

    def draw_score(self):
        """
		Puts the current score on the screen
		"""
        score_text = f"Score: {self.score}"
        start_x = 20
        start_y = SCREEN_HEIGHT - 100

        arcade.draw_rectangle_filled(self.dashboard.right // 2,
                                     SCREEN_HEIGHT - 70,
                                     self.dashboard.right + 1, 140,
                                     arcade.color.DARK_MIDNIGHT_BLUE)
        arcade.draw_text(score_text,
                         start_x=start_x,
                         start_y=start_y,
                         font_size=30,
                         color=arcade.color.WHITE)

        text = f"Ammo: {self.ammo}"
        arcade.draw_text(text,
                         start_x,
                         SCREEN_HEIGHT - (SCREEN_HEIGHT // 1.10),
                         font_size=30,
                         color=arcade.color.WHITE)

    def draw_get_ready(self):
        """
		Writes a get ready message on the screen 
		"""
        arcade.draw_text("Get ready", ((SCREEN_WIDTH - DASHBOARD_WIDTH) / 2) +
                         DASHBOARD_WIDTH,
                         SCREEN_HEIGHT / 2,
                         arcade.color.WHITE,
                         font_size=30,
                         anchor_x="center")

    def update(self, delta_time):
        """
		Update each object in the game.
		:param delta_time: tells us how much time has actually elapsed
		"""

        # Check to see if keys are being held, and then
        # take appropriate action
        self.check_keys()
        self.check_off_screen()

        self.bullets.update()

        self.meteors.update()

        if (self.animationsLoaded):
            if randint(0, self.delay) == 1:
                self.create_meteor()

        self.ship.update()

        self.check_collisions()

        self.animations.update()

        #Check if animations have already been loaded
        if (not self.animationsLoaded):
            self.check_animations_loaded()

        #Check if the ship is still alive
        if (not self.ship.alive):
            #Check if there ship has  frames left
            #This gives time for  the explosion of the ship to appear on the screen
            if (self.ship.framesAfterDead == 0):
                self.gameOver()
            else:
                self.ship.framesAfterDead = self.ship.framesAfterDead - 1

    def check_collisions(self):
        for meteor in self.meteors:
            #Check if a meteor collided with a bullet
            if meteor.collides_with_list(self.bullets):
                meteor.alive = False
                # Instantiate an explosion
                self.create_explosion(meteor.center_x, meteor.center_y)
                arcade.sound.play_sound(self.hit_sound)
                self.score += 10

            #Create a temp list for the ship
            ship = SpriteList()
            ship.append(self.ship)
            #Check if a meteor collided with the ship
            if meteor.collides_with_list(ship):
                meteor.alive = False
                self.ship.alive = False
                # Instantiate an explosion
                self.create_explosion(meteor.center_x, meteor.center_y)
                arcade.sound.play_sound(self.hit_sound)

            #Check if a meteor crossed the bottom screen
            elif meteor.bottom <= 10:
                self.create_explosion(meteor.center_x, meteor.center_y)
                arcade.sound.play_sound(self.hit_sound)
                self.lives -= 1
                self.lifeList.remove(self.lifeList[-1])
                meteor.alive = False
                if self.lives <= 0:
                    self.gameOver()

        #Check if a bullet collided with a meteor
        for bullet in self.bullets:
            if bullet.collides_with_list(self.meteors):
                bullet.alive = False

        #Remove all dead sprites
        self.clean_up_zombies()

    def clean_up_zombies(self):
        for meteor in self.meteors:
            if not meteor.alive:
                self.meteors.remove(meteor)

        for bullet in self.bullets:
            if not bullet.alive:
                self.bullets.remove(bullet)

    def check_off_screen(self):
        """ 
		Removes sprites that have gone off screen
		"""
        for bullet in self.bullets:
            if bullet.bottom > SCREEN_HEIGHT + bullet.height:
                self.bullets.remove(bullet)

    def check_keys(self):
        """
		Checks to see if the user is holding down an
		arrow key, and if so, takes appropriate action.
		"""
        if arcade.key.LEFT in self._keys:
            self.ship.move_left()
        elif arcade.key.RIGHT in self._keys:
            self.ship.move_right()

    def on_key_press(self, key, key_modifiers):
        """
		Called when a key is pressed. Sets the state of
		holding an arrow key.
		:param key: The key that was pressed
		:param key_modifiers: Things like shift, ctrl, etc
		"""
        #Wait for animations to be loaded before accepting user input
        if (self.animationsLoaded):
            if key == arcade.key.LEFT:
                self._keys.add(key)

            if key == arcade.key.RIGHT:
                self._keys.add(key)

            if key == arcade.key.SPACE:
                self.create_bullet()

        if key == arcade.key.A or key == arcade.key.S or key == arcade.key.D or key == arcade.key.F:

            if self.dashboard.check_answer(key):

                self.reload()
                # !!!!!!!!!!!!!
                # TODO: Add display for right/wrong answer and its consequences
                # !!!!!!!!!!!!!
            else:
                self.lives -= 1
                self.lifeList.remove(self.lifeList[-1])
                if self.lives <= 0:
                    self.gameOver()

        if key == arcade.key.F1:
            # User hits s. Flip between full and not full screen.
            self.window.set_fullscreen(not self.window.fullscreen)
            # Instead of a one-to-one mapping, stretch/squash window to match the
            # constants. This does NOT respect aspect ratio. You'd need to
            # do a bit of math for that.
            self.window.set_viewport(0, SCREEN_WIDTH, 0, SCREEN_HEIGHT)

        if key == arcade.key.ESCAPE:
            self.gameOver()

    def on_key_release(self, key, key_modifiers):
        """
		Called when a key is released. Sets the state of
		the arrow key as being not held anymore.
		:param key: The key that was pressed
		:param key_modifiers: Things like shift, ctrl, etc
		"""
        #The game is waiting  for animations to be loaded before accepting user input
        if (self.animationsLoaded) and len(self._keys) > 0:
            if key == arcade.key.LEFT:
                self._keys.remove(key)

            if key == arcade.key.RIGHT:
                self._keys.remove(key)

    def create_bullet(self):
        """
		Creates an instance of laser and appends it to the bullets sprite list
		"""
        if self.ammo > 0:
            laser = Laser(self.ship.center_x, self.ship.center_y)
            self.bullets.append(laser)
            arcade.sound.play_sound(self.gun_sound)
            self.ammo -= 1

    def reload(self):
        self.ammo += 5

    def create_meteor(self):
        """
		Creates an instance of Meteor and appends it to the meteors sprite list
		"""
        self.meteors.append(Meteor())

    def create_explosion(self, x, y):
        """
		Creates an instance of Explosion and appends it to the animations sprite list
		"""
        new_explosion = Explosion(self.explosion_texture_list, x, y)
        # Call update() because it sets which image we start on
        new_explosion.update()
        self.animations.append(new_explosion)

    def load_animantion_frames(self):
        """
		Creates an instance of all possible animations so that they are loaded before the game starts 
		"""
        # Initialize  an explosion outside of the screen to load the explosion animation frames
        self.create_explosion(-50, -50)

    def check_animations_loaded(self):
        """
		Sets the self.animationsLoaded variable to true if the animations list is empty
		"""
        if (len(self.animations) == 0):
            self.animationsLoaded = True

    def gameOver(self):
        """
		Renders the GemeOverView and sends the score to the server
		"""
        self.window.show_view(GameOverView(self.score))