import pyxel

# Classe pour définir des boutons interactifs avec une zone et une action associée
class Button:
    def __init__(self, x1, x2, y1, y2, action=None):
        # Définit une zone de détection pour le bouton
        self.zone = Detec_zone(x1, x2, y1, y2)
        # Action à exécuter lors d'un clic sur le bouton
        self.action = action

    # Vérifie si un clic a eu lieu dans la zone et exécute l'action
    def check_click(self, mouse_x, mouse_y):
        if self.zone.detection(mouse_x, mouse_y):
            if self.action:
                self.action()

# Classe principale de l'application
class App:
    def __init__(self):
        # Initialisation de la fenêtre Pyxel
        pyxel.init(160, 128, title="Viking shenanigans", fps=60)
        pyxel.load("res.pyxres")

        # Initialisation des états du jeu
        self.menu_state = True  # Indique si on est dans le menu
        self.settings = False  # Indique si le menu des paramètres est ouvert
        self.inv = False  # Indique si l'inventaire est ouvert
        self.Health = 8  # Points de vie du joueur
        self.potion = 4  # Nombre de potions disponibles

        # Liste des boutons et des actions associées

        self.buttons = [
            Button(75, 85, 60, 67, self.start_game),
            Button(128, 140, 3, 13, self.toggle_settings),
            Button(73, 87, 55, 67, self.return_to_menu),
            Button(128, 143, 110, 124, self.toggle_inventory),
        ]



        # Chargement du niveau initial
        self.change_lvl("house", 72, 64)
        # Zone de collision du personnage
        self.coll = Detec_zone(self.charX, self.charX + 16, self.charY, self.charY + 16)
        self.rebond = 0  # Gestion des animations de saut
        self.movement = False  # Indique si le personnage est en mouvement
        self.lastInput = 0  # Compteur depuis la dernière action
        self.charOrientation = 0  # Orientation du personnage
        self.charImages = [0, 16, 32, 48]  # Index des images du personnage
        # Lancement de la boucle principale
        pyxel.run(self.update, self.draw)

    # Action pour démarrer le jeu
    def start_game(self):
        self.menu_state = False

    # Action pour ouvrir/fermer le menu des paramètres
    def toggle_settings(self):
        self.settings = not self.settings

    # Action pour retourner au menu principal
    def return_to_menu(self):
        if self.settings:
            self.settings = False
            self.menu_state = True

    # Action pour ouvrir/fermer l'inventaire
    def toggle_inventory(self):
        self.inv = not self.inv

    # Mise à jour des éléments du jeu
    def update(self):
        # Récupère la position actuelle de la souris
        self.mouse_posX = pyxel.mouse_x
        self.mouse_posY = pyxel.mouse_y
        
        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
            print(self.mouse_posX, self.mouse_posY)

        # Vérifie si un clic a eu lieu sur un bouton
        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
            for button in self.buttons:
                button.check_click(self.mouse_posX, self.mouse_posY)

        # Gère les collisions et les transitions entre niveaux
        if not self.menu_state:
            for sortie in self.niveau.sorties:
                if self.coll.chevauche(sortie["zone"]):
                    self.change_lvl(
                        sortie["destination"], sortie["destinationX"], sortie["destinationY"]
                    )

        # Met à jour la position du personnage et vérifie les collisions
        self.character_movement()
        self.coll.maj(self.charX, self.charX + 16, self.charY, self.charY + 16)

    # Change le niveau actuel
    def change_lvl(self, niveau, x, y):
        self.niveau = Niveau(niveau)
        self.charX = x
        self.charY = y

    # Gestion des mouvements du personnage
    def character_movement(self):
        if not self.menu_state:
            self.lastInput += 1
            self.movement = False

            # Dictionnaire associant les touches aux déplacements
            movement_dict = {
                pyxel.KEY_RIGHT: (0.5, 2),
                pyxel.KEY_LEFT: (-0.5, 3),
                pyxel.KEY_DOWN: (0.5, 0),
                pyxel.KEY_UP: (-0.5, 1)
            }

            # Mise à jour de la position et de l'orientation selon les touches pressées
            for key, (dx, orientation) in movement_dict.items():
                if pyxel.btn(key):
                    self.charX += dx if key in [pyxel.KEY_RIGHT, pyxel.KEY_LEFT] else 0
                    self.charY += dx if key in [pyxel.KEY_DOWN, pyxel.KEY_UP] else 0
                    self.charOrientation = orientation
                    self.movement = True
                    self.lastInput = 0

            # Empêche le personnage de sortir des limites de l'écran
            self.charX = min(max(self.charX, 16), 128)
            self.charY = min(max(self.charY, 0), 112)

    # Dessine les éléments du jeu
    def draw(self):
        pyxel.cls(0)
        if self.menu_state:
            self.menu()
        else:
            self.drawMap()
            self.sprite()
            self.drawMapTop()
            self.gui()

    # Affiche le menu principal
    def menu(self):
        # Dessin du menu
        pyxel.cls(0)
        if self.menu_state == True:
            pyxel.bltm(16,0,0,0,128,128,128)
            pyxel.bltm(0, 0, 1, 0, 0, 16, 128)
            pyxel.bltm(144, 0, 1, 0, 0, 16, 128)
        pyxel.blt(75,60,0,3,164,16,15,0) #bouton play
        pyxel.text(45, 5, "Viking Shenanigans", 7)
        pyxel.text(30, 120, "made by: Adrien et Mathis", 7)
        pyxel.blt(self.mouse_posX, self.mouse_posY, 0, 17, 161, 10, 10, 0)

    # Dessine la carte principale
    def drawMap(self):
        if not self.menu_state:
            pyxel.bltm(16, 0, self.niveau.tilemap, self.niveau.tilemapX, self.niveau.tilemapY, 128, 128, 0)

    # Dessine le personnage
    def sprite(self):
        # Dessin du sprite avec gestion des animations de rebond
        if not self.movement and self.lastInput >= 6:
            self.rebond = 0

        if self.rebond <= 6:
            pyxel.blt(self.charX, self.charY, 0, self.charImages[self.charOrientation], 80, 16, 16, 0)
        else:
            pyxel.blt(self.charX, self.charY - 2, 0, self.charImages[self.charOrientation], 80, 16, 16, 0)

        self.rebond = (self.rebond + 1) % 17

    # Dessine les éléments au-dessus de la carte
    def drawMapTop(self):
        if not self.menu_state and self.niveau.tilemapTop != None :
            pyxel.bltm(16, 0, self.niveau.tilemapTop, self.niveau.tilemapTopX, self.niveau.tilemapTopY, 128, 128, 0)
            
            
    def gui(self):
        pyxel.bltm(0, 0, 1, 0, 0, 16, 128)  # Bordure 1
        pyxel.bltm(144, 0, 1, 0, 0, 16, 128)
        pyxel.blt(30, 5, 0, 0, 69, 16, 8, 0)  # barre de vie
        pyxel.blt(48, 110, 0, 0, 128, 16, 16)  # inventaire case 1
        pyxel.blt(64, 110, 0, 0, 128, 16, 16)  # inventaire case 2
        pyxel.blt(80, 110, 0, 0, 128, 16, 16)  # inventaire case 3
        pyxel.blt(96, 110, 0, 0, 128, 16, 16)  # inventaire case 4
        pyxel.blt(48, 111, 0, 0, 32, 16, 16, 0)  # potion
        pyxel.blt(65, 111, 0, 0, 0, 16, 14, 0)  # épée
        pyxel.blt(80, 110, 0, 0, 16, 16, 16, 0)  # bouclier
        pyxel.blt(96, 111, 0, 0, 48, 16, 16, 0)  # boule de feu
        pyxel.blt(15, 0, 0, 64, 80, 16, 16, 0)  # tête joueur

        if self.inv:
            pyxel.blt(128, 110, 0, 16, 144, 16, 16, 0)  # open backpack
        else:
            pyxel.blt(128, 110, 0, 0, 144, 16, 16, 0)  # backpack

        pyxel.blt(128, 0, 0, 0, 176, 16, 16, 0)  # settings

        if self.settings:
            pyxel.blt(64, 30, 0, 0, 192, 32, 48, 0)  # settings_window
            pyxel.text(72, 35, "Menu", 13)

        if self.inv:
            pyxel.blt(56, 30, 0, 40, 192, 64, 48, 0)  # inventory window
            pyxel.text(63, 32, "Inventory", 13)

        pyxel.blt(self.mouse_posX, self.mouse_posY, 0, 17, 161, 10, 10, 0)

class Niveau:
    def __init__(self, lvl_id):
        niv = niveaux[lvl_id]
        self.tilemap = niv["tilemap"]
        self.tilemapX = niv["x"]
        self.tilemapY = niv["y"]

        if niv["top"]:
            top = niveaux[niv["top"]]
            self.tilemapTop = top["tilemap"]
            self.tilemapTopX = top["x"]
            self.tilemapTopY = top["y"]
        else:
            self.tilemapTop = None
            self.tilemapTopX = None
            self.tilemapTopY = None

        self.sorties = niv["sorties"]

class Detec_zone:
    def __init__(self, x1, x2, y1, y2):
        self.maj(x1, x2, y1, y2)

    def maj(self, x1, x2, y1, y2):
        self.x1 = x1
        self.x2 = x2
        self.y1 = y1
        self.y2 = y2

    def detection(self, dx, dy):
        return self.x1 <= dx <= self.x2 and self.y1 <= dy <= self.y2

    def chevauche(self, zone):
        return not (self.x2 < zone.x1 or zone.x2 < self.x1 or self.y2 < zone.y1 or zone.y2 < self.y1)

    def affiche(self):
        print(f"X1: {self.x1} Y1: {self.y1}, X2: {self.x2} Y2: {self.y2}")

niveaux = {
    "house": {
        "tilemap": 0,
        "x": 0,
        "y": 0,
        "top": "house_top",
        "sorties": [
            {
                "zone": Detec_zone(64, 80, 120, 128),
                "destination": "hub",
                "destinationX": 72,
                "destinationY": 16
            }
        ]
    },
    "house_top": {
        "tilemap": 0,
        "x": 128,
        "y": 0,
        "top": None
    },
    "hub": {
        "tilemap": 0,
        "x": 256,
        "y": 0,
        "top": None,
        "sorties": [
            {
                "zone": Detec_zone(64, 80, 0, 8),
                "destination": "house",
                "destinationX": 72,
                "destinationY": 96
            },
            {
                "zone": Detec_zone(16, 22, 56, 71),
                "destination": "path",
                "destinationX": 120,
                "destinationY": 56
            },
            {
                "zone": Detec_zone(140, 143, 56, 71),
                "destination": "path2",
                "destinationX": 20,
                "destinationY": 64
            }
        ]
    },
    "path": {
        "tilemap": 0,
        "x": 128,
        "y": 128,
        "top": None,
        "sorties": [
            {
                "zone": Detec_zone(140, 143, 56, 71),
                "destination": "hub",
                "destinationX": 24,
                "destinationY": 56
            },
            {
                "zone": Detec_zone(16, 22, 56, 71),
                "destination": "Shop",
                "destinationX": 120,
                "destinationY": 56
            }
        ]
    },
    "path2": {
        "tilemap": 0,
        "x": 0,
        "y": 256,
        "top": None,
        "sorties": [
            {
                "zone": Detec_zone(16, 18, 56, 71),
                "destination": "hub",
                "destinationX": 120,
                "destinationY": 56
            },
            {
                "zone": Detec_zone(141, 143, 48, 63),
                "destination": "MountainPass",
                "destinationX": 27,
                "destinationY": 56
            }
        ]
    },
    "Shop": {
        "tilemap": 0,
        "x": 256,
        "y": 128,
        "top": None,
        "sorties": [
            {
                "zone": Detec_zone(140, 143, 56, 71),
                "destination": "path",
                "destinationX": 28,
                "destinationY": 56
            }
        ]
    },
    "MountainPass": {
        "tilemap": 0,
        "x": 128,
        "y": 256,
        "top": None,
        "sorties": [
            {
                "zone": Detec_zone(16, 18, 48, 63),
                "destination": "path2",
                "destinationX": 125,
                "destinationY": 48
            }
        ]
    },
}


App()