import pygame
import random
import os  # For file handling

pygame.init()

# Window settings
width = 700
height = 600
fullscreen = False  # Fullscreen flag

# Create the actual window surface (window size changes with fullscreen toggle)
win = pygame.display.set_mode((width, height))
pygame.display.set_caption("Car Game")  # Updated title

# Create an internal fixed-size surface to draw the game on
game_surface = pygame.Surface((width, height))

# Colors
ASPHALT = (50, 50, 50)
WHITE = (255, 255, 255)
YELLOW = (255, 255, 0)
ROAD_EDGE = (180, 180, 180)
BLACK = (0, 0, 0)
BLUE = (0, 0, 255)
RED = (255, 0, 0)

# Road and lanes
road_left = 100
road_right = 600
lane_count = 5
lane_width = (road_right - road_left) // lane_count
lanes = [road_left + i * lane_width + lane_width // 2 for i in range(lane_count)]  # center x of each lane

# Car settings (hitbox dimensions)
car_width = 70  # Player car hitbox width
car_height = 140  # Player car hitbox height
car_lane = 2  # Start in the middle lane
car_x = lanes[car_lane] - car_width // 2  # Current x position
car_target_x = car_x  # Target x position for smooth movement
car_y = height - car_height - 10
car_speed = 10  # Speed of smooth movement (pixels per frame)

# Obstacle settings (hitbox dimensions)
obstacle_width = 70  # Obstacle car hitbox width
obstacle_height = 120  # Obstacle car hitbox height
obstacles = [
    {"lane": random.randint(0, lane_count - 1), "y": -obstacle_height, "skin": None},
    {"lane": random.randint(0, lane_count - 1), "y": -obstacle_height - 200, "skin": None},  # Second car starts farther away
]
obstacle_speed = 5  # Initial speed
third_obstacle_added = False  # Flag for adding a third obstacle
fourth_obstacle_added = False  # Flag for adding a fourth obstacle

# Visual dimensions (for rendering only)
visual_car_width = 120  # Player car appears thicker
visual_obstacle_width = 70  # Obstacle car appears thinner

# Load car images with updated visual dimensions
player_car_img = pygame.image.load("car_player.png")  # Replace with your actual car image path
player_car_img = pygame.transform.scale(player_car_img, (visual_car_width, car_height))

# Load multiple obstacle images
obstacle_skins = [
    pygame.transform.scale(pygame.image.load("car_obstacle1.png"), (visual_obstacle_width, obstacle_height)),
    pygame.transform.scale(pygame.image.load("car_obstacle2.png"), (visual_obstacle_width, obstacle_height)),
    pygame.transform.scale(pygame.image.load("car_obstacle3.png"), (visual_obstacle_width, obstacle_height)),
    pygame.transform.scale(pygame.image.load("car_obstacle4.png"), (visual_obstacle_width, obstacle_height)),
]

# Assign random skins to initial obstacles
for obstacle in obstacles:
    obstacle["skin"] = random.choice(obstacle_skins)

# --- NEW: Load settings icon and define button rect ---
settings_icon_img = pygame.image.load("settings_icon.png")
settings_icon_img = pygame.transform.scale(settings_icon_img, (50, 50))
settings_button_rect = pygame.Rect(10, height - 60, 50, 50)  # Bottom left corner button

clock = pygame.time.Clock()
font = pygame.font.Font(pygame.font.match_font('arial'), 36)  # Stylish font
title_font = pygame.font.Font(pygame.font.match_font('arial'), 72)

# Load a monospace font for odometer style speed display
odometer_font = pygame.font.SysFont('consolas', 40, bold=True)

# Game variables and state
score = 0
line_offset = 0  # Offset for moving dashed lines
game_stage = "menu"  # States: 'menu', 'playing', 'drift', 'game_over', 'level_complete', 'settings'

# High score handling
high_score_file = "highscore.txt"

# New variable to track deaths for skip level option
death_count = 0

def load_high_score():
    if os.path.exists(high_score_file):
        with open(high_score_file, "r") as file:
            try:
                return int(file.read().strip())
            except ValueError:
                return 0
    return 0

def save_high_score(high_score):
    with open(high_score_file, "w") as file:
        file.write(str(high_score))

high_score = load_high_score()

def draw_speedometer(speed):
    speed_str = f"{speed:03d} km/h"
    speed_text = odometer_font.render(speed_str, True, WHITE)

    padding_x = 15
    padding_y = 10

    box_width = speed_text.get_width() + 2 * padding_x
    box_height = speed_text.get_height() + 2 * padding_y

    x = width - box_width - 20
    y = height - box_height - 20

    pygame.draw.rect(game_surface, BLACK, (x, y, box_width, box_height), border_radius=10)
    pygame.draw.rect(game_surface, WHITE, (x, y, box_width, box_height), 3, border_radius=10)
    game_surface.blit(speed_text, (x + padding_x, y + padding_y))

def draw_highway():
    global line_offset
    game_surface.fill(ASPHALT)

    pygame.draw.rect(game_surface, ROAD_EDGE, (road_left - 20, 0, 20, height))  # Left shoulder
    pygame.draw.rect(game_surface, ROAD_EDGE, (road_right, 0, 20, height))  # Right shoulder

    pygame.draw.rect(game_surface, ASPHALT, (road_left, 0, road_right - road_left, height))

    pygame.draw.line(game_surface, WHITE, (road_left, 0), (road_left, height), 4)
    pygame.draw.line(game_surface, WHITE, (road_right, 0), (road_right, height), 4)

    line_offset = (line_offset + 5) % 40
    for i in range(1, lane_count):
        lane_x = road_left + i * lane_width
        for y in range(-line_offset, height, 40):
            pygame.draw.rect(game_surface, YELLOW, (lane_x - 2, y, 4, 20))

def draw_game():
    draw_highway()
    visual_car_x = car_x - (visual_car_width - car_width) // 2

    game_surface.blit(player_car_img, (visual_car_x, car_y))
    for obstacle in obstacles:
        obstacle_x = lanes[obstacle["lane"]] - visual_obstacle_width // 2
        game_surface.blit(obstacle["skin"], (obstacle_x, obstacle["y"]))

    score_text = font.render(f"Score: {score}", True, WHITE)
    game_surface.blit(score_text, (10, 10))

    draw_speedometer(obstacle_speed + 95)

def end_game_screen():
    global score, high_score, obstacles, third_obstacle_added, fourth_obstacle_added, game_stage, death_count

    if score > high_score:
        high_score = score
        save_high_score(high_score)

    # Increase death count whenever game over screen is entered
    death_count +=1

    # Define buttons
    play_again_button = pygame.Rect(width // 2 - 100, 300, 200, 50)
    quit_button = pygame.Rect(width // 2 - 100, 400, 200, 50)

    # New Skip Level button if death_count >= 3
    skip_level_button = pygame.Rect(width // 2 - 100, 500, 200, 50) if death_count >= 3 else None

    while True:
        game_surface.fill(ASPHALT)
        end_text = title_font.render("Game Over", True, RED)
        score_text = font.render(f"Your Score: {score}", True, WHITE)
        high_score_text = font.render(f"High Score: {high_score}", True, WHITE)

        # Fullscreen and settings removed from Game Over screen as requested

        play_again_text = font.render("Play Again", True, WHITE)
        quit_text = font.render("Quit", True, WHITE)
        skip_level_text = font.render("Skip Level", True, WHITE) if death_count >=3 else None

        game_surface.blit(end_text, (width // 2 - end_text.get_width() // 2, 100))
        game_surface.blit(score_text, (width // 2 - score_text.get_width() // 2, 200))
        game_surface.blit(high_score_text, (width // 2 - high_score_text.get_width() // 2, 250))

        pygame.draw.rect(game_surface, BLUE, play_again_button)
        pygame.draw.rect(game_surface, BLUE, quit_button)

        game_surface.blit(play_again_text, (play_again_button.x + play_again_button.width // 2 - play_again_text.get_width() // 2,
                                            play_again_button.y + play_again_button.height // 2 - play_again_text.get_height() // 2))
        game_surface.blit(quit_text, (quit_button.x + quit_button.width // 2 - quit_text.get_width() // 2,
                                      quit_button.y + quit_button.height // 2 - quit_text.get_height() // 2))

        # Draw Skip Level button conditionally
        if skip_level_button:
            pygame.draw.rect(game_surface, BLUE, skip_level_button)
            game_surface.blit(skip_level_text, (skip_level_button.x + skip_level_button.width // 2 - skip_level_text.get_width() // 2,
                                                skip_level_button.y + skip_level_button.height // 2 - skip_level_text.get_height() // 2))

        blit_scaled()
        pygame.display.update()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if play_again_button.collidepoint(event.pos):
                    reset_game_variables()
                    score = 0
                    game_stage = "playing"
                    return
                elif quit_button.collidepoint(event.pos):
                    pygame.quit()
                    exit()
                elif skip_level_button and skip_level_button.collidepoint(event.pos):
                    # Reset deaths count so player won't see skip option immediately again
                    death_count = 0
                    # Logic for skipping level - jump score forward and switch game_stage
                    score = 100
                    game_stage = "level_complete"
                    return

def main_menu():
    global game_stage

    play_button_rect = pygame.Rect(width // 2 - 100, 300, 200, 50)
    settings_button_rect_local = settings_button_rect  # Use global rect for consistency

    while game_stage == "menu":
        clock.tick(60)

        for obstacle in obstacles:
            obstacle["y"] += obstacle_speed
            if obstacle["y"] > height:
                obstacle["y"] = -obstacle_height
                obstacle["lane"] = random.randint(0, lane_count - 1)
                obstacle["skin"] = random.choice(obstacle_skins)

        draw_game()

        title_text = title_font.render("Car Game", True, WHITE)
        play_text = font.render("Play", True, WHITE)
        settings_text = font.render("Settings", True, WHITE)

        high_score_text = font.render(f"High Score: {high_score}", True, WHITE)

        game_surface.blit(title_text, (width // 2 - title_text.get_width() // 2, 100))
        game_surface.blit(high_score_text, (width // 2 - high_score_text.get_width() // 2, 200))

        pygame.draw.rect(game_surface, BLUE, play_button_rect)
        game_surface.blit(play_text, (play_button_rect.x + play_button_rect.width // 2 - play_text.get_width() // 2,
                             play_button_rect.y + play_button_rect.height // 2 - play_text.get_height() // 2))

        # --- Draw settings button ---
        game_surface.blit(settings_icon_img, settings_button_rect_local.topleft)

        blit_scaled()
        pygame.display.update()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                # Adjust event.pos for scaled coordinates for correct button detection
                mx, my = event.pos
                scaled_x = mx * (width / win.get_width())
                scaled_y = my * (height / win.get_height())
                if play_button_rect.collidepoint(scaled_x, scaled_y):
                    reset_game_variables()
                    score = 0
                    # Reset death count when starting new game
                    global death_count
                    death_count = 0
                    game_stage = "playing"
                    return
                elif settings_button_rect_local.collidepoint(scaled_x, scaled_y):
                    game_stage = "settings"
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_F11:
                    global fullscreen
                    fullscreen = not fullscreen
                    toggle_fullscreen()

def settings_screen():
    global fullscreen, game_stage

    fullscreen_button_rect = pygame.Rect(width // 2 - 150, 300, 300, 50)
    back_button_rect = pygame.Rect(width // 2 - 100, 400, 200, 50)

    while game_stage == "settings":
        clock.tick(60)

        game_surface.fill(ASPHALT)

        title_text = title_font.render("Settings", True, WHITE)
        game_surface.blit(title_text, (width // 2 - title_text.get_width() // 2, 100))

        fullscreen_text_str = "Fullscreen: ON" if fullscreen else "Fullscreen: OFF"
        fullscreen_text = font.render(fullscreen_text_str, True, WHITE)
        back_text = font.render("Back", True, WHITE)

        pygame.draw.rect(game_surface, BLUE, fullscreen_button_rect)
        game_surface.blit(fullscreen_text, (fullscreen_button_rect.x + fullscreen_button_rect.width // 2 - fullscreen_text.get_width() // 2,
                                    fullscreen_button_rect.y + fullscreen_button_rect.height // 2 - fullscreen_text.get_height() // 2))

        pygame.draw.rect(game_surface, BLUE, back_button_rect)
        game_surface.blit(back_text, (back_button_rect.x + back_button_rect.width // 2 - back_text.get_width() // 2,
                             back_button_rect.y + back_button_rect.height // 2 - back_text.get_height() // 2))

        blit_scaled()
        pygame.display.update()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                mx, my = event.pos
                scaled_x = mx * (width / win.get_width())
                scaled_y = my * (height / win.get_height())
                if fullscreen_button_rect.collidepoint(scaled_x, scaled_y):
                    fullscreen = not fullscreen
                    toggle_fullscreen()
                elif back_button_rect.collidepoint(scaled_x, scaled_y):
                    game_stage = "menu"
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_F11:
                    fullscreen = not fullscreen
                    toggle_fullscreen()
                elif event.key == pygame.K_ESCAPE:
                    game_stage = "menu"

def toggle_fullscreen():
    global win
    if fullscreen:
        info = pygame.display.Info()
        win = pygame.display.set_mode((info.current_w, info.current_h), pygame.FULLSCREEN)
    else:
        win = pygame.display.set_mode((width, height))

# Reset game variables helper
def reset_game_variables():
    global obstacles, third_obstacle_added, fourth_obstacle_added, obstacle_speed
    global car_lane, car_x, car_target_x, score

    obstacles.clear()
    obstacles.extend([
        {"lane": random.randint(0, lane_count - 1), "y": -obstacle_height, "skin": random.choice(obstacle_skins)},
        {"lane": random.randint(0, lane_count - 1), "y": -obstacle_height - 200, "skin": random.choice(obstacle_skins)},
    ])
    third_obstacle_added = False
    fourth_obstacle_added = False
    obstacle_speed = 5
    score = 0
    global car_lane, car_x, car_target_x
    car_lane = 2
    car_x = lanes[car_lane] - car_width // 2
    car_target_x = car_x

# A helper function to scale and blit the game_surface to the window
def blit_scaled():
    window_size = win.get_size()
    scaled_surface = pygame.transform.smoothscale(game_surface, window_size)
    win.blit(scaled_surface, (0, 0))

# --- Level Complete Choice Stage ---
def level_complete_screen():
    global game_stage, fullscreen, win

    clock.tick(60)

    continue_text = font.render("Continue Playing", True, WHITE)
    drift_text = font.render("Enter Drift Stage", True, WHITE)
    title_text = title_font.render("Level 100 Reached!", True, WHITE)

    continue_button = pygame.Rect(width // 2 - 150, 300, 300, 50)
    drift_button = pygame.Rect(width // 2 - 150, 400, 300, 50)

    draw_highway()

    game_surface.blit(title_text, (width // 2 - title_text.get_width() // 2, 150))

    pygame.draw.rect(game_surface, BLUE, continue_button)
    pygame.draw.rect(game_surface, BLUE, drift_button)

    game_surface.blit(continue_text, (continue_button.x + continue_button.width // 2 - continue_text.get_width() // 2,
                             continue_button.y + continue_button.height // 2 - continue_text.get_height() // 2))
    game_surface.blit(drift_text, (drift_button.x + drift_button.width // 2 - drift_text.get_width() // 2,
                          drift_button.y + drift_button.height // 2 - drift_text.get_height() // 2))

    fs_toggle_text = font.render("Press F11 to Toggle Fullscreen", True, WHITE)
    game_surface.blit(fs_toggle_text, (width // 2 - fs_toggle_text.get_width() // 2, 500))

    blit_scaled()
    pygame.display.update()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        elif event.type == pygame.MOUSEBUTTONDOWN:
            mx, my = event.pos
            scaled_x = mx * (width / win.get_width())
            scaled_y = my * (height / win.get_height())
            if continue_button.collidepoint(scaled_x, scaled_y):
                game_stage = "playing"
            elif drift_button.collidepoint(scaled_x, scaled_y):
                global drift_timer, drift_position, drift_angle, drift_speed, drift_velocity
                drift_timer = 0
                drift_position.update(width // 2, height - 150)
                drift_angle = 0
                drift_speed = 0
                drift_velocity.update(0, 0)
                game_stage = "drift"
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_F11:
                global fullscreen
                fullscreen = not fullscreen
                toggle_fullscreen()

# --- Drifting Stage Variables ---
drift_position = pygame.Vector2(width // 2, height - 150)
drift_velocity = pygame.Vector2(0, 0)
drift_angle = 0  # degrees
drift_speed = 0
DRIFT_MAX_SPEED = 10
DRIFT_ACCELERATION = 0.2
DRIFT_FRICTION = 0.05
DRIFT_TURN_SPEED = 3  # degrees per frame
drift_timer = 0
DRIFT_TIME_LIMIT = 30 * 60  # 30 seconds * 60 FPS

drift_car_img = player_car_img  # Reuse player car image

def drift_stage():
    global drift_position, drift_velocity, drift_angle, drift_speed, drift_timer, game_stage, score
    global fullscreen, win

    clock.tick(60)
    drift_timer += 1

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_F11:
                fullscreen = not fullscreen
                toggle_fullscreen()

    keys = pygame.key.get_pressed()

    if keys[pygame.K_LEFT]:
        drift_angle += DRIFT_TURN_SPEED
    if keys[pygame.K_RIGHT]:
        drift_angle -= DRIFT_TURN_SPEED

    if keys[pygame.K_UP]:
        drift_speed += DRIFT_ACCELERATION
    else:
        drift_speed -= DRIFT_FRICTION

    drift_speed = max(0, min(DRIFT_MAX_SPEED, drift_speed))

    rad_angle = -drift_angle * (3.14159265 / 180)
    drift_velocity.x = drift_speed * pygame.math.Vector2(1, 0).rotate(rad_angle).x
    drift_velocity.y = drift_speed * pygame.math.Vector2(1, 0).rotate(rad_angle).y

    drift_position += drift_velocity

    drift_position.x = max(visual_car_width // 2, min(width - visual_car_width // 2, drift_position.x))
    drift_position.y = max(car_height // 2, min(height - car_height // 2, drift_position.y))

    game_surface.fill((180, 220, 255))  # Icy blue

    rotated_car = pygame.transform.rotate(drift_car_img, drift_angle)
    rect = rotated_car.get_rect(center=drift_position)
    game_surface.blit(rotated_car, rect.topleft)

    time_left = max(0, (DRIFT_TIME_LIMIT - drift_timer) // 60)
    timer_text = font.render(f"Time Left: {time_left}s", True, BLACK)
    game_surface.blit(timer_text, (10, 10))

    speed_text = font.render(f"Speed: {int(drift_speed*10)}", True, BLACK)
    game_surface.blit(speed_text, (10, 50))

    fs_toggle_text = font.render("Press F11 to Toggle Fullscreen", True, BLACK)
    game_surface.blit(fs_toggle_text, (width // 2 - fs_toggle_text.get_width() // 2, height - 40))

    blit_scaled()
    pygame.display.update()

    if drift_timer >= DRIFT_TIME_LIMIT:
        drift_timer = 0
        reset_game_variables()
        game_stage = "menu"

# --- Main Playing Loop ---
def play_stage():
    global score, obstacle_speed, third_obstacle_added, fourth_obstacle_added
    global car_x, car_target_x, car_lane, game_stage
    global fullscreen, win

    clock.tick(60)

    obstacle_speed = 5 + (score // 10)

    if score >= 10 and not third_obstacle_added:
        obstacles.append({"lane": random.randint(0, lane_count - 1), "y": -obstacle_height - 400, "skin": random.choice(obstacle_skins)})
        third_obstacle_added = True

    if score >= 20 and not fourth_obstacle_added:
        obstacles.append({"lane": random.randint(0, lane_count - 1), "y": -obstacle_height - 600, "skin": random.choice(obstacle_skins)})
        fourth_obstacle_added = True

    draw_game()
    blit_scaled()
    pygame.display.update()

    for obstacle in obstacles:
        obstacle["y"] += obstacle_speed
        if obstacle["y"] > height:
            obstacle["y"] = -obstacle_height
            obstacle["lane"] = random.randint(0, lane_count - 1)
            obstacle["skin"] = random.choice(obstacle_skins)
            score += 1

    if car_x < car_target_x:
        car_x += min(car_speed, car_target_x - car_x)
    elif car_x > car_target_x:
        car_x -= min(car_speed, car_x - car_target_x)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT and car_lane > 0:
                car_lane -= 1
                car_target_x = lanes[car_lane] - car_width // 2
            elif event.key == pygame.K_RIGHT and car_lane < lane_count - 1:
                car_lane += 1
                car_target_x = lanes[car_lane] - car_width // 2
            elif event.key == pygame.K_F11:
                fullscreen = not fullscreen
                toggle_fullscreen()

    car_rect = pygame.Rect(car_x, car_y, car_width, car_height)
    for obstacle in obstacles:
        obstacle_x = lanes[obstacle["lane"]] - obstacle_width // 2

        obstacle_hitbox_width = obstacle_width * 0.1
        obstacle_hitbox_height = obstacle_height * 0.1
        obstacle_hitbox_x = obstacle_x + (obstacle_width - obstacle_hitbox_width) // 2
        obstacle_hitbox_y = obstacle["y"] + (obstacle_height - obstacle_hitbox_height) // 2

        obstacle_rect = pygame.Rect(
            obstacle_hitbox_x, obstacle_hitbox_y, obstacle_hitbox_width, obstacle_hitbox_height
        )

        if car_rect.colliderect(obstacle_rect):
            game_stage = "game_over"
            return

    if score >= 100 and game_stage != "level_complete":
        game_stage = "level_complete"

def main():
    global game_stage
    reset_game_variables()
    while True:
        if game_stage == "menu":
            main_menu()
        elif game_stage == "settings":
            settings_screen()  # added settings screen here
        elif game_stage == "playing":
            play_stage()
        elif game_stage == "drift":
            drift_stage()
        elif game_stage == "game_over":
            end_game_screen()
        elif game_stage == "level_complete":
            level_complete_screen()

if __name__ == "__main__":
    main() make it so the continue playing works