import pygame
from pygame.locals import *
from pygame import mixer
import pickle
from os import path
import datetime

pygame.mixer.pre_init(44100, -16, 2, 512)
mixer.init()
pygame.init()
# Set up the game clock to manage the game's frame rate
clock = pygame.time.Clock()
fps = 60

# Define the dimensions of the game window
screen_width = 1000
screen_height = 1000

# Create the game window
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Platformer')

# define font
font = pygame.font.SysFont('Bauhaus 93', 70)
font_score = pygame.font.SysFont('Bauhaus 93', 30)

# define game variables
tile_size = 50
game_over = 0
main_menu = True
level = 5
max_levels = 5
score = 0
lives = 3

# define colours
white = (255, 255, 255)
blue = (0, 0, 255)
red = (255, 0, 0)

# load images
bg_img = pygame.image.load('img/background.png')
restart_img = pygame.image.load('img/restart_btn.png')
start_img = pygame.image.load('img/start_btn.png')
exit_img = pygame.image.load('img/exit_btn.png')

# load sounds
pygame.mixer.music.load('music/music.wav')
pygame.mixer.music.play(-1, 0.0, 5000)
coin_fx = pygame.mixer.Sound('music/coin.wav')
coin_fx.set_volume(0.5)
jump_fx = pygame.mixer.Sound('music/jump.wav')
jump_fx.set_volume(0.5)
game_over_fx = pygame.mixer.Sound('music/game_over.wav')
game_over_fx.set_volume(0.5)

# Function to draw text on the screen
def draw_text(text, font, text_col, x, y):
    img = font.render(text, True, text_col)
    screen.blit(img, (x, y))

# function to reset level
def reset_level(level):
    player.reset(100, screen_height - 130) #reset player postion
    #empty all groups:
    blob_group.empty()
    platform_group.empty()
    lava_group.empty()
    exit_group.empty()
    coin_group.empty()
    #add score coin to coin group to make it on every level:
    coin_group.add(score_coin)
    
    # load in level data and create world
    if path.exists(f'level{level}_data'):
        pickle_in = open(f'level{level}_data', 'rb')
        world_data = pickle.load(pickle_in)
    world = World(world_data)
    return world

# Button class for creating interactive buttons
class Button():
    def __init__(self, x, y, image):
        self.image = image
        self.rect = self.image.get_rect()
        self.rect.x = x #set x postion of button
        self.rect.y = y #set y postion of button
        self.clicked = False # Flag to check if the button has been clicked
    
    def draw(self):
        action = False
        # get mouse position
        pos = pygame.mouse.get_pos()

        # check mouseover and clicked conditions
        if self.rect.collidepoint(pos):
            if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
                action = True
                self.clicked = True

        if pygame.mouse.get_pressed()[0] == 0:
            self.clicked = False

        # draw button
        screen.blit(self.image, self.rect)
        return action

class Player():
    def __init__(self, x, y):
        self.reset(x, y)

    def update(self, game_over, lives):
        dx = 0
        dy = 0
        walk_cooldown = 5
        idle_cooldown = 10 # Cooldown for idle animation
        fall_cooldown = 10
        jump_cooldown = 10
        landing_cooldown = 10
        col_thresh = 20
        attack_cooldown = 5

        if game_over == 0:
            # get key presses
            key = pygame.key.get_pressed()
            mouse = pygame.mouse.get_pressed()

            if mouse[0] and not self.attacking and not self.in_air:
                self.attacking = True
                self.attack_counter = 0

            # If the player is attacking, handle attack animation
            if self.attacking:
                self.counter += 1 # Increment the animation counter
                if self.counter >= attack_cooldown:
                    self.counter = 0
                    self.attack_counter += 1 # Move to the next attack frame
                    if self.attack_counter >= len(self.attack_frames):
                        self.attacking = False # End the attack if all frames have been shown
                        self.attack_counter = 0 # Reset the attack counter
                    else:
                        # Display the current attack frame
                        self.image = pygame.transform.flip(self.attack_frames[self.attack_counter], self.direction, False)
            else:
                 # Handle jumping
                if key[pygame.K_SPACE] and self.jumped == False and self.in_air == False:
                    jump_fx.play()
                    self.vel_y = -15
                    self.jumped = True
                if key[pygame.K_SPACE] == False:
                    self.jumped = False # Reset jumped flag when space key is released
                # Handle left movement
                if key[pygame.K_LEFT]:
                    dx -= 5
                    self.direction = True
                # Handle right movement
                if key[pygame.K_RIGHT]:
                    dx += 5
                    self.direction = False

            self.counter += 1
            
            # Handle in-air animations
            if self.in_air:
                if self.vel_y < 0:  # Player is moving upwards
                    if self.index >= len(self.jump_frames):
                        self.index = len(self.jump_frames) - 1  # Hold the last jump frame
                    self.image = pygame.transform.flip(self.jump_frames[self.index], self.direction, False) # Display jump frame
                if self.counter > jump_cooldown:
                    if self.counter > jump_cooldown:
                        self.counter = 0 #reset counter
                        self.index += 1 #move to next jump frame

                else:
                    if  self.index >= len(self.falling_frames):
                        self.index = len(self.falling_frames) - 1  # Hold the last falling frame
                    self.image = pygame.transform.flip(self.falling_frames[self.index], self.direction, False)
                    if self.counter > fall_cooldown:
                        self.counter = 0
                        self.index += 1
            # Handle landing animations
            else:
                if self.landing:
                    if self.index >= len(self.landing_frames):
                        self.index = len(self.landing_frames) - 1 # Hold the last landing frame
                    self.image = pygame.transform.flip(self.landing_frames[self.index], self.direction, False)  # Flip based on direction
                    if self.counter > landing_cooldown:
                        self.counter = 0 #reset counter
                        self.index += 1 #move to next landing frame
                        if self.index >= len(self.landing_frames):
                            self.landing = False # End landing animation if all frames have been shown
                            self.index = 0 #reset frame index
                # Handle idle animations
                else:
                    if not key[pygame.K_LEFT] and not key[pygame.K_RIGHT]:
                        if self.counter > idle_cooldown:
                            self.counter = 0 #reset counter 
                            self.index += 1 #move to next idle frame
                            if self.index >= len(self.idle_right):  # Both idle_right and idle_left should have the same length
                                self.index = 0 # Reset idle frame index
                            if self.direction == False:
                                self.image = self.idle_right[self.index] # Display idle frame facing right
                            if self.direction == True:
                                self.image = self.idle_left[self.index] # Display idle frame facing left
                    # Handle walking animations
                    else:
                        if self.counter > walk_cooldown:
                            self.counter = 0 #reset counter 
                            self.index += 1 #move to next walking frame
                            if self.index >= len(self.images_right):  # Both images_right and images_left should have the same length
                                self.index = 0
                        if self.direction == False:
                            self.image = self.images_right[self.index] # Display walk frame facing right
                        if self.direction == True:
                            self.image = self.images_left[self.index] # Display walk frame facing left

            # add gravity
            self.vel_y += 1 # Increase vertical velocity to simulate gravity
            if self.vel_y > 10:
                self.vel_y = 10 # Cap the vertical velocity to prevent falling too fast
            dy += self.vel_y # Apply vertical velocity to the change in y position (dy)

            # check player collision
            old_air = self.in_air
            self.in_air = True # Assume the player is in the air
            
            # Check collision with tiles
            for tile in world.tile_list:
                # Check for collision in the x direction
                if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
                    dx = 0 # Stop horizontal movement on collision
                # Check for collision in the y direction
                if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
                    if self.vel_y < 0: # Collision while moving upwards
                        dy = tile[1].bottom - self.rect.top # Adjust dy to stop at the top of the tile
                        self.vel_y = 0 # Reset vertical velocity
                    # Collision while moving downwards:
                    elif self.vel_y >= 0:
                        dy = tile[1].top - self.rect.bottom # Adjust dy to stop at the bottom of the tile
                        self.vel_y = 0 # Reset vertical velocity
                        self.in_air = False  # Player is no longer in the air

            # check for collision with enemies
            if pygame.sprite.spritecollide(self, blob_group, False): #if player collides with blob:
                lives -= 1
                
                for blob in pygame.sprite.spritecollide(self, blob_group, False):
                    if self.direction and self.rect.x > blob.rect.x: # if you are facing a blob on the right side and attacking, remove enemy and add 1 score while giving your life back
                        if self.attacking: 
                            blob_group.remove(blob)
                            lives += 1 
                            score +1
                    if (not self.direction) and self.rect.x < blob.rect.x: # if you are left the blob for thr right side and attacking, remove enemy and add 1 score while giving your life back
                        if self.attacking:
                            blob_group.remove(blob)
                            lives += 1  
                            score +1
                    
                    #when hit by blob get knocked back
                    else:
                        if self.rect.x < blob.rect.x:
                            dx = -25  # Push player left
                        else:
                            dx = 25  # Push player right
                        if self.rect.y < blob.rect.y:
                            dy = -10  # Push player up slightly
                        else:
                            dy = 10  # Push player down slightly


                if lives == 0: # Check if lives are depleted
                    #calculate time sinse timer started and formatt to mm:ss
                    minutes, seconds = divmod((datetime.datetime.now() - timer).seconds, 60)
                    self.finshed_time = '{:02}:{:02}'.format(int(minutes), int(seconds))
                    game_over = -1
                game_over_fx.play()
            # check for collision with lava
            if pygame.sprite.spritecollide(self, lava_group, False): #if player collide with lava
                game_over = -1
                lives = 0
                #calculate time sinse timer started and formatt to mm:ss
                minutes, seconds = divmod((datetime.datetime.now() - timer).seconds, 60)
                self.finshed_time = '{:02}:{:02}'.format(int(minutes), int(seconds))

                print(game_over)
                game_over_fx.play()
            # check for collision with exit
            if pygame.sprite.spritecollide(self, exit_group, False):
                game_over = 1
                print(game_over)

            # check for collision with platforms
            for platform in platform_group:
                # collision in the x direction
                if platform.rect.colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
                    dx = 0 # Stop horizontal movement on collision
                # check collision in the y direction
                if platform.rect.colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
                    # check if below platform
                    if abs((self.rect.top + dy) - platform.rect.bottom) < col_thresh:
                        self.vel_y = 0 # Reset vertical velocity
                        dy = platform.rect.bottom - self.rect.top # Adjust dy to stop at the bottom of the platform
                    # check if above platform
                    elif abs((self.rect.bottom + dy) - platform.rect.top) < col_thresh:
                        self.rect.bottom = platform.rect.top - 1 # Adjust position to stand on top of the platform
                        self.in_air = False # Player is no longer in the air
                        dy = 0
                    # move sideways with the platform
                    if platform.move_x != 0:
                            self.rect.x += platform.move_direction #player x is same as platform x

            if old_air and not self.in_air:
                self.landing = True # Trigger landing animation
                self.index = 0
                self.counter = 0

            #update player coordinates
            self.rect.x += dx
            self.rect.y += dy

        elif game_over == -1:
            self.image = self.dead_image
            pygame.draw.rect(screen, (255,255,255),pygame.Rect((screen_width // 2) - 210, (screen_height // 2) -50, 400, 200) )  
            draw_text('GAME OVER!', font, red, (screen_width // 2) - 200, screen_height // 2 - 50)
            draw_text('final time: ' + self.finshed_time, font_score, red,  (screen_width // 2) - 200, screen_height // 2 +10)
            draw_text('Your Coins: ' + str(score), font_score, red,  (screen_width // 2) - 200, screen_height // 2 + 40)      
    
            if self.rect.y > 200:
                self.rect.y -= 5 # Move player up after game over

        #draw player onto screen
        screen.blit(self.image, self.rect)

        return game_over, lives # Return game over state and lives

    def reset(self, x, y):
        self.images_right = []  #right movement frames
        self.images_left = [] #left movement frames
        self.idle_right = [] # Right idle animation frames
        self.idle_left = [] # Left idle animation frames
        self.falling_frames = [] # Falling animation frames
        self.jump_frames = [] # Jumping animation frames
        self.landing_frames = [] # Landing animation frames
        self.attack_frames = [] # attacking frames
        self.index = 0 # Animation frame index
        self.counter = 0 # Animation counter
        
 
        # Load run images
        for num in range(1, 9):
            img_right = pygame.image.load(f'img/run{num}.png') # Load right movement image
            img_right = pygame.transform.scale(img_right, (45, 70))
            img_left = pygame.transform.flip(img_right, True, False) # Flip image for left movement
            self.images_right.append(img_right)
            self.images_left.append(img_left)

        # Load falling images
        for num in range(1, 7):  # Assuming there are 6 falling frames
            img_falling_right = pygame.image.load(f'img/fall ({num}).png') # Load falling image
            img_falling_right = pygame.transform.scale(img_falling_right, (45, 70))
            self.falling_frames.append(img_falling_right)

        # Load jumping images
        for num in range(1, 9):  # Assuming there are 8 jump frames
            img_jump_right = pygame.image.load(f'img/jump{num}.png') # Load jump image
            img_jump_right = pygame.transform.scale(img_jump_right, (45, 70))
            self.jump_frames.append(img_jump_right)

        # Load landing images
        for num in range(7, 9):  # Assuming you have 2 landing frames
            img_landing_right = pygame.image.load(f'img/fall ({num}).png') # Load landing image
            img_landing_right = pygame.transform.scale(img_landing_right, (45, 70))
            self.landing_frames.append(img_landing_right)

        # Load idle images
        for num in range(1, 7):  # Assuming there are 6 idle frames
            img_idle_right = pygame.image.load(f'img/idle{num}.png')  # Load idle image
            img_idle_right = pygame.transform.scale(img_idle_right, (45, 70))
            img_idle_left = pygame.transform.flip(img_idle_right, True, False) # Flip image for left idle
            self.idle_right.append(img_idle_right)
            self.idle_left.append(img_idle_left)
        
        #load attack frames
        for num in range(1, 7):  # Assuming there are 6 idle frames
            img_attack_right = pygame.image.load(f'img/attack{num}.png') # Load attack image
            img_attack_right = pygame.transform.scale(img_attack_right, (45, 70))
            self.attack_frames.append(img_attack_right)

        self.dead_image = pygame.image.load('img/ghost.png')
        self.image = self.idle_right[self.index] # Set initial image to the first idle right frame
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.width = self.image.get_width()
        self.height = self.image.get_height()
        self.vel_y = 0
        self.jumped = False
        self.direction = False   #false = right, true = left
        self.in_air = True
        self.landing = False
        self.attacking = False
        self.attack_counter = 0


class World():
    def __init__(self, data):
        self.tile_list = []

        # Load images for different types of tiles
        dirt_img = pygame.image.load('img/tile6.png')
        grass_img = pygame.image.load('img/tile5.png')
        left_wall_img = pygame.image.load('img/tile10.png')
        right_wall_img = pygame.image.load('img/tile11.png')
        full_plat_img = pygame.image.load('img/tile1.png')
        left_top_img = pygame.image.load('img/tile16.png')
        right_top_img = pygame.image.load('img/tile17.png')
        top_3_img = pygame.image.load('img/tile2.png')
        left_3_img = pygame.image.load('img/tile3.png')
        right_3_img = pygame.image.load('img/tile4.png')
        left_corner_img = pygame.image.load('img/tile12.png')
        right_corner_img = pygame.image.load('img/tile13.png')
        double_ho_img = pygame.image.load('img/tile7.png')
        roof_silver_img = pygame.image.load('img/tile9.png')
        dirt_2_img = pygame.image.load('img/tile14.png')

        # Process each tile in the provided data grid
        row_count = 0
        for row in data:
            col_count = 0
            for tile in row:
                if tile == 1: # Dirt tile
                    img = pygame.transform.scale(dirt_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 2: # Grass tile
                    img = pygame.transform.scale(grass_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 3: # Enemy blob
                    blob = Enemy(col_count * tile_size, row_count * tile_size + 15)
                    blob_group.add(blob)
                if tile == 4: #creating new platform
                    platform = Platform(col_count * tile_size, row_count * tile_size, 1, 0)
                    platform_group.add(platform)
                if tile == 5:
                    platform = Platform(col_count * tile_size, row_count * tile_size, 0, 1)
                    platform_group.add(platform)
                if tile == 6: # Lava
                    lava = Lava(col_count * tile_size, row_count * tile_size +(tile_size // 2) )
                    lava_group.add(lava)
                if tile == 7: # Coin
                    coin = Coin(col_count * tile_size + (tile_size // 2), row_count * tile_size +(tile_size // 2) )
                    coin_group.add(coin)                    
                if tile == 8: # Exit
                    exit = Exit(col_count * tile_size, row_count * tile_size - (tile_size // 2))
                    exit_group.add(exit)
                if tile == 9: # Left wall tile
                    img = pygame.transform.scale(left_wall_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 10: # Right wall tile
                    img = pygame.transform.scale(right_wall_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 11: # Full platform tile
                    img = pygame.transform.scale(full_plat_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 12: # Left top corner tile
                    img = pygame.transform.scale(left_top_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 13: # Right top corner tile
                    img = pygame.transform.scale(right_top_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 14: # Top 3-tile block
                    img = pygame.transform.scale(top_3_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 15: # Left 3-tile block
                    img = pygame.transform.scale(left_3_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 16: # Right 3-tile block
                    img = pygame.transform.scale(right_3_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 17: # Left corner tile
                    img = pygame.transform.scale(left_corner_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 18: # Right corner tile
                    img = pygame.transform.scale(right_corner_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 19: # Double horizontal tile
                    img = pygame.transform.scale(double_ho_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 20: # Roof silver tile
                    img = pygame.transform.scale(roof_silver_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 21: # Alternate dirt tile
                    img = pygame.transform.scale(dirt_2_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)

                col_count += 1
            row_count += 1

    def draw(self):
        # Draw all tiles in the tile list onto the screen
        for tile in self.tile_list:
            screen.blit(tile[0], tile[1])



class Enemy(pygame.sprite.Sprite):
    def __init__(self, x, y):
        self.index = 0
        self.move_direction = 1 # Initial movement direction
        self.direction = False  # Initialize direction for right movement (False for right, True for left)
        self.move_counter = 0
        self.counter = 0

        self.images_right = [] # List to store right blob animation frames
        self.images_left = [] # List to store left blob animation frames
        
        pygame.sprite.Sprite.__init__(self)
        
        # Load multiple images for enemy animation
        for num in range(1, 9):  # Assuming you have 8 blob frames
            img = pygame.image.load(f'img/blob{num}.png')
            self.image = pygame.transform.scale(img, (46, 35))
            img_left = pygame.transform.flip(self.image, True, False) # Flip image for left movement
            self.images_right.append(self.image)
            self.images_left.append(img_left)
        self.image = self.images_right[0]  # Initialize with the first frame of the right images
        self.rect = self.image.get_rect()
        self.rect.topleft = (x, y)  # Place the top-left corner of the image at the specified coordinates

        try: #if we aren't the first Enemy
            #set our direction to be the opposite of the last Enemy
            self.move_direction = Enemy.direction_g * -1
            #flip it for the next Enemy
            Enemy.direction_g = Enemy.direction_g * -1
        except: #if we are the first Enemy
            #set class direction_g and set our direction to be the same
            Enemy.direction_g = 1
            self.move_direction = Enemy.direction_g 

    def update(self):
        # Move enemy horizontally
        self.move_counter += 1
        move_cooldown = 5

        if (self.move_counter % 2) == 0 or (self.move_counter % 3) == 0:
            self.rect.x += self.move_direction
            
            # Reverse direction after certain distance
            if abs(self.move_counter) > 75:
                self.move_direction *= -1
                self.move_counter *= -1
        
        if self.counter > move_cooldown:
            self.counter = 0 #reset counter 
            self.index += 1 #move to next moving frame
            if self.index >= len(self.images_right):  # Both images_right and images_left should have the same length
                self.index = 0
        # Set the correct image based on the direction
        if self.move_direction > 0:
            self.image = self.images_right[self.index]  # Display walk frame facing right
        else:
            self.image = self.images_left[self.index]  # Display walk frame facing left

        self.counter += 1  # Increment counter for animation timing



class Platform(pygame.sprite.Sprite): 
    def __init__(self, x, y, move_x, move_y):
        pygame.sprite.Sprite.__init__(self)
        img = pygame.image.load('img/platform2.png')
        self.image = pygame.transform.scale(img, (tile_size, tile_size // 2))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.move_counter = 0
        
        self.move_x = move_x
        self.move_y = move_y    

        try: #if we aren't the first platform
            #set our direction to be the opposite of the last platforms
            self.move_direction = Platform.direction_g * -1
            #flip it for the next platform
            Platform.direction_g = Platform.direction_g * -1
        except: #if we are the first platform
            #set class direction_g and set our direction to be the same
            Platform.direction_g = 1
            self.move_direction = Platform.direction_g 


    def update(self):
        # Move platform horizontally or vertically
        self.rect.x += self.move_direction * self.move_x
        self.rect.y += self.move_direction * self.move_y
        self.move_counter += 1

        # Reverse direction after certain distance
        if abs(self.move_counter) > 50:
            self.move_direction *= -1
            self.move_counter *= -1


class Lava(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        img = pygame.image.load('img/lava.png')
        self.image = pygame.transform.scale(img, (tile_size, tile_size // 2))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

class Coin(pygame.sprite.Sprite):
    def __init__(self, x, y):
        self.index = 0
        self.images = [] # List to store coin animation frames
        self.counter = 0
        pygame.sprite.Sprite.__init__(self)
        
        # Load multiple images for coin animation
        for num in range(1, 10):  # Assuming you have 9 coin frames
            img = pygame.image.load(f'img/Coin ({num}).png')
            self.image = pygame.transform.scale(img, (tile_size // 2, tile_size // 2))
            self.images.append(self.image)
        self.rect = self.image.get_rect()
        self.rect.center = (x, y)
    
    def update(self):
        # Animate the coin by cycling through images
        self.counter += 1 
        if self.counter == 6:
            self.index += 1
            if self.index == len(self.images):
                self.index = 0
            self.image = self.images[self.index]
            self.counter = 0
        
        


class Exit(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        img = pygame.image.load('img/exit.png')
        self.image = pygame.transform.scale(img, (tile_size, int(tile_size * 1.5)))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

# Initialize the player at a specific position
player = Player(100, screen_height - 130)

# Create groups for different types of sprites
blob_group = pygame.sprite.Group()
platform_group = pygame.sprite.Group()
lava_group = pygame.sprite.Group()
coin_group = pygame.sprite.Group()
exit_group = pygame.sprite.Group()

#create dummy coin for showing score
score_coin = Coin(tile_size // 2, tile_size // 2)
coin_group.add(score_coin)

#load in level data and create world
if path.exists(f'level{level}_data'):
    pickle_in = open(f'level{level}_data', 'rb')
    world_data = pickle.load(pickle_in)
world = World(world_data)

# Create buttons for restarting, starting, and exiting the game
restart_button = Button(screen_width // 2 - 50, screen_height //2 + 100, restart_img)
start_button = Button(screen_width // 2 - 350, screen_height // 2, start_img)
exit_button = Button(screen_width // 2 + 150, screen_height // 2, exit_img)

# Timer variable to track the game duration
timer = datetime.datetime.now()
finshed_time = False
run = True

#game loop
while run:

     # Control the game frame rate
    clock.tick(fps)

    # Draw the background image
    screen.blit(bg_img, (0, 0))




    if main_menu == True:
        # If in the main menu, draw buttons and check for button clicks
        if exit_button.draw():
            run = False
        if start_button.draw():
            main_menu = False
            timer = datetime.datetime.now()

    else:
        # Draw the game world
        world.draw()
        if game_over == 0:
            # Update groups and check for collisions
            blob_group.update()
            platform_group.update()
            coin_group.update()
            #update score
            #check if coin has been collected and update score
            if pygame.sprite.spritecollide(player, coin_group, True):
                score += 1
                coin_fx.play()

            # Draw the score, lives, and timer on the screen
            draw_text('X ' + str(score), font_score, white, tile_size - 10, 10)
            draw_text('Lives: ' + str(lives), font_score, white, tile_size +100, 10)
            current_timer = datetime.datetime.now() - timer
            minutes, seconds = divmod(current_timer.seconds, 60)
            draw_text('timer: ' + '{:02}:{:02}'.format(int(minutes), int(seconds)), font_score, white, tile_size +250, 10)
        
        # Draw groups on the screen
        blob_group.draw(screen)
        platform_group.draw(screen)
        lava_group.draw(screen)
        coin_group.draw(screen)
        exit_group.draw(screen)
        
        # Update the player's status and check for game over
        game_over, lives = player.update(game_over, lives)

        #if player has died
        if game_over == -1:
            #if player died show reset button
            if restart_button.draw():
                # Reset game state
                level = 1
                world_data = []
                world = reset_level(level)                
                game_over = 0
                score = 0
                lives = 3
                timer = datetime.datetime.now()
                coin_group.add(score_coin)

        #if player has completed level
        if game_over == 1:
            #reset game and go to next level
            level += 1
            if level <= max_levels: #if level is smaller than max level, move net level             #reset level
                world_data = []
                world = reset_level(level)
                game_over = 0
                lives = lives
            else: # if final level is complete
                # Display the win screen with final stats
                if not finshed_time:
                    minutes, seconds = divmod((datetime.datetime.now() - timer).seconds, 60)
                    finshed_time = '{:02}:{:02}'.format(int(minutes), int(seconds))
                
                #draw game complete text and rectangle
                pygame.draw.rect(screen, (255,255,255),pygame.Rect((screen_width // 2) -190 , (screen_height // 2) -50, 400, 200) )  
                draw_text('YOU WIN!', font, blue, (screen_width // 2) - 140, screen_height // 2 - 50)
                draw_text('final time: ' + finshed_time, font_score, red,  (screen_width // 2) - 140, screen_height // 2 +10)
                draw_text('Your Coins: ' + str(score), font_score, red,  (screen_width // 2) - 140, screen_height // 2 + 40)
                draw_text('Lives remaining: ' + str(lives), font_score, red, (screen_width // 2) - 140, screen_height // 2 + 60)
                
                #restart game from win screen
                if restart_button.draw():
                    level = 1
                    #reset level
                    world_data = []
                    world = reset_level(level)
                    game_over = 0
                    score = 0
                    lives = 3

    # Handle events such as quitting the game
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    pygame.display.update()

pygame.quit()