"""
房间管理器模块
负责管理多个游戏房间或场景实例
"""

import time
import threading
import uuid
from typing import Dict, Any, List, Optional

class RoomManager:
    """
    房间管理器
    负责管理多个游戏房间或场景实例
    """
    
    def __init__(self, plugin):
        """
        初始化房间管理器
        
        Args:
            plugin: 服务器架构插件实例
        """
        self.plugin = plugin
        self.enabled = False
        self.initialized = False
        
        # 房间配置
        self.room_config = {
            "max_rooms": 100,
            "max_clients_per_room": 50,
            "enable_room_persistence": False,
            "room_timeout": 3600,  # 1小时无活动房间自动关闭
            "enable_room_passwords": True,
            "enable_room_visibility": True,
            "default_room_settings": {
                "max_clients": 10,
                "is_public": True,
                "allow_spectators": True,
                "enable_voice_chat": True
            }
        }
        
        # 房间存储
        self.rooms = {}  # 房间字典
        self.client_rooms = {}  # 客户端所在房间映射
        
        # 房间统计
        self.room_stats = {
            "total_rooms": 0,
            "active_rooms": 0,
            "clients_in_rooms": 0,
            "rooms_created": 0,
            "rooms_destroyed": 0,
            "clients_joined": 0,
            "clients_left": 0,
            "errors": 0
        }
        
        # 线程锁
        self.rooms_lock = threading.RLock()
        
        # 回调函数
        self.room_callbacks = {
            "room_created": [],
            "room_destroyed": [],
            "client_joined": [],
            "client_left": [],
            "room_updated": []
        }
        
        # 时间戳记录
        self.last_cleanup = 0.0
        self.last_room_check = 0.0
        
        print("✓ 房间管理器已创建")
        
    def initialize(self) -> bool:
        """
        初始化房间管理器
        
        Returns:
            是否初始化成功
        """
        try:
            print("正在初始化房间管理器...")
            
            self.initialized = True
            print("✓ 房间管理器初始化完成")
            return True
            
        except Exception as e:
            print(f"✗ 房间管理器初始化失败: {e}")
            self.room_stats["errors"] += 1
            import traceback
            traceback.print_exc()
            return False
            
    def enable(self) -> bool:
        """
        启用房间管理器
        
        Returns:
            是否启用成功
        """
        try:
            if not self.initialized:
                print("✗ 房间管理器未初始化")
                return False
                
            self.enabled = True
            print("✓ 房间管理器已启用")
            return True
            
        except Exception as e:
            print(f"✗ 房间管理器启用失败: {e}")
            self.room_stats["errors"] += 1
            import traceback
            traceback.print_exc()
            return False
            
    def disable(self):
        """禁用房间管理器"""
        try:
            self.enabled = False
            
            # 关闭所有房间
            self.destroy_all_rooms()
            
            print("✓ 房间管理器已禁用")
            
        except Exception as e:
            print(f"✗ 房间管理器禁用失败: {e}")
            self.room_stats["errors"] += 1
            import traceback
            traceback.print_exc()
            
    def finalize(self):
        """清理房间管理器资源"""
        try:
            # 禁用管理器
            if self.enabled:
                self.disable()
                
            # 清理回调
            self.room_callbacks.clear()
            
            self.initialized = False
            print("✓ 房间管理器资源已清理")
            
        except Exception as e:
            print(f"✗ 房间管理器资源清理失败: {e}")
            import traceback
            traceback.print_exc()
            
    def update(self, dt: float):
        """
        更新房间管理器状态
        
        Args:
            dt: 时间增量（秒）
        """
        try:
            if not self.enabled:
                return
                
            current_time = time.time()
            
            # 定期清理过期房间
            if current_time - self.last_cleanup > 60.0:  # 每分钟清理一次
                self._cleanup_expired_rooms(current_time)
                self.last_cleanup = current_time
                
        except Exception as e:
            print(f"✗ 房间管理器更新失败: {e}")
            self.room_stats["errors"] += 1
            import traceback
            traceback.print_exc()
            
    def _cleanup_expired_rooms(self, current_time: float):
        """清理过期房间"""
        try:
            expired_rooms = []
            with self.rooms_lock:
                for room_id, room_data in self.rooms.items():
                    # 检查房间是否超时
                    if current_time - room_data["last_activity"] > self.room_config["room_timeout"]:
                        # 检查房间是否为空
                        if len(room_data["clients"]) == 0:
                            expired_rooms.append(room_id)
                            
            # 销毁过期房间
            for room_id in expired_rooms:
                self.destroy_room(room_id)
                
        except Exception as e:
            print(f"✗ 过期房间清理失败: {e}")
            self.room_stats["errors"] += 1
            
    def create_room(self, room_name: str = None, room_settings: Dict[str, Any] = None, 
                   room_password: str = None) -> Optional[str]:
        """
        创建房间
        
        Args:
            room_name: 房间名称
            room_settings: 房间设置
            room_password: 房间密码
            
        Returns:
            房间ID或None
        """
        try:
            if not self.enabled:
                return None
                
            # 检查房间数量限制
            with self.rooms_lock:
                if len(self.rooms) >= self.room_config["max_rooms"]:
                    print("✗ 房间数量已达上限")
                    return None
                    
            # 生成房间ID
            room_id = str(uuid.uuid4())
            
            # 使用默认设置或传入设置
            settings = self.room_config["default_room_settings"].copy()
            if room_settings:
                settings.update(room_settings)
                
            # 创建房间数据
            room_data = {
                "room_id": room_id,
                "room_name": room_name or f"房间-{room_id[:8]}",
                "settings": settings,
                "password": room_password,
                "clients": {},  # 客户端ID到客户端数据的映射
                "host_client_id": None,
                "created_time": time.time(),
                "last_activity": time.time(),
                "room_state": {},  # 房间状态数据
                "custom_data": {}  # 自定义房间数据
            }
            
            # 添加到房间列表
            with self.rooms_lock:
                self.rooms[room_id] = room_data
                
            self.room_stats["total_rooms"] += 1
            self.room_stats["active_rooms"] += 1
            self.room_stats["rooms_created"] += 1
            
            # 触发房间创建回调
            self._trigger_room_callback("room_created", {
                "room_id": room_id,
                "room_name": room_data["room_name"],
                "settings": settings,
                "timestamp": room_data["created_time"]
            })
            
            print(f"✓ 房间已创建: {room_id} ({room_data['room_name']})")
            return room_id
            
        except Exception as e:
            print(f"✗ 房间创建失败: {e}")
            self.room_stats["errors"] += 1
            return None
            
    def destroy_room(self, room_id: str) -> bool:
        """
        销毁房间
        
        Args:
            room_id: 房间ID
            
        Returns:
            是否销毁成功
        """
        try:
            if not self.enabled:
                return False
                
            # 检查房间是否存在
            with self.rooms_lock:
                if room_id not in self.rooms:
                    print(f"✗ 房间不存在: {room_id}")
                    return False
                    
                room_data = self.rooms[room_id]
                
                # 通知房间内所有客户端
                for client_id in list(room_data["clients"].keys()):
                    self._notify_client_room_destroyed(client_id, room_id)
                    
                # 移除房间
                del self.rooms[room_id]
                
            self.room_stats["active_rooms"] -= 1
            self.room_stats["rooms_destroyed"] += 1
            
            # 触发房间销毁回调
            self._trigger_room_callback("room_destroyed", {
                "room_id": room_id,
                "room_name": room_data["room_name"],
                "timestamp": time.time()
            })
            
            print(f"✓ 房间已销毁: {room_id}")
            return True
            
        except Exception as e:
            print(f"✗ 房间销毁失败: {e}")
            self.room_stats["errors"] += 1
            return False
            
    def destroy_all_rooms(self):
        """销毁所有房间"""
        try:
            with self.rooms_lock:
                room_ids = list(self.rooms.keys())
                
            for room_id in room_ids:
                self.destroy_room(room_id)
                
        except Exception as e:
            print(f"✗ 销毁所有房间失败: {e}")
            self.room_stats["errors"] += 1
            
    def add_client_to_room(self, room_id: str, client_id: str, client_data: Dict[str, Any] = None) -> bool:
        """
        添加客户端到房间
        
        Args:
            room_id: 房间ID
            client_id: 客户端ID
            client_data: 客户端数据
            
        Returns:
            是否添加成功
        """
        try:
            if not self.enabled:
                return False
                
            # 检查客户端是否已认证
            if not self.plugin.client_manager.is_client_authenticated(client_id):
                print(f"✗ 客户端未认证: {client_id}")
                return False
                
            # 检查房间是否存在
            with self.rooms_lock:
                if room_id not in self.rooms:
                    print(f"✗ 房间不存在: {room_id}")
                    return False
                    
                room_data = self.rooms[room_id]
                
                # 检查房间是否已满
                if len(room_data["clients"]) >= room_data["settings"]["max_clients"]:
                    print(f"✗ 房间已满: {room_id}")
                    return False
                    
                # 检查房间密码
                if room_data["password"] and not self._verify_room_password(room_id, client_data):
                    print(f"✗ 房间密码错误: {room_id}")
                    return False
                    
                # 添加客户端到房间
                client_info = client_data or {}
                client_info["join_time"] = time.time()
                client_info["last_activity"] = time.time()
                
                room_data["clients"][client_id] = client_info
                room_data["last_activity"] = time.time()
                
                # 设置房间主机（如果是第一个客户端）
                if room_data["host_client_id"] is None:
                    room_data["host_client_id"] = client_id
                    
                # 更新客户端房间映射
                self.client_rooms[client_id] = room_id
                
            self.room_stats["clients_in_rooms"] += 1
            self.room_stats["clients_joined"] += 1
            
            # 触发客户端加入回调
            self._trigger_room_callback("client_joined", {
                "room_id": room_id,
                "room_name": room_data["room_name"],
                "client_id": client_id,
                "timestamp": time.time()
            })
            
            print(f"✓ 客户端已加入房间: {client_id} -> {room_id}")
            return True
            
        except Exception as e:
            print(f"✗ 添加客户端到房间失败: {e}")
            self.room_stats["errors"] += 1
            return False
            
    def remove_client_from_room(self, room_id: str, client_id: str) -> bool:
        """
        从房间移除客户端
        
        Args:
            room_id: 房间ID
            client_id: 客户端ID
            
        Returns:
            是否移除成功
        """
        try:
            if not self.enabled:
                return False
                
            # 检查房间是否存在
            with self.rooms_lock:
                if room_id not in self.rooms:
                    print(f"✗ 房间不存在: {room_id}")
                    return False
                    
                room_data = self.rooms[room_id]
                
                # 检查客户端是否在房间中
                if client_id not in room_data["clients"]:
                    print(f"✗ 客户端不在房间中: {client_id}")
                    return False
                    
                # 移除客户端
                del room_data["clients"][client_id]
                room_data["last_activity"] = time.time()
                
                # 更新主机（如果移除的是主机）
                if room_data["host_client_id"] == client_id:
                    if room_data["clients"]:
                        # 选择第一个客户端作为新主机
                        room_data["host_client_id"] = next(iter(room_data["clients"]))
                    else:
                        room_data["host_client_id"] = None
                        
                # 移除客户端房间映射
                if client_id in self.client_rooms:
                    del self.client_rooms[client_id]
                    
            self.room_stats["clients_in_rooms"] -= 1
            self.room_stats["clients_left"] += 1
            
            # 触发客户端离开回调
            self._trigger_room_callback("client_left", {
                "room_id": room_id,
                "room_name": room_data["room_name"],
                "client_id": client_id,
                "timestamp": time.time()
            })
            
            # 如果房间为空，销毁房间
            if len(room_data["clients"]) == 0:
                self.destroy_room(room_id)
                
            print(f"✓ 客户端已离开房间: {client_id} <- {room_id}")
            return True
            
        except Exception as e:
            print(f"✗ 从房间移除客户端失败: {e}")
            self.room_stats["errors"] += 1
            return False
            
    def _verify_room_password(self, room_id: str, client_data: Dict[str, Any]) -> bool:
        """
        验证房间密码
        
        Args:
            room_id: 房间ID
            client_data: 客户端数据
            
        Returns:
            密码是否正确
        """
        try:
            if not self.room_config["enable_room_passwords"]:
                return True
                
            with self.rooms_lock:
                if room_id not in self.rooms:
                    return False
                    
                room_data = self.rooms[room_id]
                if not room_data["password"]:
                    return True
                    
                client_password = client_data.get("password") if client_data else None
                return client_password == room_data["password"]
                
        except Exception as e:
            print(f"✗ 房间密码验证失败: {e}")
            self.room_stats["errors"] += 1
            return False
            
    def _notify_client_room_destroyed(self, client_id: str, room_id: str):
        """
        通知客户端房间被销毁
        
        Args:
            client_id: 客户端ID
            room_id: 房间ID
        """
        try:
            # 从客户端房间映射中移除
            if client_id in self.client_rooms:
                del self.client_rooms[client_id]
                
            # 发送房间销毁通知
            if self.plugin.message_router:
                destroy_message = {
                    "type": "room_destroyed",
                    "room_id": room_id,
                    "timestamp": time.time()
                }
                
                client_data = self.plugin.client_manager.get_client(client_id)
                if client_data and "socket" in client_data:
                    self.plugin.message_router.send_message(
                        destroy_message, 
                        client_data["socket"], 
                        client_id
                    )
                    
        except Exception as e:
            print(f"✗ 通知客户端房间销毁失败: {e}")
            self.room_stats["errors"] += 1
            
    def get_room_info(self, room_id: str) -> Optional[Dict[str, Any]]:
        """
        获取房间信息
        
        Args:
            room_id: 房间ID
            
        Returns:
            房间信息或None
        """
        try:
            with self.rooms_lock:
                if room_id in self.rooms:
                    room_data = self.rooms[room_id]
                    # 返回不包含敏感信息的房间信息
                    safe_room_data = {
                        "room_id": room_data["room_id"],
                        "room_name": room_data["room_name"],
                        "settings": room_data["settings"],
                        "client_count": len(room_data["clients"]),
                        "has_password": bool(room_data["password"]),
                        "host_client_id": room_data["host_client_id"],
                        "created_time": room_data["created_time"],
                        "last_activity": room_data["last_activity"]
                    }
                    return safe_room_data
                else:
                    return None
                    
        except Exception as e:
            print(f"✗ 获取房间信息失败: {e}")
            self.room_stats["errors"] += 1
            return None
            
    def get_all_rooms(self) -> List[Dict[str, Any]]:
        """
        获取所有房间信息
        
        Returns:
            房间信息列表
        """
        try:
            rooms_info = []
            with self.rooms_lock:
                for room_id, room_data in self.rooms.items():
                    # 只返回公开房间或用户所在的房间
                    if room_data["settings"].get("is_public", True):
                        safe_room_data = {
                            "room_id": room_data["room_id"],
                            "room_name": room_data["room_name"],
                            "settings": room_data["settings"],
                            "client_count": len(room_data["clients"]),
                            "has_password": bool(room_data["password"]),
                            "host_client_id": room_data["host_client_id"],
                            "created_time": room_data["created_time"],
                            "last_activity": room_data["last_activity"]
                        }
                        rooms_info.append(safe_room_data)
                        
            return rooms_info
            
        except Exception as e:
            print(f"✗ 获取所有房间信息失败: {e}")
            self.room_stats["errors"] += 1
            return []
            
    def get_client_room(self, client_id: str) -> Optional[str]:
        """
        获取客户端所在房间
        
        Args:
            client_id: 客户端ID
            
        Returns:
            房间ID或None
        """
        try:
            return self.client_rooms.get(client_id)
        except Exception as e:
            print(f"✗ 获取客户端房间失败: {e}")
            self.room_stats["errors"] += 1
            return None
            
    def get_room_clients(self, room_id: str) -> List[str]:
        """
        获取房间内所有客户端
        
        Args:
            room_id: 房间ID
            
        Returns:
            客户端ID列表
        """
        try:
            with self.rooms_lock:
                if room_id in self.rooms:
                    return list(self.rooms[room_id]["clients"].keys())
                else:
                    return []
                    
        except Exception as e:
            print(f"✗ 获取房间客户端失败: {e}")
            self.room_stats["errors"] += 1
            return []
            
    def update_room_state(self, room_id: str, state_data: Dict[str, Any]) -> bool:
        """
        更新房间状态
        
        Args:
            room_id: 房间ID
            state_data: 状态数据
            
        Returns:
            是否更新成功
        """
        try:
            with self.rooms_lock:
                if room_id not in self.rooms:
                    return False
                    
                self.rooms[room_id]["room_state"].update(state_data)
                self.rooms[room_id]["last_activity"] = time.time()
                
            # 触发房间更新回调
            self._trigger_room_callback("room_updated", {
                "room_id": room_id,
                "state_data": state_data,
                "timestamp": time.time()
            })
            
            return True
            
        except Exception as e:
            print(f"✗ 更新房间状态失败: {e}")
            self.room_stats["errors"] += 1
            return False
            
    def broadcast_to_room(self, room_id: str, message_data: Dict[str, Any], 
                         exclude_client_id: str = None) -> bool:
        """
        向房间内所有客户端广播消息
        
        Args:
            room_id: 房间ID
            message_data: 消息数据
            exclude_client_id: 要排除的客户端ID
            
        Returns:
            是否广播成功
        """
        try:
            if not self.enabled:
                return False
                
            with self.rooms_lock:
                if room_id not in self.rooms:
                    return False
                    
                room_data = self.rooms[room_id]
                success_count = 0
                
                # 向房间内每个客户端发送消息
                for client_id in room_data["clients"]:
                    # 跳过排除的客户端
                    if client_id == exclude_client_id:
                        continue
                        
                    # 获取客户端数据
                    client_data = self.plugin.client_manager.get_client(client_id)
                    if client_data and "socket" in client_data:
                        # 发送消息
                        if self.plugin.message_router:
                            send_success = self.plugin.message_router.send_message(
                                message_data, 
                                client_data["socket"], 
                                client_id
                            )
                            if send_success:
                                success_count += 1
                                
                return success_count > 0
                
        except Exception as e:
            print(f"✗ 房间广播失败: {e}")
            self.room_stats["errors"] += 1
            return False
            
    def set_room_custom_data(self, room_id: str, key: str, value: Any) -> bool:
        """
        设置房间自定义数据
        
        Args:
            room_id: 房间ID
            key: 数据键
            value: 数据值
            
        Returns:
            是否设置成功
        """
        try:
            with self.rooms_lock:
                if room_id not in self.rooms:
                    return False
                    
                self.rooms[room_id]["custom_data"][key] = value
                return True
                
        except Exception as e:
            print(f"✗ 设置房间自定义数据失败: {e}")
            self.room_stats["errors"] += 1
            return False
            
    def get_room_custom_data(self, room_id: str, key: str, default: Any = None) -> Any:
        """
        获取房间自定义数据
        
        Args:
            room_id: 房间ID
            key: 数据键
            default: 默认值
            
        Returns:
            数据值或默认值
        """
        try:
            with self.rooms_lock:
                if room_id not in self.rooms:
                    return default
                    
                return self.rooms[room_id]["custom_data"].get(key, default)
                
        except Exception as e:
            print(f"✗ 获取房间自定义数据失败: {e}")
            self.room_stats["errors"] += 1
            return default
            
    def get_room_stats(self) -> Dict[str, Any]:
        """
        获取房间统计信息
        
        Returns:
            房间统计字典
        """
        return {
            "stats": self.room_stats.copy(),
            "config": self.room_config.copy(),
            "current_rooms": len(self.rooms),
            "current_clients_in_rooms": len(self.client_rooms)
        }
        
    def reset_stats(self):
        """重置房间统计信息"""
        try:
            self.room_stats = {
                "total_rooms": 0,
                "active_rooms": 0,
                "clients_in_rooms": 0,
                "rooms_created": 0,
                "rooms_destroyed": 0,
                "clients_joined": 0,
                "clients_left": 0,
                "errors": 0
            }
            print("✓ 房间统计信息已重置")
        except Exception as e:
            print(f"✗ 房间统计信息重置失败: {e}")
            
    def set_room_config(self, config: Dict[str, Any]) -> bool:
        """
        设置房间配置
        
        Args:
            config: 房间配置字典
            
        Returns:
            是否设置成功
        """
        try:
            self.room_config.update(config)
            print(f"✓ 房间配置已更新: {self.room_config}")
            return True
        except Exception as e:
            print(f"✗ 房间配置设置失败: {e}")
            return False
            
    def get_room_config(self) -> Dict[str, Any]:
        """
        获取房间配置
        
        Returns:
            房间配置字典
        """
        return self.room_config.copy()
        
    def _trigger_room_callback(self, callback_type: str, data: Dict[str, Any]):
        """
        触发房间回调
        
        Args:
            callback_type: 回调类型
            data: 回调数据
        """
        try:
            if callback_type in self.room_callbacks:
                for callback in self.room_callbacks[callback_type]:
                    try:
                        callback(data)
                    except Exception as e:
                        print(f"✗ 房间回调执行失败: {callback_type} - {e}")
        except Exception as e:
            print(f"✗ 房间回调触发失败: {e}")
            
    def register_room_callback(self, callback_type: str, callback: callable):
        """
        注册房间回调
        
        Args:
            callback_type: 回调类型
            callback: 回调函数
        """
        try:
            if callback_type in self.room_callbacks:
                self.room_callbacks[callback_type].append(callback)
                print(f"✓ 房间回调已注册: {callback_type}")
            else:
                print(f"✗ 无效的回调类型: {callback_type}")
        except Exception as e:
            print(f"✗ 房间回调注册失败: {e}")
            
    def unregister_room_callback(self, callback_type: str, callback: callable):
        """
        注销房间回调
        
        Args:
            callback_type: 回调类型
            callback: 回调函数
        """
        try:
            if callback_type in self.room_callbacks:
                if callback in self.room_callbacks[callback_type]:
                    self.room_callbacks[callback_type].remove(callback)
                    print(f"✓ 房间回调已注销: {callback_type}")
            else:
                print(f"✗ 无效的回调类型: {callback_type}")
        except Exception as e:
            print(f"✗ 房间回调注销失败: {e}")