import pygame
import random

# Initialize Pygame
pygame.init()

# Constants for the game
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
FPS = 60

# Setup the display
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Advanced 2D Shooter Game")

# Fonts
font = pygame.font.SysFont(None, 36)
large_font = pygame.font.SysFont(None, 72)

# Game Variables
level = 1
player_health = 3
score = 0
high_score = 0

# Game classes
class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((50, 50))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.center = (SCREEN_WIDTH // 2, SCREEN_HEIGHT - 50)
        self.speed = 7
        self.health = 3
        self.bullets = pygame.sprite.Group()

    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] and self.rect.left > 0:
            self.rect.x -= self.speed
        if keys[pygame.K_RIGHT] and self.rect.right < SCREEN_WIDTH:
            self.rect.x += self.speed
        if keys[pygame.K_UP] and self.rect.top > 0:
            self.rect.y -= self.speed
        if keys[pygame.K_DOWN] and self.rect.bottom < SCREEN_HEIGHT:
            self.rect.y += self.speed

    def shoot(self):
        bullet = Bullet(self.rect.centerx, self.rect.top)
        self.bullets.add(bullet)
        all_sprites.add(bullet)

class Bullet(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((5, 20))
        self.image.fill(YELLOW)
        self.rect = self.image.get_rect()
        self.rect.center = (x, y)
        self.speed = 10

    def update(self):
        self.rect.y -= self.speed
        if self.rect.bottom < 0:
            self.kill()

class Enemy(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((50, 50))
        self.image.fill(RED)
        self.rect = self.image.get_rect()
        self.rect.x = random.randint(0, SCREEN_WIDTH - 50)
        self.rect.y = random.randint(-100, -40)
        self.speed = random.randint(2, 5)

    def update(self):
        self.rect.y += self.speed
        if self.rect.top > SCREEN_HEIGHT:
            self.rect.x = random.randint(0, SCREEN_WIDTH - 50)
            self.rect.y = random.randint(-100, -40)

    def hit(self):
        self.kill()

class PowerUp(pygame.sprite.Sprite):
    def __init__(self, type):
        super().__init__()
        self.image = pygame.Surface((30, 30))
        self.image.fill(BLUE if type == 'shield' else (0, 255, 255))
        self.rect = self.image.get_rect()
        self.rect.x = random.randint(0, SCREEN_WIDTH - 30)
        self.rect.y = random.randint(-100, -40)
        self.speed = 3
        self.type = type

    def update(self):
        self.rect.y += self.speed
        if self.rect.top > SCREEN_HEIGHT:
            self.kill()

# Draw HUD (Health, Score, Level, High Score)
def draw_hud(player):
    health_text = font.render(f"Health: {player.health}", True, WHITE)
    score_text = font.render(f"Score: {score}", True, WHITE)
    level_text = font.render(f"Level: {level}", True, WHITE)
    high_score_text = font.render(f"High Score: {high_score}", True, WHITE)

    screen.blit(health_text, (10, 10))
    screen.blit(score_text, (10, 50))
    screen.blit(level_text, (SCREEN_WIDTH - 200, 10))
    screen.blit(high_score_text, (SCREEN_WIDTH - 200, 50))

    pygame.display.flip()

# Main Menu
def main_menu():
    screen.fill(BLACK)
    title_text = large_font.render("2D Shooter Game", True, WHITE)
    start_text = font.render("Press Enter to Start", True, WHITE)
    quit_text = font.render("Press Escape to Quit", True, WHITE)
    
    screen.blit(title_text, (SCREEN_WIDTH // 2 - title_text.get_width() // 2, SCREEN_HEIGHT // 4))
    screen.blit(start_text, (SCREEN_WIDTH // 2 - start_text.get_width() // 2, SCREEN_HEIGHT // 2))
    screen.blit(quit_text, (SCREEN_WIDTH // 2 - quit_text.get_width() // 2, SCREEN_HEIGHT // 2 + 40))

    pygame.display.flip()

    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    return True
                if event.key == pygame.K_ESCAPE:
                    running = False
                    pygame.quit()
                    quit()
    return False

# Game Over
def game_over():
    global high_score
    screen.fill(BLACK)
    game_over_text = large_font.render("Game Over", True, RED)
    quit_text = font.render("Press Escape to Quit", True, WHITE)
    
    # Check and update high score
    if score > high_score:
        high_score = score

    high_score_text = font.render(f"High Score: {high_score}", True, WHITE)
    
    screen.blit(game_over_text, (SCREEN_WIDTH // 2 - game_over_text.get_width() // 2, SCREEN_HEIGHT // 4))
    screen.blit(high_score_text, (SCREEN_WIDTH // 2 - high_score_text.get_width() // 2, SCREEN_HEIGHT // 2))
    screen.blit(quit_text, (SCREEN_WIDTH // 2 - quit_text.get_width() // 2, SCREEN_HEIGHT // 2 + 40))

    pygame.display.flip()

    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    running = False
                    pygame.quit()
                    quit()

# Main Game Loop
def game_loop():
    global level, score, player_health
    player = Player()
    all_sprites = pygame.sprite.Group()
    all_sprites.add(player)
    enemies = pygame.sprite.Group()
    powerups = pygame.sprite.Group()

    # Spawn initial enemies
    for _ in range(5):
        enemy = Enemy()
        all_sprites.add(enemy)
        enemies.add(enemy)

    # Spawn initial power-ups
    for _ in range(2):
        powerup = PowerUp('health')
        all_sprites.add(powerup)
        powerups.add(powerup)

    clock = pygame.time.Clock()

    running = True
    while running:
        clock.tick(FPS)

        # Event handling
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    player.shoot()

        # Update game elements
        all_sprites.update()

        # Check for collisions between bullets and enemies
        collisions = pygame.sprite.groupcollide(player.bullets, enemies, True, True)
        if collisions:
            score += 10
            # Spawn a new enemy
            enemy = Enemy()
            all_sprites.add(enemy)
            enemies.add(enemy)

        # Check for player collisions with enemies
        if pygame.sprite.spritecollide(player, enemies, False):
            player.health -= 1
            if player.health <= 0:
                running = False  # Game over when player runs out of health

        # Power-up collision detection
        if pygame.sprite.spritecollide(player, powerups, True):
            player.health += 1  # Power-up to increase health

        # Spawn new enemies and power-ups based on random chance
        if random.random() < 0.02:
            powerup = PowerUp(random.choice(['health', 'shield']))
            all_sprites.add(powerup)
            powerups.add(powerup)

        # Drawing
        screen.fill(BLACK)
        draw_hud(player)
        all_sprites.draw(screen)

        pygame.display.flip()

        # Level up logic
        if score >= 100 * level:
            level += 1
            for _ in range(level):  # Increase enemies per level
                enemy = Enemy()
                all_sprites.add(enemy)
                enemies.add(enemy)

    game_over()

# Start of the game
def start_game():
    global level, score, player_health
    level = 1
    score = 0
    player_health = 3

    while True:
        if main_menu():
            game_loop()

if __name__ == "__main__":
    start_game()