#!/usr/bin/python3

import random
import os
import json

from engine import maze, sdl2 as engine, controls, graphics, unit_manager, scoring
from engine.collision_system import CollisionSystem
from units import points
from engine.user_profile_integration import UserProfileIntegration


class MiceMaze(
    controls.KeyBindings,
    unit_manager.UnitManager,
    graphics.Graphics,
    scoring.Scoring
):

    # ==================== INITIALIZATION ====================
    
    def __init__(self, maze_file):
        # Initialize user profile integration
        self.profile_integration = UserProfileIntegration()
        
        self.map = maze.Map(maze_file)
        
        # Load profile-specific settings
        self.audio = self.profile_integration.get_setting('sound_enabled', True)
        sound_volume = self.profile_integration.get_setting('sound_volume', 50)
        
        self.cell_size = 40
        self.full_screen = False
        
        # Initialize render engine with profile-aware title
        player_name = self.profile_integration.get_profile_name()
        window_title = f"Mice! - {player_name}"
        
        self.render_engine = engine.GameWindow(self.map.width, self.map.height, 
                                        self.cell_size, window_title, 
                                        key_callback=self.trigger)
        
        # Apply profile settings
        if hasattr(self.render_engine, 'set_volume'):
            self.render_engine.set_volume(sound_volume)
        
        self.load_assets()
        self.render_engine.window.show()
        self.pointer = (random.randint(1, self.map.width-2), random.randint(1, self.map.height-2))
        self.scroll_cursor()
        self.points = 0
        self.units = {}
        
        # Initialize optimized collision system with NumPy
        self.collision_system = CollisionSystem(
            self.cell_size, 
            self.map.width, 
            self.map.height
        )
        
        # Keep old dictionaries for backward compatibility (can be removed later)
        self.unit_positions = {}
        self.unit_positions_before = {}
        
        self.scrolling_direction = None
        self.game_status = "start_menu"
        self.game_end = (False, None)
        self.scrolling = False
        self.sounds = {}
        self.start_game()
        self.background_texture = None
        self.configs = self.get_config()
        self.combined_scores = None

        
    def get_config(self):
        configs = {}
        for file in os.listdir("conf"):
            if file.endswith(".json"):
                with open(os.path.join("conf", file)) as f:
                    configs[file[:-5]] = json.load(f)
        return configs
    
    def start_game(self):
        self.combined_scores = False
        self.ammo = {
            "bomb": {
                "count": 2,
                "max": 8
            },
            "nuclear": {
                "count": 1,
                "max": 1
            },
            "mine": {
                "count": 2,
                "max": 4
            },
            "gas": {
                "count": 2,
                "max": 4
            }
        }
        self.blood_stains = {}
        self.background_texture = None
        
        # Clear blood layer on game start/restart
        self.blood_layer_sprites.clear()
        
        for _ in range(5):
            self.spawn_rat()
            
    def reset_game(self):
            self.pause = False
            self.game_status = "game"
            self.game_end = (False, None)
            self.units.clear()
            self.points = 0
            self.start_game()

    
    # ==================== GAME LOGIC ====================

    def refill_ammo(self):
        for ammo_type, data in self.ammo.items():
            if ammo_type == "bomb":
                if random.random() < 0.02:
                    data["count"] = min(data["count"] + 1, data["max"])
            elif ammo_type == "mine":
                if random.random() < 0.05:
                    data["count"] = min(data["count"] + 1, data["max"])
            elif ammo_type == "gas":
                if random.random() < 0.01:
                    data["count"] = min(data["count"] + 1, data["max"])

    def update_maze(self):
        if self.game_over():
            return
        if self.game_status == "paused":
            self.render_engine.dialog("Pause")
            return
        if self.game_status == "start_menu":
            # Create personalized greeting
            player_name = self.profile_integration.get_profile_name()
            device_id = self.profile_integration.get_device_id()
            
            greeting_title = f"Welcome to Mice, {player_name}!"
            
            # Build subtitle with proper formatting
            subtitle = "A game by Matteo, because he was bored."
            device_line = f"Device: {device_id}"
            
            # Show profile stats if available
            if self.profile_integration.current_profile:
                profile = self.profile_integration.current_profile
                stats_line = f"Best Score: {profile['best_score']} | Games: {profile['games_played']}"
                full_subtitle = f"{subtitle}\n{device_line}\n{stats_line}"
            else:
                full_subtitle = f"{device_line}\nNo profile loaded - playing as guest"
            
            self.render_engine.dialog(greeting_title, 
                                    subtitle=full_subtitle,
                                    image=self.assets["BMP_WEWIN"])
            return
        self.render_engine.delete_tag("unit")
        self.render_engine.delete_tag("effect")
        self.render_engine.draw_pointer(self.pointer[0] * self.cell_size, self.pointer[1] * self.cell_size)
        
        # Clear collision system for new frame
        self.collision_system.clear()
        self.unit_positions.clear()
        self.unit_positions_before.clear()
        
        # First pass: Register all units in collision system BEFORE move
        # This allows bombs/gas to find victims during their move()
        for unit in self.units.values():
            # Calculate bbox if not yet set (first frame)
            if not hasattr(unit, 'bbox') or unit.bbox == (0, 0, 0, 0):
                # Temporary bbox based on position
                x_pos = unit.position[0] * self.cell_size
                y_pos = unit.position[1] * self.cell_size
                unit.bbox = (x_pos, y_pos, x_pos + self.cell_size, y_pos + self.cell_size)
            
            # Register unit in optimized collision system
            self.collision_system.register_unit(
                unit.id,
                unit.bbox,
                unit.position,
                unit.position_before,
                unit.collision_layer
            )
            
            # Maintain backward compatibility dictionaries
            self.unit_positions.setdefault(unit.position, []).append(unit)
            self.unit_positions_before.setdefault(unit.position_before, []).append(unit)
        
        # Second pass: move all units (can now access collision system)
        for unit in self.units.copy().values():
            unit.move()
        
        # Third pass: Update collision system with new positions after move
        self.collision_system.clear()
        self.unit_positions.clear()
        self.unit_positions_before.clear()
        
        for unit in self.units.values():
            # Register with updated positions/bbox from move()
            self.collision_system.register_unit(
                unit.id,
                unit.bbox,
                unit.position,
                unit.position_before,
                unit.collision_layer
            )
            
            self.unit_positions.setdefault(unit.position, []).append(unit)
            self.unit_positions_before.setdefault(unit.position_before, []).append(unit)
        
        # Fourth pass: check collisions and draw
        for unit in self.units.copy().values():
            unit.collisions()
            unit.draw()
        
        self.render_engine.update_status(f"Mice: {self.count_rats()} - Points: {self.points}")
        self.refill_ammo()
        self.render_engine.update_ammo(self.ammo, self.assets)
        self.scroll()
        self.render_engine.new_cycle(50, self.update_maze)

    def run(self):
        self.render_engine.mainloop(update=self.update_maze, bg_update=self.draw_maze)
 
    # ==================== GAME OVER LOGIC ====================
    
    def game_over(self):
        if self.game_end[0]:
            if not self.combined_scores:
                self.combined_scores = self.profile_integration.get_global_leaderboard(4)
            global_scores = []

            for entry in self.combined_scores:
                # Convert to format expected by dialog: [date, score, name, device]
                global_scores.append([
                    entry.get('last_play', ''),
                    entry.get('best_score', 0),
                    entry.get('user_id', 'Unknown'),
                    
                ])
                
            if not self.game_end[1]:
                self.render_engine.dialog(
                    "Game Over: Mice are too many!", 
                    image=self.assets["BMP_WEWIN"],
                    scores=global_scores
                )
            else:
                self.render_engine.dialog(
                    f"You Win! Points: {self.points}", 
                    image=self.assets["BMP_WEWIN"], 
                    scores=global_scores
                )

                
            return True
        count_rats = self.count_rats()
        if count_rats > 200:
            self.render_engine.stop_sound()
            self.render_engine.play_sound("WEWIN.WAV")
            self.game_end = (True, False)
            self.game_status = "paused"
            
            # Track incomplete game in profile
            self.profile_integration.update_game_stats(self.points, completed=False)
            
            return True
        if not count_rats and not any(isinstance(unit, points.Point) for unit in self.units.values()):
            self.render_engine.stop_sound()
            self.render_engine.play_sound("VICTORY.WAV")
            self.render_engine.play_sound("WELLDONE.WAV", tag="effects")
            self.game_end = (True, True)
            self.game_status = "paused"
            
            # Save score to both traditional file and user profile
            self.save_score()
            self.profile_integration.update_game_stats(self.points, completed=True)
            
            return True




        
if __name__ == "__main__":
    print("Game starting...")
    solver = MiceMaze('maze.json')
    solver.run()

