# This is the main Delivery Drone game file.
# It sets up the game window, handles the game loop, and manages game states.
# The game will run off of Pyxel and use speech recognition for voice commands.
import pyxel
#import speech_recognition as sr    [not compatible with Pyxel files, specifically on html]
from screens import MainGame
from screens import MainMenu
from screens import PauseMenu
from screens import GameOver
from drone import Drone
from obstacles import Bird
from obstacles import Building
from obstacles import Plane
from drone import Package

class DeliveryDrone:
    """Main class for the Delivery Drone game."""
    def __init__(self):
        """Initializes the main attributes of the game."""
        pyxel.init(160, 144, title="Delivery Drone", display_scale=6)
        self.x = 0
        self.mg = MainGame(self)
        self.mm = MainMenu(self)
        self.pause = PauseMenu(self)
        self.go = GameOver(self)
        self.d = Drone()
        self.bdg = Building()
        self.bd = Bird()
        self.p = Plane()
        self.pkg = Package(self.d)
        self.score = self.mg.score
        self.high_score = 0
        self.collision_timer = 0              # Frames remaining of invulnerability
        self.collision_duration_frames = 120   # How long to be invulnerable
        #self.r = sr.Recognizer()
        #self.mic = sr.Microphone()
        #self._handle_voice_commands()
        self.running = False
        #self.enable_voice_commands = False
        self.paused = False
        self.gameover = False
        #self.voice_command = None
        
        pyxel.run(self.update, self.draw)
        

    def update(self):
        """Updates the game state."""
        self.handle_input()
        
        if self.running and not self.paused:
            if self.collision_timer > 0:
                self.collision_timer -= 1  # Decrease invulnerability timer
            self.collision_events()
            self.bdg.update()
            self.bd.update()
            self.d.update()
            self.pkg.update()
            self.p.update()
            # if self.voice_command:
            #     command = self.voice_command
            #     if command == 'red':
            #         self.pkg.current_package = self.pkg.package_list[0]
            #         self.pkg.drop_package()
            #     elif command == 'green':
            #         self.pkg.current_package = self.pkg.package_list[2]
            #         self.pkg.drop_package()
            #     elif command == 'blue':
            #         self.pkg.current_package = self.pkg.package_list[1]
            #         self.pkg.drop_package()
            #     elif command == 'drop':
            #         self.pkg.drop_package()

            #     self.voice_command = None

    def handle_input(self):
        """Handles keyboard."""
        if pyxel.btnp(pyxel.KEY_Q):
            pyxel.quit()
        elif pyxel.btnp(pyxel.KEY_P):
            self.paused = not self.paused
            return
        elif pyxel.btnp(pyxel.KEY_R):
            # Restart the game when game over
            if self.gameover:
                self.reset_game()
            return
        if not self.running and not self.paused:
            if pyxel.btnp(pyxel.KEY_RETURN):
                self.running = True
                pyxel.playm(0, loop=True)
        # if not self.running or self.paused:
        #     if pyxel.btnp(pyxel.KEY_V):
        #         if not self.enable_voice_commands:
        #             self.enable_voice_commands = True
        #         else:
        #             self.enable_voice_commands = False
        elif self.running:
            if pyxel.btn(pyxel.KEY_W) or pyxel.btn(pyxel.KEY_UP):
                if self.d.y > 6:
                    self.d.y -= 2
            elif pyxel.btn(pyxel.KEY_S) or pyxel.btn(pyxel.KEY_DOWN):
                if self.d.y < 126:
                    self.d.y += 2
            elif pyxel.btn(pyxel.KEY_A) or pyxel.btn(pyxel.KEY_LEFT):
                if self.d.x > -13:
                    self.d.x -= 2
            elif pyxel.btn(pyxel.KEY_D) or pyxel.btn(pyxel.KEY_RIGHT):
                if self.d.x < 123:
                    self.d.x += 2
            elif pyxel.btnp(pyxel.KEY_TAB):
                if self.pkg.package_dropped == False:
                    self.pkg.current_package = self.pkg.package_list[(self.pkg.package_list.index(self.pkg.current_package) + 1) % len(self.pkg.package_list)]
                else:
                    pass    
            elif pyxel.btn(pyxel.KEY_SPACE):
                self.pkg.drop_package()

    # def _callback(self, r, audio):
    #     try:
    #         text = self.r.recognize_google(audio).lower()
    #         self.voice_command = text
    #         print(text)
    #     except sr.UnknownValueError:
    #         pass
    #     except sr.RequestError as e:
    #         print(e)

    # def _handle_voice_commands(self):
    #     """Handles speech recognition for package drops."""
    #     # Set microphone as source to listen for input
    #     with self.mic as source:
    #         # Designate variable to catch audio
    #         self.r.adjust_for_ambient_noise(source, duration=0.2)
    #     stop_listening = self.r.listen_in_background(self.mic, self._callback)
    #     self.stop_voice_listener = stop_listening

    def check_collision(self, obj1, obj2):
        """Checks for collision between two rectangular objects."""
        # Helper to extract rectangle bounds from object or dict
        def rect(o):
            if isinstance(o, dict):
                return o.get('x', 0), o.get('y', 0), o.get('w', 0), o.get('h', 0)
            # For classes with x,y,w,h attributes
            return getattr(o, 'x', 0), getattr(o, 'y', 0), getattr(o, 'w', 0), getattr(o, 'h', 0)

        obj1x, obj1y, obj1w, obj1h = rect(obj1)
        obj2x, obj2y, obj2w, obj2h = rect(obj2)

        # Checks if two rectangles overlap
        return (obj1x < obj2x + obj2w and
                obj1x + obj1w > obj2x and
                obj1y < obj2y + obj2h and
                obj1y + obj1h > obj2y)
    
    def collision_events(self):
        """Handles collision events."""
        # Delay collision checks if recently collided
        if self.collision_timer == 0:
            # Drone vs bird or plane collisionst
            bird_rect = {
                'x': getattr(self.bd, 'x', 0),
                'y': getattr(self.bd, 'y', 0),
                'w': self.bd.current_bird.get('w', 0 - 5),
                'h': self.bd.current_bird.get('h', 0 - 5)
            }
            # Check collision with plane and birds
            if self.check_collision(self.d, bird_rect) or self.check_collision(self.d, self.p):
                if self.mg.lives:
                    self.mg.lives.pop()  # Lose a life on collision
                self.collision_timer = self.collision_duration_frames  # Start invulnerability timer
                # Reset drone position
                self.d.x = 0
                self.d.y = 60

            # Drone vs buildings
            for random_building in self.bdg.current_buildings:
                # Building is a dict with x,y,w,h, 'color', and 'level'
                if self.check_collision(self.d, random_building):
                    if self.mg.lives:
                        self.mg.lives.pop()
                    self.collision_timer = self.collision_duration_frames  # Start invulnerability timer
                    # Reset drone position
                    self.d.x = 0
                    self.d.y = 60
                    break

        # Package vs buildings (scoring)
        if self.pkg.package_dropped:
            dropped_package_hitbox = {
                'x': self.pkg.x,
                'y': self.pkg.y,
                'w': self.pkg.current_package.get('w', 0),
                'h': self.pkg.current_package.get('h', 0)
            }

            delivered = False
            for building in self.bdg.current_buildings:
                if self.check_collision(dropped_package_hitbox, building):
                    # Reset package regardless of success
                    self.pkg.reset_package()
                    delivered = True
                    pkg_color = self.pkg.current_package.get('color')
                    b_color = building.get('color')
                    # Score mapping by building level
                    level_score = {'high': 5, 'mid': 10, 'low': 15}
                    score_delta = level_score.get(building.get('level'), 0)
                    if pkg_color == b_color:
                        self.mg.score += score_delta
                    else:
                        # Penalize for wrong roof color
                        self.mg.score -= score_delta
                    break

            # If package fell off screen without delivery
            if not delivered and self.pkg.y > 144:
                self.mg.score -= 5
                self.pkg.reset_package()
                if self.mg.lives:
                    self.mg.lives.pop()

        if self.mg.lives == []:
                pyxel.stop(0)
                pyxel.stop(1)
                self.gameover = True

    def reset_game(self):
        """Resets the game after gameover."""
        # Recreate main game screen and reset score/lives/timer
        self.mg = MainGame(self)
        # Recreate player and obstacles to clear state
        self.d = Drone()
        self.bdg = Building()
        self.bd = Bird()
        self.p = Plane()
        self.pkg = Package(self.d)

        # Reset flags and timers
        self.collision_timer = 0
        self.running = False
        self.paused = False
        self.gameover = False
        # self.enable_voice_commands = False

        # Ensure score is reset on the main game screen
        self.mg.score = 0
        self.score = self.mg.score

    def draw(self):
        """Draws the game elements."""
        if not self.running:
            self.mm.draw()
        elif self.running and not self.gameover:    
            if not self.paused:    
                self.mg.draw()
                self.d.draw()
                self.pkg.draw()
                self.bdg.draw()
                self.bd.draw()
                self.p.draw()
            elif self.paused:
                self.pause.draw()
        elif self.gameover:
            self.go.draw()

DeliveryDrone()