"""
客户端管理器模块
负责管理客户端连接、认证和断开
"""

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

class ClientManager:
    """
    客户端管理器
    负责管理客户端连接、认证和断开
    """
    
    def __init__(self, plugin):
        """
        初始化客户端管理器
        
        Args:
            plugin: 服务器架构插件实例
        """
        self.plugin = plugin
        self.enabled = False
        self.initialized = False
        
        # 客户端配置
        self.client_config = {
            "enable_authentication": True,
            "auth_timeout": 30.0,
            "max_clients": 1000,
            "enable_heartbeat": True,
            "heartbeat_interval": 30.0,
            "enable_rate_limiting": True,
            "max_requests_per_second": 100,
            "enable_banning": True,
            "ban_duration": 3600  # 1小时
        }
        
        # 客户端存储
        self.clients = {}  # 已认证客户端
        self.pending_clients = {}  # 待认证客户端
        self.banned_clients = {}  # 被禁止的客户端
        
        # 客户端统计
        self.client_stats = {
            "total_clients": 0,
            "authenticated_clients": 0,
            "pending_clients": 0,
            "disconnected_clients": 0,
            "banned_clients": 0,
            "authentication_success": 0,
            "authentication_failed": 0,
            "rate_limit_exceeded": 0,
            "heartbeat_timeouts": 0,
            "errors": 0
        }
        
        # 线程锁
        self.clients_lock = threading.RLock()
        
        # 回调函数
        self.client_callbacks = {
            "client_authenticated": [],
            "client_disconnected": [],
            "client_banned": [],
            "authentication_failed": [],
            "rate_limit_exceeded": []
        }
        
        # 时间戳记录
        self.last_cleanup = 0.0
        self.last_heartbeat_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.client_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.client_stats["errors"] += 1
            import traceback
            traceback.print_exc()
            return False
            
    def disable(self):
        """禁用客户端管理器"""
        try:
            self.enabled = False
            
            # 断开所有客户端
            self.disconnect_all_clients()
            
            print("✓ 客户端管理器已禁用")
            
        except Exception as e:
            print(f"✗ 客户端管理器禁用失败: {e}")
            self.client_stats["errors"] += 1
            import traceback
            traceback.print_exc()
            
    def finalize(self):
        """清理客户端管理器资源"""
        try:
            # 禁用管理器
            if self.enabled:
                self.disable()
                
            # 清理回调
            self.client_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_data(current_time)
                self.last_cleanup = current_time
                
            # 检查心跳超时
            if self.client_config["enable_heartbeat"]:
                if current_time - self.last_heartbeat_check > self.client_config["heartbeat_interval"]:
                    self._check_heartbeat_timeouts(current_time)
                    self.last_heartbeat_check = current_time
                    
        except Exception as e:
            print(f"✗ 客户端管理器更新失败: {e}")
            self.client_stats["errors"] += 1
            import traceback
            traceback.print_exc()
            
    def _cleanup_expired_data(self, current_time: float):
        """清理过期数据"""
        try:
            # 清理过期的待认证客户端
            expired_pending = []
            for client_id, client_data in self.pending_clients.items():
                if current_time - client_data["connect_time"] > self.client_config["auth_timeout"]:
                    expired_pending.append(client_id)
                    
            for client_id in expired_pending:
                del self.pending_clients[client_id]
                self.client_stats["pending_clients"] -= 1
                
            # 清理过期的禁止列表
            expired_bans = []
            for client_addr, ban_data in self.banned_clients.items():
                if current_time - ban_data["ban_time"] > self.client_config["ban_duration"]:
                    expired_bans.append(client_addr)
                    
            for client_addr in expired_bans:
                del self.banned_clients[client_addr]
                self.client_stats["banned_clients"] -= 1
                
        except Exception as e:
            print(f"✗ 过期数据清理失败: {e}")
            self.client_stats["errors"] += 1
            
    def _check_heartbeat_timeouts(self, current_time: float):
        """检查心跳超时"""
        try:
            timed_out_clients = []
            with self.clients_lock:
                for client_id, client_data in self.clients.items():
                    last_heartbeat = client_data.get("last_heartbeat", client_data["connect_time"])
                    if current_time - last_heartbeat > self.client_config["heartbeat_interval"] * 3:
                        timed_out_clients.append(client_id)
                        
            for client_id in timed_out_clients:
                self.disconnect_client(client_id, "heartbeat_timeout")
                self.client_stats["heartbeat_timeouts"] += 1
                
        except Exception as e:
            print(f"✗ 心跳超时检查失败: {e}")
            self.client_stats["errors"] += 1
            
    def add_pending_client(self, client_socket, client_address) -> str:
        """
        添加待认证客户端
        
        Args:
            client_socket: 客户端套接字
            client_address: 客户端地址
            
        Returns:
            客户端ID
        """
        try:
            # 检查是否被禁止
            if self._is_client_banned(client_address):
                client_socket.close()
                self.client_stats["banned_clients"] += 1
                return ""
                
            # 检查连接限制
            if len(self.pending_clients) + len(self.clients) >= self.client_config["max_clients"]:
                client_socket.close()
                return ""
                
            # 生成客户端ID
            client_id = str(uuid.uuid4())
            
            # 添加到待认证列表
            with self.clients_lock:
                self.pending_clients[client_id] = {
                    "socket": client_socket,
                    "address": client_address,
                    "connect_time": time.time(),
                    "last_activity": time.time(),
                    "request_count": 0,
                    "last_request_time": time.time()
                }
                
            self.client_stats["pending_clients"] += 1
            
            return client_id
            
        except Exception as e:
            print(f"✗ 添加待认证客户端失败: {e}")
            self.client_stats["errors"] += 1
            return ""
            
    def authenticate_client(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
        """
        认证客户端
        
        Args:
            client_id: 客户端ID
            auth_data: 认证数据
            
        Returns:
            是否认证成功
        """
        try:
            if not self.enabled:
                return False
                
            if not self.client_config["enable_authentication"]:
                # 如果禁用认证，直接通过
                return self._complete_authentication(client_id, auth_data)
                
            # 检查客户端是否在待认证列表中
            if client_id not in self.pending_clients:
                self.client_stats["authentication_failed"] += 1
                return False
                
            # 使用安全管理系统进行认证
            if self.plugin.security_manager:
                auth_result = self.plugin.security_manager.authenticate_client(
                    client_id, 
                    auth_data, 
                    self.pending_clients[client_id]["address"]
                )
                
                if auth_result:
                    return self._complete_authentication(client_id, auth_data)
                else:
                    self.client_stats["authentication_failed"] += 1
                    
                    # 触发认证失败回调
                    self._trigger_client_callback("authentication_failed", {
                        "client_id": client_id,
                        "auth_data": auth_data,
                        "timestamp": time.time()
                    })
                    
                    # 移除待认证客户端
                    with self.clients_lock:
                        if client_id in self.pending_clients:
                            del self.pending_clients[client_id]
                            self.client_stats["pending_clients"] -= 1
                            
                    return False
            else:
                # 如果没有安全管理系统，使用简单认证
                return self._complete_authentication(client_id, auth_data)
                
        except Exception as e:
            print(f"✗ 客户端认证失败: {e}")
            self.client_stats["errors"] += 1
            return False
            
    def _complete_authentication(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
        """
        完成客户端认证
        
        Args:
            client_id: 客户端ID
            auth_data: 认证数据
            
        Returns:
            是否完成认证
        """
        try:
            # 检查客户端是否在待认证列表中
            if client_id not in self.pending_clients:
                return False
                
            # 获取待认证客户端数据
            pending_client = self.pending_clients[client_id]
            
            # 创建已认证客户端数据
            client_data = {
                "socket": pending_client["socket"],
                "address": pending_client["address"],
                "connect_time": pending_client["connect_time"],
                "last_activity": time.time(),
                "last_heartbeat": time.time(),
                "user_id": auth_data.get("user_id", ""),
                "username": auth_data.get("username", ""),
                "permissions": auth_data.get("permissions", []),
                "session_id": str(uuid.uuid4()),
                "bytes_sent": 0,
                "bytes_received": 0,
                "messages_sent": 0,
                "messages_received": 0
            }
            
            # 移动客户端到已认证列表
            with self.clients_lock:
                self.clients[client_id] = client_data
                del self.pending_clients[client_id]
                
            self.client_stats["authenticated_clients"] += 1
            self.client_stats["pending_clients"] -= 1
            self.client_stats["authentication_success"] += 1
            
            # 触发客户端认证回调
            self._trigger_client_callback("client_authenticated", {
                "client_id": client_id,
                "user_id": client_data["user_id"],
                "username": client_data["username"],
                "address": client_data["address"],
                "timestamp": client_data["last_activity"]
            })
            
            return True
            
        except Exception as e:
            print(f"✗ 完成客户端认证失败: {e}")
            self.client_stats["errors"] += 1
            return False
            
    def disconnect_client(self, client_id: str, reason: str = "unknown"):
        """
        断开客户端连接
        
        Args:
            client_id: 客户端ID
            reason: 断开原因
        """
        try:
            client_data = None
            with self.clients_lock:
                if client_id in self.clients:
                    client_data = self.clients[client_id]
                    del self.clients[client_id]
                    self.client_stats["authenticated_clients"] -= 1
                elif client_id in self.pending_clients:
                    client_data = self.pending_clients[client_id]
                    del self.pending_clients[client_id]
                    self.client_stats["pending_clients"] -= 1
                    
            if client_data:
                # 关闭套接字
                try:
                    client_data["socket"].close()
                except:
                    pass
                    
                self.client_stats["disconnected_clients"] += 1
                
                # 触发客户端断开回调
                self._trigger_client_callback("client_disconnected", {
                    "client_id": client_id,
                    "address": client_data["address"],
                    "reason": reason,
                    "timestamp": time.time()
                })
                
                print(f"✓ 客户端已断开: {client_id} ({reason})")
                
        except Exception as e:
            print(f"✗ 断开客户端连接失败: {e}")
            self.client_stats["errors"] += 1
            
    def disconnect_all_clients(self):
        """断开所有客户端连接"""
        try:
            with self.clients_lock:
                # 断开已认证客户端
                client_ids = list(self.clients.keys())
                for client_id in client_ids:
                    self.disconnect_client(client_id, "server_shutdown")
                    
                # 断开待认证客户端
                pending_ids = list(self.pending_clients.keys())
                for client_id in pending_ids:
                    self.disconnect_client(client_id, "server_shutdown")
                    
        except Exception as e:
            print(f"✗ 断开所有客户端连接失败: {e}")
            self.client_stats["errors"] += 1
            
    def ban_client(self, client_address, reason: str = "unknown"):
        """
        禁止客户端连接
        
        Args:
            client_address: 客户端地址
            reason: 禁止原因
        """
        try:
            if not self.client_config["enable_banning"]:
                return
                
            ban_time = time.time()
            self.banned_clients[client_address] = {
                "ban_time": ban_time,
                "reason": reason,
                "ban_duration": self.client_config["ban_duration"]
            }
            
            self.client_stats["banned_clients"] += 1
            
            # 断开该地址的所有客户端
            self._disconnect_clients_by_address(client_address)
            
            # 触发客户端禁止回调
            self._trigger_client_callback("client_banned", {
                "address": client_address,
                "reason": reason,
                "ban_time": ban_time,
                "duration": self.client_config["ban_duration"]
            })
            
            print(f"✓ 客户端已被禁止: {client_address} ({reason})")
            
        except Exception as e:
            print(f"✗ 禁止客户端失败: {e}")
            self.client_stats["errors"] += 1
            
    def _disconnect_clients_by_address(self, client_address):
        """
        根据地址断开客户端连接
        
        Args:
            client_address: 客户端地址
        """
        try:
            # 断开已认证客户端
            clients_to_disconnect = []
            with self.clients_lock:
                for client_id, client_data in self.clients.items():
                    if client_data["address"] == client_address:
                        clients_to_disconnect.append(client_id)
                        
            for client_id in clients_to_disconnect:
                self.disconnect_client(client_id, "banned")
                
            # 断开待认证客户端
            pending_to_disconnect = []
            with self.clients_lock:
                for client_id, client_data in self.pending_clients.items():
                    if client_data["address"] == client_address:
                        pending_to_disconnect.append(client_id)
                        
            for client_id in pending_to_disconnect:
                self.disconnect_client(client_id, "banned")
                
        except Exception as e:
            print(f"✗ 根据地址断开客户端失败: {e}")
            self.client_stats["errors"] += 1
            
    def _is_client_banned(self, client_address) -> bool:
        """
        检查客户端是否被禁止
        
        Args:
            client_address: 客户端地址
            
        Returns:
            是否被禁止
        """
        try:
            if not self.client_config["enable_banning"]:
                return False
                
            if client_address in self.banned_clients:
                ban_data = self.banned_clients[client_address]
                if time.time() - ban_data["ban_time"] < ban_data["ban_duration"]:
                    return True
                else:
                    # 禁止时间已过期，移除
                    del self.banned_clients[client_address]
                    self.client_stats["banned_clients"] -= 1
                    
            return False
            
        except Exception as e:
            print(f"✗ 检查客户端禁止状态失败: {e}")
            self.client_stats["errors"] += 1
            return False
            
    def update_client_activity(self, client_id: str):
        """
        更新客户端活动时间
        
        Args:
            client_id: 客户端ID
        """
        try:
            current_time = time.time()
            with self.clients_lock:
                if client_id in self.clients:
                    self.clients[client_id]["last_activity"] = current_time
                elif client_id in self.pending_clients:
                    self.pending_clients[client_id]["last_activity"] = current_time
                    
        except Exception as e:
            print(f"✗ 更新客户端活动时间失败: {e}")
            self.client_stats["errors"] += 1
            
    def update_client_heartbeat(self, client_id: str):
        """
        更新客户端心跳时间
        
        Args:
            client_id: 客户端ID
        """
        try:
            current_time = time.time()
            with self.clients_lock:
                if client_id in self.clients:
                    self.clients[client_id]["last_heartbeat"] = current_time
                    
        except Exception as e:
            print(f"✗ 更新客户端心跳时间失败: {e}")
            self.client_stats["errors"] += 1
            
    def send_heartbeat(self):
        """发送心跳消息到所有客户端"""
        try:
            if not self.client_config["enable_heartbeat"]:
                return
                
            heartbeat_message = b'{"type": "heartbeat"}'
            with self.clients_lock:
                for client_id, client_data in self.clients.items():
                    try:
                        client_data["socket"].send(heartbeat_message)
                        client_data["messages_sent"] += 1
                        client_data["bytes_sent"] += len(heartbeat_message)
                    except Exception as e:
                        print(f"✗ 心跳消息发送失败: {client_id} - {e}")
                        self.client_stats["errors"] += 1
                        
        except Exception as e:
            print(f"✗ 发送心跳消息失败: {e}")
            self.client_stats["errors"] += 1
            
    def get_client(self, client_id: str) -> Optional[Dict[str, Any]]:
        """
        获取客户端信息
        
        Args:
            client_id: 客户端ID
            
        Returns:
            客户端信息或None
        """
        try:
            with self.clients_lock:
                return self.clients.get(client_id, {}).copy()
        except Exception as e:
            print(f"✗ 获取客户端信息失败: {e}")
            self.client_stats["errors"] += 1
            return None
            
    def get_all_clients(self) -> Dict[str, Dict[str, Any]]:
        """
        获取所有客户端信息
        
        Returns:
            所有客户端信息字典
        """
        try:
            with self.clients_lock:
                return {k: v.copy() for k, v in self.clients.items()}
        except Exception as e:
            print(f"✗ 获取所有客户端信息失败: {e}")
            self.client_stats["errors"] += 1
            return {}
            
    def get_client_count(self) -> int:
        """
        获取客户端数量
        
        Returns:
            客户端数量
        """
        try:
            with self.clients_lock:
                return len(self.clients)
        except Exception as e:
            print(f"✗ 获取客户端数量失败: {e}")
            self.client_stats["errors"] += 1
            return 0
            
    def is_client_authenticated(self, client_id: str) -> bool:
        """
        检查客户端是否已认证
        
        Args:
            client_id: 客户端ID
            
        Returns:
            客户端是否已认证
        """
        try:
            with self.clients_lock:
                return client_id in self.clients
        except Exception as e:
            print(f"✗ 检查客户端认证状态失败: {e}")
            self.client_stats["errors"] += 1
            return False
            
    def check_rate_limit(self, client_id: str) -> bool:
        """
        检查客户端速率限制
        
        Args:
            client_id: 客户端ID
            
        Returns:
            是否超过速率限制
        """
        try:
            if not self.client_config["enable_rate_limiting"]:
                return False  # 未启用速率限制
                
            current_time = time.time()
            with self.clients_lock:
                client_data = None
                if client_id in self.clients:
                    client_data = self.clients[client_id]
                elif client_id in self.pending_clients:
                    client_data = self.pending_clients[client_id]
                else:
                    return False  # 客户端不存在
                    
                # 计算请求速率
                time_diff = current_time - client_data["last_request_time"]
                if time_diff >= 1.0:  # 重置计数器
                    client_data["request_count"] = 0
                    client_data["last_request_time"] = current_time
                    
                client_data["request_count"] += 1
                
                # 检查是否超过限制
                if client_data["request_count"] > self.client_config["max_requests_per_second"]:
                    self.client_stats["rate_limit_exceeded"] += 1
                    
                    # 触发速率限制回调
                    self._trigger_client_callback("rate_limit_exceeded", {
                        "client_id": client_id,
                        "request_count": client_data["request_count"],
                        "max_requests": self.client_config["max_requests_per_second"],
                        "timestamp": current_time
                    })
                    
                    return True  # 超过限制
                    
            return False  # 未超过限制
            
        except Exception as e:
            print(f"✗ 检查速率限制失败: {e}")
            self.client_stats["errors"] += 1
            return False
            
    def get_client_stats(self) -> Dict[str, Any]:
        """
        获取客户端统计信息
        
        Returns:
            客户端统计字典
        """
        return {
            "clients": self.client_stats.copy(),
            "config": self.client_config.copy(),
            "current_clients": len(self.clients),
            "current_pending": len(self.pending_clients),
            "current_banned": len(self.banned_clients)
        }
        
    def reset_stats(self):
        """重置客户端统计信息"""
        try:
            self.client_stats = {
                "total_clients": 0,
                "authenticated_clients": 0,
                "pending_clients": 0,
                "disconnected_clients": 0,
                "banned_clients": 0,
                "authentication_success": 0,
                "authentication_failed": 0,
                "rate_limit_exceeded": 0,
                "heartbeat_timeouts": 0,
                "errors": 0
            }
            print("✓ 客户端统计信息已重置")
        except Exception as e:
            print(f"✗ 客户端统计信息重置失败: {e}")
            
    def set_client_config(self, config: Dict[str, Any]) -> bool:
        """
        设置客户端配置
        
        Args:
            config: 客户端配置字典
            
        Returns:
            是否设置成功
        """
        try:
            self.client_config.update(config)
            print(f"✓ 客户端配置已更新: {self.client_config}")
            return True
        except Exception as e:
            print(f"✗ 客户端配置设置失败: {e}")
            return False
            
    def get_client_config(self) -> Dict[str, Any]:
        """
        获取客户端配置
        
        Returns:
            客户端配置字典
        """
        return self.client_config.copy()
        
    def _trigger_client_callback(self, callback_type: str, data: Dict[str, Any]):
        """
        触发客户端回调
        
        Args:
            callback_type: 回调类型
            data: 回调数据
        """
        try:
            if callback_type in self.client_callbacks:
                for callback in self.client_callbacks[callback_type]:
                    try:
                        callback(data)
                    except Exception as e:
                        print(f"✗ 客户端回调执行失败: {callback_type} - {e}")
        except Exception as e:
            print(f"✗ 客户端回调触发失败: {e}")
            
    def register_client_callback(self, callback_type: str, callback: callable):
        """
        注册客户端回调
        
        Args:
            callback_type: 回调类型
            callback: 回调函数
        """
        try:
            if callback_type in self.client_callbacks:
                self.client_callbacks[callback_type].append(callback)
                print(f"✓ 客户端回调已注册: {callback_type}")
            else:
                print(f"✗ 无效的回调类型: {callback_type}")
        except Exception as e:
            print(f"✗ 客户端回调注册失败: {e}")
            
    def unregister_client_callback(self, callback_type: str, callback: callable):
        """
        注销客户端回调
        
        Args:
            callback_type: 回调类型
            callback: 回调函数
        """
        try:
            if callback_type in self.client_callbacks:
                if callback in self.client_callbacks[callback_type]:
                    self.client_callbacks[callback_type].remove(callback)
                    print(f"✓ 客户端回调已注销: {callback_type}")
            else:
                print(f"✗ 无效的回调类型: {callback_type}")
        except Exception as e:
            print(f"✗ 客户端回调注销失败: {e}")