import random
import pygame


class GameObject:
    def __init__(self, game, image: str):
        self.game = game
        self.image = pygame.image.load(image)
        image_rect = self.image.get_rect()

        self.x = 0
        self.y = 0
        self.w = image_rect.w
        self.h = image_rect.h

    def update(self):
        self.game.screen.blit(self.image, pygame.Rect(self.x, self.y, self.w, self.h))

    def check_collision(self, game_obj):
        return (
                self.x < game_obj.x + game_obj.w and
                self.x + self.w > game_obj.x and
                self.y < game_obj.y + game_obj.h and
                self.y + self.h > game_obj.y
        )


class Player(GameObject):
    def __init__(self, game):
        super().__init__(game, "kolesar.png")

        self.x = self.game.screen.get_width() / 2 - self.w / 2
        self.y = self.game.screen.get_height() - self.h

        self.lives = 3

    def update(self):
        if pygame.K_LEFT in self.game.keys:
            self.x -= 1
        if pygame.K_RIGHT in self.game.keys:
            self.x += 1

        for obstacle in self.game.obstacles:
            if not self.check_collision(obstacle):
                continue

            if obstacle.get_point:
                self.game.points += 1
                self.game.play_sound("jump.mp3")
            else:
                self.lives -= 1
                self.game.play_sound("explosion.mp3")
            obstacle.delete()

        if self.lives <= 0:
            self.game.loose()

        super().update()


class Obstacle(GameObject):
    def __init__(self, game):
        obstacles = {"bottle.png": False, "flowers.png": False, "grass.png": False, "scooter.png": False,
                     "stones.png": False, "walker.png": False, "mol.png": True}

        image = random.choice(list(obstacles))
        self.get_point = obstacles[image]

        super().__init__(game, image)

        self.x = (self.game.screen.get_width() - self.w) * random.random()
        self.y = -self.h

        self.game.obstacles.append(self)

    def update(self):
        if self.y > self.game.screen.get_height():
            self.delete()
            return

        self.y += 1 + self.game.get_level() / 10
        super().update()

    def delete(self):
        self.game.obstacles.remove(self)
        del self


class Game:
    def __init__(self):
        pygame.init()
        pygame.font.init()
        pygame.display.set_caption("Slalom v D-molu")

        self.screen = pygame.display.set_mode((800, 600))
        self.clock = pygame.time.Clock()
        self.font = pygame.font.SysFont("Consolas", 20)

        pygame.mixer.music.load("arcade.mp3")
        pygame.mixer.music.play(-1)
        pygame.mixer.music.set_volume(0.1)

        self.running = True
        self.lost = False
        self.keys = set()
        self.obstacles = []

        self.points = 0
        self.next_obstacle = 0

        self.player = Player(self)

        while self.running:
            self.update()

        pygame.quit()

    def get_level(self):
        return self.points // 5 + 1

    @staticmethod
    def play_sound(sound: str):
        channel = pygame.mixer.find_channel()
        channel.set_volume(0.1)
        channel.play(pygame.mixer.Sound(sound))

    def loose(self):
        self.lost = True
        pygame.mixer.music.stop()
        big_font = pygame.font.SysFont("Consolas", 40)
        you_lost = big_font.render("Izgubil si!", True, "white")
        self.screen.blit(
            you_lost,
            (self.screen.get_width() / 2 - you_lost.get_width() / 2,
             self.screen.get_height() / 2 - you_lost.get_height() / 2))

    def update(self):
        for event in pygame.event.get():
            match event.type:
                case pygame.QUIT:
                    self.running = False
                    break
                case pygame.KEYDOWN:
                    self.keys.add(event.key)
                    break
                case pygame.KEYUP:
                    self.keys.remove(event.key)
                    break

        if self.lost:
            return

        self.next_obstacle -= 1
        if self.next_obstacle <= 0:
            if self.get_level() >= 13:
                self.next_obstacle = 30
            else:
                self.next_obstacle = random.randrange(30, 160 - 10 * self.get_level())

            Obstacle(self)

        self.screen.fill("black")

        for obstacle in self.obstacles:
            obstacle.update()

        self.player.update()

        points = self.font.render(f'Točke: {self.points}', True, "white")
        self.screen.blit(points, (10, 10))

        level = self.font.render(f'Level: {self.get_level()}', True, "white")
        self.screen.blit(level, (self.screen.get_width() / 2 - level.get_width() / 2, 10))

        lives = self.font.render(f'Lives: {self.player.lives}', True, "white")
        self.screen.blit(lives, (self.screen.get_width() - lives.get_width() - 10, 10))

        pygame.display.flip()
        self.clock.tick(480)


Game()
