import pygame
import random
import time
import RPi.GPIO as GPIO

# Initialize pygame
pygame.init()

# Set up GPIO
GPIO.setmode(GPIO.BCM)  # Use Broadcom pin numbering
BUTTON_PIN = 17  # The GPIO pin to which the pushbutton is connected
LED_PIN = 27  # The GPIO pin to which the LED is connected
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # Set the pin as input with pull-up
GPIO.setup(LED_PIN, GPIO.OUT)  # Set the pin as output for the LED

# Screen dimensions
WIDTH = 400
HEIGHT = 600
FPS = 60

# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
BLUE = (135, 206, 235)

# Bird parameters
BIRD_WIDTH = 60
BIRD_HEIGHT = 60
GRAVITY = 0.5
FLAP_STRENGTH = -8

# Pipe parameters
PIPE_WIDTH = 80
PIPE_HEIGHT = 500
PIPE_GAP = 250
PIPE_SPEED = 5

# Set up the game window
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Flappy Bird")
GPIO.output(LED_PIN, GPIO.LOW)  # Turn off the LED
# Fonts
font = pygame.font.SysFont('Arial', 32)
game_over_font = pygame.font.SysFont('Arial', 50)

# File to store high score
HIGH_SCORE_FILE = "high_score.txt"

def get_high_score():
    try:
        with open(HIGH_SCORE_FILE, "r") as f:
            return int(f.read().strip())
    except (FileNotFoundError, ValueError):
        return 0

def save_high_score(score):
    high_score = get_high_score()
    if score > high_score:
        with open(HIGH_SCORE_FILE, "w") as f:
            f.write(str(score))

# Bird class
class Bird:
    def __init__(self):
        self.x = 100
        self.y = HEIGHT // 2
        self.velocity = 0
    
    def update(self):
        self.velocity += GRAVITY
        self.y += self.velocity
        if self.y > HEIGHT - BIRD_HEIGHT:  # Bird hits the bottom
            return False  # Game over
        elif self.y < 0:  # Bird hits the top
            return False  # Game over
        return True  # Bird is still alive
    
    def flap(self):
        self.velocity = FLAP_STRENGTH
    
    def draw(self, screen):
        pygame.draw.rect(screen, (255, 255, 0), (self.x, self.y, BIRD_WIDTH, BIRD_HEIGHT))

# Pipe class
class Pipe:
    def __init__(self):
        self.x = WIDTH
        self.height = random.randint(100, HEIGHT - PIPE_GAP - 100)
        self.top_rect = pygame.Rect(self.x, 0, PIPE_WIDTH, self.height)
        self.bottom_rect = pygame.Rect(self.x, self.height + PIPE_GAP, PIPE_WIDTH, HEIGHT - (self.height + PIPE_GAP))
    
    def update(self):
        self.x -= PIPE_SPEED
        self.top_rect.x = self.x
        self.bottom_rect.x = self.x
    
    def draw(self, screen):
        pygame.draw.rect(screen, GREEN, self.top_rect)
        pygame.draw.rect(screen, GREEN, self.bottom_rect)

# Display "Press to Play" screen
def display_start_screen():
    screen.fill(BLUE)
    start_text = font.render("Press Button to Start", True, BLACK)
    screen.blit(start_text, (WIDTH // 2 - start_text.get_width() // 2, HEIGHT // 2))
    pygame.display.flip()
    
    while True:
        if GPIO.input(BUTTON_PIN) == GPIO.HIGH:
            break
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                GPIO.cleanup()
                exit()

# Main game loop
def main():
    while True:
        display_start_screen()

        clock = pygame.time.Clock()
        bird = Bird()
        pipes = [Pipe()]
        score = 0
        running = True

        while running:

            clock.tick(FPS)
            screen.fill(BLUE)

            # Handle events
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    GPIO.cleanup()
                    exit()

            # Check if the button is pressed
            if GPIO.input(BUTTON_PIN) == GPIO.HIGH:  # Button is pressed when GPIO reads HIGH
                bird.flap()

            # Update bird and pipes
            if not bird.update():
                running = False

            for pipe in pipes:
                pipe.update()
                if pipe.x + PIPE_WIDTH < 0:
                    pipes.remove(pipe)
                if pipe.x + PIPE_WIDTH < bird.x and not hasattr(pipe, 'passed'):
                    pipe.passed = True
                    score += 1

            if pipes[-1].x < WIDTH - 300:
                pipes.append(Pipe())

            # Draw the bird and pipes
            bird.draw(screen)
            for pipe in pipes:
                pipe.draw(screen)

            # Display score
            score_text = font.render(f"Score: {score}", True, BLACK)
            screen.blit(score_text, (10, 10))

            # Check for collisions
            for pipe in pipes:
                if bird.x + BIRD_WIDTH > pipe.top_rect.x and bird.x < pipe.top_rect.x + PIPE_WIDTH:
                    if bird.y < pipe.height or bird.y + BIRD_HEIGHT > pipe.height + PIPE_GAP:
                        running = False

            # Update the display
            pygame.display.flip()

        # When the game ends, activate the LED and display 'Game Over' screen
        GPIO.output(LED_PIN, GPIO.HIGH)  # Turn on the LED
        save_high_score(score)
        high_score = get_high_score()
        game_over_text = game_over_font.render("Game Over", True, BLACK)
        final_score_text = font.render(f"Final Score: {score}", True, BLACK)
        high_score_text = font.render(f"High Score: {high_score}", True, BLACK)
        retry_text = font.render("Press Button to Retry", True, BLACK)
        screen.fill(BLUE)
        screen.blit(game_over_text, (WIDTH // 2 - game_over_text.get_width() // 2, HEIGHT // 2 - 50))
        screen.blit(final_score_text, (WIDTH // 2 - final_score_text.get_width() // 2, HEIGHT // 2))
        screen.blit(high_score_text, (WIDTH // 2 - high_score_text.get_width() // 2, HEIGHT // 2 + 50))
        screen.blit(retry_text, (WIDTH // 2 - retry_text.get_width() // 2, HEIGHT // 2 + 100))
        pygame.display.flip()

        # Wait for the user to press the button to retry
        while True:
            if GPIO.input(BUTTON_PIN) == GPIO.HIGH:
                break
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    GPIO.cleanup()
                    exit()

        GPIO.output(LED_PIN, GPIO.LOW)  # Turn off the LED

if __name__ == "__main__":
    try:
        main()
    finally:
        GPIO.cleanup()
