import pyxel
import random
import math

# --- Configuration ---
TILE = 16
PLAYER_SIZE = (8, 16)
SCREEN_W = 10 * TILE
SCREEN_H = 10 * TILE
FPS = 90
ROAD_COLOR = 0
BG_COLOR = 0
LANE_TYPES = ["grass", "road"]
# Densities & speeds: default (will be updated by menu)
CAR_DENSITY_MIN = 0.01  # rehaussé (Easy plus dur)
CAR_DENSITY_MAX = 0.02
CAR_SPEED_MIN = 0.7
CAR_SPEED_MAX = 1.2
SAFE_ZONE_BOTTOM_SIZE = 3
SAFE_ZONE_TOP_SIZE = 15
CAR_SIZE = (24, 16)
TRUCK_SIZE = (32, 16)


# --- Bouton animé ---
class Button:
    def __init__(self, x, y, w, h, label):
        self.x = x  #position horizontal
        self.y = y #pos vert
        self.w = w #longeur
        self.h = h #hauteur
        self.label = label #nom du bouton
        self.hover_timer = 0

    def is_hovered(self):
        return self.x <= pyxel.mouse_x <= self.x + self.w and self.y <= pyxel.mouse_y <= self.y + self.h #savoir si la souris est dans le rectangle

    def is_clicked(self):
        return self.is_hovered() and pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT)#si la souris est dans le rectangle et il est clique

    def draw(self):
        hovered = self.is_hovered() #on verifie si le bouton est survole 
        if hovered:
            self.hover_timer = min(self.hover_timer + 0.2, 1)#animation si survole
        else:
            self.hover_timer = max(self.hover_timer - 0.2, 0)
        scale = 1 + 0.05 * math.sin(self.hover_timer * math.pi)
        w_scaled = int(self.w * scale)#agrandi avec l'animation
        h_scaled = int(self.h * scale)
        x_scaled = self.x - (w_scaled - self.w) // 2 #pour que l'anim reste centre
        y_scaled = self.y - (h_scaled - self.h) // 2
        color = 6 if hovered else 1
        pyxel.rect(x_scaled, y_scaled, w_scaled, h_scaled, color)
        pyxel.text(
            x_scaled + w_scaled // 2 - len(self.label) * 2,
            y_scaled + h_scaled // 2 - 2,
            self.label,
            7,
        )

# --- Joueur ---
class Player:
    def __init__(self, x, y, skin=(0, 16)):
        self.x = x
        self.y = y
        self.w, self.h = PLAYER_SIZE
        self.w -= 4
        self.h -= 4
        self.skin = skin

    def rect(self):
        return (self.x + 2, self.y + 2, self.w, self.h)

# --- Routes ---
class Lane:
    """ Lane représente une rangée. Si type == "road", elle contient 1..3 files. Chaque file a:
    - speed (même pour toutes les voitures de la file),
    - dir (même pour toutes les voitures de la file),
    - density,
    - cars: liste d'éléments [x, car_type, w, h, y_offset, anim_timer, speed_factor, anim_state]
    """
    def __init__(self, world_row_index, lane_type, biome="forest", difficulty="easy"):
        self.difficulty = difficulty
        self.level = "easy"
        self.world_row = world_row_index
        self.type = lane_type
        self.y = self.world_row * TILE
        self.biome = biome
        self.cars = []
        self.files = []
        self.update_speed_based_on_difficulty()
        
    
        # --- Décors aléatoires (spawnent partout sur la largeur) ---
        self.decor_sprites = []
        if self.type == "grass":  # ou != "road" si tu veux en mettre aussi ailleurs
            biome_decor = {
                "forest": [(48,0), (48,32)],   # arbres, buissons
                "desert": [(56,0), (56,32)],   # cactus, rochers
                "neige": [(48,16), (48,48)],     # sapins enneigés
                "city": [(56,16), (56,48)],     # lampadaires, panneaux
                #"progressif": [(0,128), (16,128), (32,128)] # default
            }
    
            decor_list = biome_decor.get(biome, [])#decor en fonction du biome
    
            # combien de décors maximum sur une lane
            decor_count = random.randint(3, 6)
    
            for _ in range(decor_count):
                if random.random() < 0.8 and decor_list:
                    u, v = random.choice(decor_list)
                    # Position aléatoire sur toute la largeur
                    x = random.randint(0, SCREEN_W - 8)
                    y_offset = random.randint(-2, 2)  # petite variation verticale
                    self.decor_sprites.append({
                        "x": x,
                        "y_offset": y_offset,
                        "u": u,
                        "v": v,
                        "w": 8,
                        "h": 16
                    })
    
        # --- Routes ---
        if self.type == "road":
            self.file_count = random.randint(1, 3)
            lane_direction = random.choice([-1, 1])
            for i in range(self.file_count):
                speed = random.uniform(CAR_SPEED_MIN, CAR_SPEED_MAX)
                direction = lane_direction
                density = random.uniform(CAR_DENSITY_MIN, CAR_DENSITY_MAX)
                self.files.append({
                    "speed": speed,
                    "dir": direction,
                    "density": density,
                    "cars": [],
                    "lane_index": i,
                    "spawn_timer": random.randint(0, 8)
                })



    def update(self):
        if self.type != "road":
            return
    
        # --- Mise à jour des voitures existantes ---
        for f in self.files:
            cars = f["cars"]
            direction = f.get("dir", 1)
            base_speed = f.get("speed", random.uniform(CAR_SPEED_MIN, CAR_SPEED_MAX))
    
            for car in cars:
                # vitesse individuelle avec variation ±10 %
                if len(car) >= 7:
                    speed_factor = car[6]
                else:
                    speed_factor = random.uniform(0.9, 1.1)
                    car.append(speed_factor)
    
                car_speed = base_speed * speed_factor
                car[0] += car_speed * direction
    
                # petite animation d’apparition
                #if len(car) >= 8:
                    #car[7] += 1
                    #if car[7] < 15:
                        #start_offset = SCREEN_W if direction == -1 else -car[2]
                        #target_x = 0 if direction == 1 else SCREEN_W - car[2]
                        #t = car[7] / 15
                        #car[0] = start_offset * (1 - t) + target_x * t
    
            # Nettoyage des voitures hors écran
            cars[:] = [c for c in cars if -c[2] * 3 <= c[0] <= SCREEN_W + c[2] * 3]#garde que les voiture qui sont dans le cadre laisse une petite marge
    
        # --- Gestion du spawn ---
        for f in self.files:
            f["spawn_timer"] = f.get("spawn_timer", 0) + 1
            if f["spawn_timer"] < 12:#spawn tt les 12 tik
                continue
            f["spawn_timer"] = 0
    
            cars = f["cars"]#recup liste de voiture pour cette file
            if len(cars) >= 6 or random.random() > f["density"]:#6voiture max par lane a la fois apres on nen spawn plus
                continue
    
            # --- Choix du type de véhicule ---
            # 20% de chance d'une voiture spéciale 
            if random.random() < 0.2:
                car_type = 2  # voiture spéciale
                w, h = CAR_SIZE  # taille normale
            else:
                car_type = random.choice([0, 1])  # voiture normale ou camion
                w, h = CAR_SIZE if car_type == 0 else TRUCK_SIZE
    
            y_offset = (TILE - h) // 2
            direction = f.get("dir", 1)
    
            # --- Position de spawn ---
            x_spawn = -w + 2 if direction == 1 else SCREEN_W - 2
    
            # --- Vérifie l’espace disponible avant de spawn ---
            SAFE_GAP = TILE * 2 + w#distance min entre voiture
            all_cars = [c for f2 in self.files for c in f2["cars"]]
            too_close = any(abs(c[0] - x_spawn) < SAFE_GAP for c in all_cars)
            if too_close:
                continue
    
            # --- Ajoute le véhicule ---
            f["cars"].append([x_spawn, car_type, w, h, y_offset, 0, random.uniform(0.9, 1.1), 0])
    
            # petit son si tu veux garder ça
            if random.random() < 0.025:
                try:
                    pyxel.play(2, 1)
                except Exception:
                    pass


    def draw(self, camera_y):
        screen_y = self.y - camera_y
        TILE = 16
    
        # --- Couleurs des biomes ---
        biome_colors = {
            "forest": 11,
            "neige": 6,
            "city": 13,
            "desert": 10,
            "progressif": 11
        }
    
        # --- Routes ---
        if self.type == "road":
            # Dessine la route principale
            pyxel.rect(0, screen_y, SCREEN_W, TILE, ROAD_COLOR)
    
            # Lignes blanches centrales (pointillées)
            for sx in range(-TILE, SCREEN_W + TILE, TILE * 2):
                pyxel.rect(sx, screen_y + TILE // 2 - 1, TILE, 2, 7)
    
            # --- Dessine les voitures ---
            for f in self.files:
                direction = f.get("dir", 1)
                lane_index = f["lane_index"]
    
                for car in f["cars"]:
                    x = int(car[0])
                    car_type = car[1]
                    w = car[2]
                    h = car[3]
                    y_offset = car[4]
                    flip_width = -w if direction == 1 else w
    
                    # --- Sélection du sprite en fonction du type et du biome ---
                    # type 0 = voiture normale, type 1 = camion, type 2 = voiture spéciale
                    if car_type == 0:
                        u, v = 0, 0
                    elif car_type == 1:
                        u, v = 16, 16
                    elif car_type == 2:
                        # voiture spéciale selon le biome
                        special_sprites = {
                            "forest": (24, 32),   # ex: voiture de forêt
                            "desert": (24, 0),  # ex: voiture de désert
                            "neige": (24, 48),    # ex: motoneige
                            "city": (24, 64),    # ex: taxi
                        }
                        u, v = special_sprites.get(self.biome, (0, 0))
    
                    # Décalage de la file pour l’alignement
                    file_offset_x = (lane_index - (len(self.files) - 1) / 2) * 6
    
                    # Dessin du véhicule
                    try:
                        pyxel.blt(int(x + file_offset_x), screen_y + y_offset, 0, u, v, flip_width, h, 0)
                    except Exception:
                        # fallback (rectangle si le sprite n’existe pas)
                        pyxel.rect(int(x + file_offset_x), screen_y + y_offset, w, h, 8)
    
        # --- Terrain normal (herbe, sable, neige, etc.) ---
        else:
            color = biome_colors.get(self.biome, 3)
            pyxel.rect(0, screen_y, SCREEN_W, TILE, color)
    
            # --- Décors latéraux ---
            for decor in self.decor_sprites:
                pyxel.blt(decor["x"], screen_y + decor["y_offset"], 0, decor["u"], decor["v"], decor["w"], decor["h"], 0)
                
    def update_speed_based_on_difficulty(self):
        if self.level == "easy":
            CAR_DENSITY_MIN = 0.01
            CAR_DENSITY_MAX = 0.02
            CAR_SPEED_MIN =  0.7
            CAR_SPEED_MAX = 1.2
        elif self.level == "medium":
            CAR_DENSITY_MIN = 0.02
            CAR_DENSITY_MAX = 0.04
            CAR_SPEED_MIN = 1.2
            CAR_SPEED_MAX = 1.8
        elif self.level == "hard":
            CAR_DENSITY_MIN = 0.05
            CAR_DENSITY_MAX = 0.08
            CAR_SPEED_MIN = 1.8
            CAR_SPEED_MAX = 2.5
        elif self.level == "impossible":
            CAR_DENSITY_MIN = 0.08
            CAR_DENSITY_MAX = 0.15
            CAR_SPEED_MIN = 2.5
            CAR_SPEED_MAX = 3.5
    
        # Assigner aux variables de l’instance
        self.car_density_min = CAR_DENSITY_MIN
        self.car_density_max = CAR_DENSITY_MAX
        self.car_speed_min = CAR_SPEED_MIN
        self.car_speed_max = CAR_SPEED_MAX
        
    def regenerate_decor(self):
        self.decor_sprites = []
        if self.type == "grass":
            biome_decor = {
                "forest": [(48,0), (48,32)],
                "desert": [(56,0), (56,32)],
                "neige": [(48,16), (48,48)],
                "city": [(56,16), (56,48)],
            }
            decor_list = biome_decor.get(self.biome, [])
            decor_count = random.randint(3, 6)
            for _ in range(decor_count):
                if decor_list and random.random() < 0.8:
                    u, v = random.choice(decor_list)
                    x = random.randint(0, SCREEN_W - 8)
                    y_offset = random.randint(-2, 2)
                    self.decor_sprites.append({
                        "x": x,
                        "y_offset": y_offset,
                        "u": u,
                        "v": v,
                        "w": 8,
                        "h": 16
                    })
        





# ------------------ [ICI, tout le reste du Game class avec menus, update/draw, main] ------------------
# Ce bloc continue exactement comme tu l’avais envoyé, sans rien couper.
class Game:
    def __init__(self):
        pyxel.init(SCREEN_W, SCREEN_H, fps=FPS, title="CROSSY RUNNER")
        pyxel.mouse(True)
        # charge ton res.pyxres existant (ne modifie rien dedans)
        try:
            pyxel.load("res.pyxres")
            pyxel.playm(1, loop=True)#joue music1 en boucle 
        except Exception:
            pass
        # --- Réinitialisation des sons (SFX) ---
# Ces sons sont recréés en mémoire, donc ils remplacent ceux du fichier res.pyxres.

        # Son de déplacement / saut
        pyxel.sound(0).set(
            notes="c2e2g2",
            tones="p",
            volumes="7",
            effects="n",
            speed=8
        )
        
        # Son de klaxon / collision
        pyxel.sound(1).set(
            notes="g2r g2r g2r",  # g2, petit "bip-bip-bip"
            tones="s",
            volumes="7",
            effects="n",
            speed=4
        )
        
        # Son de mort
        pyxel.sound(2).set(
            notes="c3a2f2c2",
            tones="p",
            volumes="7654",
            effects="n",
            speed=10
        )
        # --- Son de transition de biome 
        pyxel.sound(4).set(
            notes="C3R D3R E3R G3R C4RR",  # montée claire, avec pauses
            tones="TTTTT",                  # son triangle, doux mais net
            volumes="77777",                # volume fort et constant
            effects="NNNNN",                # pas d’effet
            speed=6                         # vitesse modérée pour entendre les notes
        )



       
        self.menu_state = "main"
        self.level = "easy"
        self.current_level = self.level

        #self.current_biome = "forest"
        
        self.biome_transition_timer = 0#temps de transition de biome en mode progressif
        self.biome_transition_text = ""
        self.best = 0
        self.level = "Easy"
        self.selected_skin = (0, 16)#taille skin
        self.victory = False
        self.victory_fade = 0
        self.name = getattr(self, "name", "easy")

       
        # --- MENU SKIN ---
        self.skin_page = "character"  # ou "biome"
        self.selected_biome = getattr(self, "selected_biome", "forest")
        self.selected_difficulty = getattr(self, "selected_difficulty", "easy")
        self.current_biome = getattr(self, "current_biome", self.selected_biome)
        self.current_difficulty = getattr(self, "current_difficulty", self.selected_difficulty)

       
        
        self.available_biomes = ["forest", "neige", "city", "desert", "progressif"]

        # Controls par défaut (modifiable via menu CONTROLS)
        self.controls = {
            "up": pyxel.KEY_W,
            "down": pyxel.KEY_S,
            "left": pyxel.KEY_A,
            "right": pyxel.KEY_D,
            "pause": pyxel.KEY_P,
            "menu": pyxel.KEY_M,   
        }


        # Centrage vertical des 4 boutons
        center_x = SCREEN_W // 2 - 50
        # Centrage vertical des 4 boutons
        total_height = (4 * 20) + (3 * 30 - 3 * 20)  # ou plus simplement 4*20 + 3*30 - 3*20 = 110
        center_y = (SCREEN_H - 110) // 2

        # Boutons principaux (ajout de CONTROLS)
        self.buttons_main = [
            Button(center_x, center_y, 100, 20, "PLAY"),
            Button(center_x, center_y + 30, 100, 20, "SKIN"),
            Button(center_x, center_y + 60, 100, 20, "LEVEL"),
            Button(center_x, center_y + 90, 100, 20, "CONTROLS"),
        ]

        # flags d'affichage et animations
        self.paused = False
        self.pause_fade = 0
        self.gameover_fade = 0

        self.reset()
        pyxel.run(self.update, self.draw)

    # ------------------ MENUS ------------------
    def update_menu_main(self):
        pyxel.mouse(True)
        if self.buttons_main[0].is_clicked():
            self.menu_state = "playing"
            self.reset()
        elif self.buttons_main[1].is_clicked():
            self.menu_state = "skin"
            #print("menu_state set to skin")
        elif self.buttons_main[2].is_clicked():
            self.menu_state = "level"
        elif self.buttons_main[3].is_clicked():
            self.menu_state = "controls"

    def draw_menu_main(self):
        pyxel.text(SCREEN_W // 2 - 30, 18, "CROSSY RUNNER", 10)
        for b in self.buttons_main:
            b.draw()
        pyxel.text(4, SCREEN_H - 10, f"Level: {self.level}", 8)

    # --- Menu Skin
    # --- UPDATE MENU SKIN ---
    def update_menu_skin(self):
        pyxel.mouse(True)
        mx, my = pyxel.mouse_x, pyxel.mouse_y
    
        # --- PAGE PERSONNAGE ---
        if self.skin_page == "character":
            skins = [(0,16), (8,16), (0,32), (8,32), (0,48), (8,48), (0,64), (8,64), (0,80)]
            case_width = 32
            case_height = 24
            gap_x = 8
            gap_y = 8
            cols = 3#nbr de colonnes
            total_width = cols * case_width + (cols-1) * gap_x
            total_height = ((len(skins) + cols - 1)//cols) * case_height + (((len(skins) + cols - 1)//cols) -1) * gap_y
            x_start = (SCREEN_W - total_width)//2
            y_start = (SCREEN_H - total_height)//2
    
            if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
                for i,(u,v) in enumerate(skins):
                    col = i % cols
                    row = i // cols
                    sx = x_start + col*(case_width + gap_x)
                    sy = y_start + row*(case_height + gap_y)
    
                    # Hitbox sur toute la case
                    if sx <= mx <= sx + case_width and sy <= my <= sy + case_height:
                        self.selected_skin = (u,v)
    
                # Bouton retour au menu principal
                if 10 <= mx <= 60 and SCREEN_H-20 <= my <= SCREEN_H-5:
                    self.menu_state = "main"
    
                # Flèche → pour passer à la page biome
                if SCREEN_W - 25 <= mx <= SCREEN_W - 10 and 10 <= my <= 20:
                    self.skin_page = "biome"
    
        # --- PAGE BIOME ---
        elif self.skin_page == "biome":
            case_width = 50
            case_height = 30
            cols = 2
            rows = (len(self.available_biomes) + cols -1)//cols
            total_width = cols * case_width + (cols - 1) * 20
            total_height = rows * case_height + (rows - 1) * 10
            x_start = (SCREEN_W - total_width)//2
            y_start = (SCREEN_H - total_height)//2
    
            if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
                for idx, biome in enumerate(self.available_biomes):
                    col = idx % cols
                    row = idx // cols
                    bx = x_start + col*(case_width + 20)
                    by = y_start + row*(case_height + 10)
    
                    # Hitbox sur toute la case
                    if bx <= mx <= bx + case_width and by <= my <= by + case_height:
                        self.selected_biome = biome
    
                # Flèche ← pour revenir à la page personnage
                if 10 <= mx <= 25 and 10 <= my <= 20:
                    self.skin_page = "character"
    
    # --- DRAW MENU SKIN ---
    def draw_menu_skin(self):
        pyxel.cls(1)
    
        # --- PAGE PERSONNAGE ---
        if self.skin_page == "character":
            pyxel.text(SCREEN_W//2 - 30, 20, "CHOOSE SKIN", 10)
            skins = [(0,16), (8,16), (0,32), (8,32), (0,48), (8,48), (0,64), (8,64), (0,80)]
            case_width = 32
            case_height = 24
            gap_x = 8
            gap_y = 8
            cols = 3
            total_width = cols * case_width + (cols-1) * gap_x
            total_height = ((len(skins)+cols-1)//cols) * case_height + (((len(skins)+cols-1)//cols)-1) * gap_y
            x_start = (SCREEN_W - total_width)//2
            y_start = (SCREEN_H - total_height)//2
    
            for i,(u,v) in enumerate(skins):
                col = i % cols
                row = i // cols
                sx = x_start + col*(case_width + gap_x)
                sy = y_start + row*(case_height + gap_y)
    
                pyxel.rectb(sx, sy, case_width, case_height, 7)
                skin_x = sx + (case_width-8)//2
                skin_y = sy + (case_height-16)//2
                try:
                    pyxel.blt(skin_x, skin_y, 0, u, v, 8, 16, 0)
                except Exception:
                    pass
                if (u,v) == self.selected_skin:
                    pyxel.rectb(sx-2, sy-2, case_width+4, case_height+4, 8)
    
            # Bouton retour menu principal
         
            pyxel.text(20, SCREEN_H-15, "< BACK", 8)
    
            # Flèche → page biome
            
            pyxel.text(SCREEN_W-31, 12, "BIOME >", 8)
    
        # --- PAGE BIOME ---
        elif self.skin_page == "biome":
            case_width = 50
            case_height = 30
            cols = 2
            rows = (len(self.available_biomes)+cols-1)//cols
            total_width = cols * case_width + (cols -1) * 20
            total_height = rows * case_height + (rows-1) * 10
            x_start = (SCREEN_W - total_width)//2
            y_start = (SCREEN_H - total_height)//2
    
            pyxel.text(SCREEN_W//2 - 35, y_start - 20, "CHOOSE BIOME", 10)
    
            for idx, biome in enumerate(self.available_biomes):
                col = idx % cols
                row = idx // cols
                bx = x_start + col*(case_width + 20)
                by = y_start + row*(case_height + 10)
                color = 7
                if biome == self.selected_biome:
                    color = 8
                pyxel.rectb(bx, by, case_width, case_height, 7)  # contour blanc permanent
                pyxel.text(bx + 5, by + 10, biome.upper(), color)
    
            # Flèche ← page personnage
            
            pyxel.text(12, 12, "< BACK", 8)


        

# --- Menu Level ---
    def update_menu_level(self):
        pyxel.mouse(True)
        global CAR_DENSITY_MIN, CAR_DENSITY_MAX, CAR_SPEED_MIN, CAR_SPEED_MAX
        levels = [("Easy",0.01,0.02), ("Medium",0.02,0.04), ("Hard",0.05,0.08), ("Impossible",0.08,0.15)]
        case_width = 100
        case_height = 20
        gap_y = 10
        x_start = SCREEN_W // 2 - case_width // 2
        total_height = (4 * case_height) + (3 * gap_y)
        y_start = (SCREEN_H - total_height) // 2
        mx, my = pyxel.mouse_x, pyxel.mouse_y

        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
        # sélection niveau
            for i,(name,min_d,max_d) in enumerate(levels):
                sy = y_start + i*(case_height+gap_y)
                if x_start <= mx <= x_start+case_width and sy <= my <= sy+case_height:
                    self.level = name
                    if name == "Easy":
                        CAR_DENSITY_MIN, CAR_DENSITY_MAX = 0.01, 0.02
                        CAR_SPEED_MIN, CAR_SPEED_MAX = 0.7, 1.2
                    elif name == "Medium":
                        CAR_DENSITY_MIN, CAR_DENSITY_MAX = 0.02, 0.04
                        CAR_SPEED_MIN, CAR_SPEED_MAX = 1.2, 1.8
                    elif name == "Hard":
                        CAR_DENSITY_MIN, CAR_DENSITY_MAX = 0.05, 0.08
                        CAR_SPEED_MIN, CAR_SPEED_MAX = 1.8, 2.5
                    elif name == "Impossible":
                        CAR_DENSITY_MIN, CAR_DENSITY_MAX = 0.08, 0.15
                        CAR_SPEED_MIN, CAR_SPEED_MAX = 2.5, 3.5
        # bouton back
            if 10 <= mx <= 60 and SCREEN_H - 20 <= my <= SCREEN_H - 5:
                self.menu_state = "main"

    def draw_menu_level(self):
        pyxel.cls(1)
        title = "CHOOSE LEVEL"
        pyxel.text(SCREEN_W // 2 - len(title)*2, 10, title, 10)
        levels = ["Easy", "Medium", "Hard", "Impossible"]
        case_width = 100
        case_height = 20
        gap_y = 10
        x_start = SCREEN_W // 2 - case_width // 2
        total_height = (4 * case_height) + (3 * gap_y)
        y_start = (SCREEN_H - total_height) // 2
        for i, name in enumerate(levels):
            sy = y_start + i * (case_height + gap_y)
            color = 8 if name == self.level else 7
            pyxel.rectb(x_start, sy, case_width, case_height, color)
            pyxel.text(x_start + case_width // 2 - len(name)*2, sy + 6, name, 7)
        pyxel.text(10, SCREEN_H - 15, "< BACK", 8)


# --- Menu Controls ---
    def update_menu_controls(self):
        pyxel.mouse(True)
        mx, my = pyxel.mouse_x, pyxel.mouse_y
        controls = [
            ("up","UP"),
            ("down","DOWN"),
            ("left","LEFT"),
            ("right","RIGHT"),
            ("pause","PAUSE"),   
            ("menu","MENU"),     
        ]

        case_w = 140
        case_h = 18
        x_start = SCREEN_W//2 - case_w//2
        total_height = len(controls) * (case_h + 6) - 6
        y_start = SCREEN_H//2 - total_height//2


        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
            for i,(key,label) in enumerate(controls):
                sy = y_start + i*(case_h+6)
                if x_start <= mx <= x_start+case_w and sy <= my <= sy+case_h:
                    self.awaiting_key = key
                    return
            # bouton back
            if 10 <= mx <= 70 and SCREEN_H - 20 <= my <= SCREEN_H:
                self.menu_state = "main"

    
        # check clavier si en attente
        if hasattr(self, "awaiting_key"):
            for k in range(0, 512):
                if pyxel.btnp(k):
                    self.controls[self.awaiting_key] = k
                    try:
                        del self.awaiting_key
                    except Exception:
                        pass
                    break
    
    def draw_menu_controls(self):
        pyxel.cls(1)
        title = "CONTROLS"
        pyxel.text(SCREEN_W // 2 - len(title) * 2, 4, title, 10)
        controls = [
            ("up","UP"),
            ("down","DOWN"),
            ("left","LEFT"),
            ("right","RIGHT"),
            ("pause","PAUSE"),   
            ("menu","MENU"),     
        ]

        case_w = 140
        case_h = 18
        x_start = SCREEN_W//2 - case_w//2
        total_height = len(controls) * (case_h + 6) - 6
        y_start = SCREEN_H//2 - total_height//2

    
        for i,(key,label) in enumerate(controls):
            sy = y_start + i*(case_h+6)#les cases sont empile separe de 6px
            pyxel.rectb(x_start, sy, case_w, case_h, 7)#contours blanc
            code = self.controls.get(key, 0)#recupere une touche 
            name = None
            try:
                name = pyxel.KEY_NAMES.get(code)#nom = la touche selectionne
            except Exception:
                pass
            if not name:
                if 32 <= code <= 126:
                    try:
                        name = chr(code).upper()
                    except Exception:
                        name = None
            if not name:
                key_map = {
                    getattr(pyxel, "KEY_UP", -1): "UP",
                    getattr(pyxel, "KEY_DOWN", -1): "DOWN",
                    getattr(pyxel, "KEY_LEFT", -1): "LEFT",
                    getattr(pyxel, "KEY_RIGHT", -1): "RIGHT",
                    getattr(pyxel, "KEY_SPACE", -1): "SPACE",
                    getattr(pyxel, "KEY_ENTER", -1): "ENTER",
                    getattr(pyxel, "KEY_RETURN", -1): "ENTER",
                    getattr(pyxel, "KEY_ESCAPE", -1): "ESC",
                    getattr(pyxel, "KEY_TAB", -1): "TAB",
                }
                name = key_map.get(code, f"Key {code}")
            pyxel.text(x_start + 8, sy + 4, f"{label}: {name}", 7 if not hasattr(self, "awaiting_key") or self.awaiting_key != key else 8)
        pyxel.text(10, SCREEN_H - 10, "< BACK", 8)
        if hasattr(self, "awaiting_key"):#verifie si on attend l'appui dune touche
            pyxel.text(SCREEN_W//2 - 40, SCREEN_H - 30, "Press a key...", 8)
    # ------------------ GAME ------------------
    def choose_lane_type(self,row):
        last3 = [self.lanes.get(row-i-1) for i in range(3)]
        if all(l is not None and l.type=="grass" for l in last3):
            return "road"
        else:
            return random.choice(LANE_TYPES)

    def reset(self):
        self.lanes = {}
        self.player = Player((SCREEN_W//2)-(TILE//2), 0, self.selected_skin)
        self.camera_y = self.player.y - SCREEN_H//2
        self.score = 0
        self.highest_row_reached = 0
        self.game_over = False
        self.move_cooldown = 0
        self.hit_timer = 0
        self.paused = False
        self.pause_fade = 0
        self.gameover_fade = 0
        self.current_biome = self.selected_biome
        self.current_difficulty = "easy"
        

    
        # Zones sûres en bas
        for i in range(-SAFE_ZONE_BOTTOM_SIZE, 0):
            self.lanes[i] = Lane(i, "grass", biome=self.current_biome, difficulty=self.current_difficulty)

# Zone initiale en haut
        for i in range(0, SAFE_ZONE_TOP_SIZE+1):
            self.lanes[i] = Lane(i, "grass", biome=self.current_biome, difficulty=self.current_difficulty)

# Lanes générées dynamiquement après
        for i in range(SAFE_ZONE_TOP_SIZE+1, SAFE_ZONE_TOP_SIZE+20):
            self.lanes[i] = Lane(i, self.choose_lane_type(i), biome=self.current_biome, difficulty=self.current_difficulty)

    
        self.player.y = 0



    def update_game(self):
        pyxel.mouse(False)
        # Touche pause/unpause
        if pyxel.btnp(self.controls["pause"]) and not self.game_over:
            self.paused = not self.paused
            # reset du fade quand on active l'écran pause
            if self.paused:
                self.pause_fade = 0
            else:
                self.pause_fade = 0

        if self.move_cooldown>0:
            self.move_cooldown -=1
        if self.victory:
            max_victory_fade = 40
            if self.victory_fade < max_victory_fade:
                self.victory_fade += 1
        
            if pyxel.btnp(pyxel.KEY_R):
                self.reset()
                self.victory = False
            if pyxel.btnp(self.controls["menu"]):
                self.menu_state = "main"
                self.victory = False
            return


        if self.game_over:
            # On incrémente la fade pour l'animation Game Over
            max_gameover_fade = 40
            if self.gameover_fade < max_gameover_fade:
                self.gameover_fade += 1
            if pyxel.btnp(pyxel.KEY_R):
                self.reset()
            elif pyxel.btnp(self.controls["menu"]):
                self.menu_state="main"
            return

        # Incrément de la fade pause si l'écran est actif
        if self.paused:
            max_pause_fade = 30
            if self.pause_fade < max_pause_fade:
                self.pause_fade += 1
            # pendant la pause, on n'exécute pas le reste du jeu
            if pyxel.btnp(self.controls["menu"]):
                self.menu_state="main"
            return

        if pyxel.btnp(self.controls["menu"]):
            self.menu_state="main"

        moved = False
        if self.move_cooldown==0:
            if pyxel.btnp(self.controls["left"]) and self.player.x-TILE>=0:
                self.player.x -= TILE
                moved = True
            elif pyxel.btnp(self.controls["right"]) and self.player.x+TILE <= SCREEN_W-TILE:
                self.player.x += TILE
                moved = True
            if pyxel.btnp(self.controls["up"]):
                # son de saut arcade léger
                try:
                    pyxel.play(1,0)
                except Exception:
                    pass
                new_y = self.player.y - TILE
                current_row = new_y//TILE
                if current_row < self.highest_row_reached:
                    self.score += 1
                    self.highest_row_reached = current_row

                    if self.score>self.best:
                        self.best = self.score
                self.player.y = new_y
                moved = True
            elif pyxel.btnp(self.controls["down"]):
                self.player.y += TILE
                moved = True

        if moved:
            self.move_cooldown = 3

        target_camera_y = self.player.y - SCREEN_H//2
        self.camera_y += (target_camera_y - self.camera_y)*0.6
        # --- Mise à jour du biome et de la difficulté en mode progressif ---
        if self.selected_biome == "progressif":
            player_row = self.player.y // TILE
            new_biome = self.current_biome
            new_level = self.level
        
            if self.score >= 0 and self.score < 50:
                new_biome = "forest"
                new_level = "easy"
            elif self.score >= 50 and self.score < 100:
                new_biome = "desert"
                new_level = "easy"
            elif self.score >= 100 and self.score < 150:
                new_biome = "neige"
                new_level = "easy"
            elif self.score >= 150 and self.score < 200:
                new_biome = "city"
                new_level = "easy"
            elif self.score >= 200:
                self.victory = True
                self.victory_fade = 0
                return

        
            # --- Détection de changement de biome ---
            # --- Détection de changement de biome ---
           
            
            if new_biome != self.current_biome or new_level != self.level:
                self.current_biome = new_biome
                self.level = new_level
                
            
                # Son de transition
                try:
                    pyxel.play(2, 4, loop=False)
                except Exception:
                    pass
            
                # Message de transition
                self.biome_transition_timer = 180
                self.biome_transition_text = f"NEW BIOME: {self.current_biome.upper()}"
                
                for row, lane in self.lanes.items():
                    lane.biome = self.current_biome
                    lane.level = self.level
                    lane.update_speed_based_on_difficulty()
                    lane.regenerate_decor() # Assure-toi que cette méthode existe dans Lane
            
                # Regénérer les lanes visibles autour du joueur
                for row in range(player_row - 15, player_row + 5):
                    if row not in self.lanes:
                        self.lanes[row] = Lane(
                            row,
                            self.choose_lane_type(row),
                            biome=self.current_biome,
                            difficulty=self.current_difficulty
                        )
                        self.lanes[row].level = self.current_level  # <-- essentiel pour que les vitesses changent
                        self.lanes[row].update_speed_based_on_difficulty()
                        



        player_row = self.player.y//TILE
        for row in range(player_row-15,player_row+5):
            if row not in self.lanes:
                self.lanes[row] = Lane(row, self.choose_lane_type(row), biome=self.current_biome, difficulty=self.current_difficulty)


        for lane in self.lanes.values():
            lane.update()

        px, py, pw, ph = self.player.rect()
        for lane in self.lanes.values():
            if lane.type != "road":
                continue
            for f in lane.files:
                for car in f["cars"]:
                    cx = int(car[0])
                    cy = lane.y + car[4]
                    cw = car[2]
                    ch = car[3]
                    if (px < cx + cw) and (px + pw > cx) and (py < cy + ch) and (py + ph > cy):
                        if not self.game_over:  # évite de rejouer 50x le son
                            self.game_over = True
                            self.hit_timer = 12
                            try:
                                pyxel.play(3, 2)  # son de collision
                            except Exception:
                                pass
                        self.gameover_fade = 0
                        break

                if self.game_over:
                    break
            if self.game_over:
                break

    def draw_game(self):
        for lane in self.lanes.values():
            lane.draw(self.camera_y)

        px, py, pw, ph = self.player.rect()
        screen_py = self.player.y - self.camera_y + 2

        if self.hit_timer>0:
            self.hit_timer -=1
        if not (self.hit_timer>0 and (pyxel.frame_count//3)%2==0):
            u,v = self.player.skin
            try:
                pyxel.blt(px,screen_py,0,u,v,PLAYER_SIZE[0],PLAYER_SIZE[1],0)
            except Exception:
                pyxel.rect(px, screen_py, PLAYER_SIZE[0], PLAYER_SIZE[1], 8)
        
        # HUD principal (sécurisé)
        pyxel.text(4, 4, f"SCORE: {self.score}", 7)
        pyxel.text(4, 12, f"BEST: {self.best}", 7)
        pyxel.text(4, 28, f"LEVEL: {self.level}", 8)
        #pyxel.text(4, 36, f"LEVEL: {self.selected_difficulty}", 7)
        
        # Biome affiché (fallback si absent)
        biome_to_show = getattr(self, "current_biome", None) or getattr(self, "selected_biome", "UNKNOWN")
        pyxel.text(4, 20, f"BIOME: {biome_to_show.upper()}", 7)
        
        # Level affiché : si mode progressif -> current_difficulty, sinon -> selected_difficulty
        # Détermination du texte du niveau affiché
        #if getattr(self, "selected_biome", "") == "progressif":
            #level_to_show = getattr(self, "current_difficulty", "easy")
        #else:
            #level_to_show = getattr(self, "name", getattr(self, "selected_difficulty", "easy"))
        
        # Affichage du level
        #pyxel.text(4, 28, f"LEVEL: {level_to_show.upper()}", 8)


        #current_level = (
            #self.current_difficulty
            #if hasattr(self, "current_difficulty") and self.selected_biome == "progressif"
            #else self.selected_difficulty
        #)
        #pyxel.text(4, 28, f"LEVEL: {current_level}", 8)


        # --- Transition de biome (texte temporaire) ---
        if self.biome_transition_timer > 0:
            self.biome_transition_timer -= 1
            pyxel.text(SCREEN_W//2 - len(self.biome_transition_text)*2, SCREEN_H//2 - 30, self.biome_transition_text, 10)

        # --- PAUSE (overlay centré + fade-in) ---
        if self.paused:
            box_w, box_h = 120, 40
            box_x = (SCREEN_W - box_w) // 2
            box_y = (SCREEN_H - box_h) // 2
            pyxel.rect(box_x, box_y, box_w, box_h, 0)
            pyxel.rectb(box_x, box_y, box_w, box_h, 7)
            title = "PAUSED"
            subtitle = "P to resume | M Menu"
            max_pause_fade = 30
            t = min(self.pause_fade, max_pause_fade)
            title_color = 7 if t > max_pause_fade * 0.4 else 6
            subtitle_color = 7 if t > max_pause_fade * 0.7 else 6
            if t > 5:
                pyxel.text(SCREEN_W // 2 - len(title) * 2, box_y + 10, title, title_color)
            if t > 12:
                pyxel.text(SCREEN_W // 2 - len(subtitle) * 2, box_y + 24, subtitle, subtitle_color)

        # --- GAME OVER (overlay centré + fade-in) ---
        if self.game_over:
            box_w, box_h = 140, 60
            box_x = (SCREEN_W - box_w) // 2
            box_y = (SCREEN_H - box_h) // 2
            pyxel.rect(box_x, box_y, box_w, box_h, 0)
            pyxel.rectb(box_x, box_y, box_w, box_h, 7)
            title = "GAME OVER"
            subtitle = "R Restart | M Menu"
            max_gameover_fade = 40
            t = min(self.gameover_fade, max_gameover_fade)
            title_color = 8 if t > max_gameover_fade * 0.4 else 7
            subtitle_color = 7 if t > max_gameover_fade * 0.6 else 6
            if t > 5:
                pyxel.text(SCREEN_W // 2 - len(title) * 2, box_y + 18, title, title_color)
            if t > 18:
                pyxel.text(SCREEN_W // 2 - len(subtitle) * 2, box_y + 32, subtitle, subtitle_color)
        # --- VICTORY (overlay centré + fade-in) ---
        if self.victory:
            box_w, box_h = 140, 60
            box_x = (SCREEN_W - box_w) // 2
            box_y = (SCREEN_H - box_h) // 2
            pyxel.rect(box_x, box_y, box_w, box_h, 0)
            pyxel.rectb(box_x, box_y, box_w, box_h, 7)
        
            title = "VICTORY"
            subtitle = "R Restart | M Menu"
        
            max_victory_fade = 40
            t = min(self.victory_fade, max_victory_fade)
        
            title_color = 11 if t > max_victory_fade * 0.4 else 7  # vert Pyxel
            subtitle_color = 7 if t > max_victory_fade * 0.6 else 6
        
            if t > 5:
                pyxel.text(SCREEN_W // 2 - len(title) * 2, box_y + 18, title, title_color)
            if t > 18:
                pyxel.text(SCREEN_W // 2 - len(subtitle) * 2, box_y + 32, subtitle, subtitle_color)
                
                
    def draw_victory(self):
        pyxel.cls(3)
        title = "YOU BEAT PROGRESSIVE MODE!"
        subtitle = "R Restart | M Menu"
        pyxel.text(SCREEN_W // 2 - len(title)*2, SCREEN_H // 2 - 10, title, 10)
        pyxel.text(SCREEN_W // 2 - len(subtitle)*2, SCREEN_H // 2 + 10, subtitle, 7)
        
    



    def update(self):
        pyxel.mouse(True)

        # --- Gestion musique de fond ---
        in_menu = self.menu_state in ["main", "level", "skin", "controls"]
        in_game = self.menu_state == "playing"
    
        if in_menu:
            # joue la musique si elle n'est pas déjà en cours
            if not pyxel.play_pos(0):
                try:
                    pyxel.playm(1, loop=True)
                except Exception:
                    pass
        elif in_game:
            # stop la musique quand on lance la partie
            pyxel.stop(0)

    # --- Le reste de la logique de ton jeu ---
        if self.menu_state == "main":
            self.update_menu_main()
        elif self.menu_state == "level":
            self.update_menu_level()
        elif self.menu_state == "skin":
            self.update_menu_skin()
        elif self.menu_state == "controls":
            self.update_menu_controls()
        elif self.menu_state == "playing":
            self.update_game()
        elif self.menu_state == "victory":
            if pyxel.btnp(pyxel.KEY_R):
                self.reset()
                self.menu_state = "playing"
        elif pyxel.btnp(self.controls["menu"]):
            self.menu_state = "main"





    def draw(self):
        pyxel.cls(BG_COLOR)
        if self.menu_state=="main":
            self.draw_menu_main()
        elif self.menu_state=="level":
            self.draw_menu_level()
        elif self.menu_state=="skin":
            self.draw_menu_skin()
        elif self.menu_state=="controls":
            self.draw_menu_controls()
        elif self.menu_state=="playing":
            self.draw_game()
        elif self.menu_state == "victory":
            self.draw_victory()



if __name__ == "__main__":
    Game()