"""
认证管理器模块
确保通信安全
"""

import time
import hashlib
import secrets
import hmac
from typing import Dict, Any, List, Optional

class AuthManager:
    """
    认证管理器
    确保通信安全
    """
    
    def __init__(self, plugin):
        """
        初始化认证管理器
        
        Args:
            plugin: 实时通信插件实例
        """
        self.plugin = plugin
        self.enabled = False
        self.initialized = False
        
        # 认证配置
        self.auth_config = {
            "enable_authentication": True,
            "auth_timeout": 30.0,
            "enable_token_auth": True,
            "enable_password_auth": True,
            "token_lifetime": 86400,  # 24小时
            "enable_session_management": True,
            "session_timeout": 3600,  # 1小时
            "enable_two_factor_auth": False,
            "max_login_attempts": 5,
            "login_lockout_duration": 900,  # 15分钟
            "enable_ip_filtering": True,
            "enable_audit_logging": True
        }
        
        # 认证状态
        self.auth_state = {
            "active_sessions": 0,
            "total_authentications": 0,
            "successful_authentications": 0,
            "failed_authentications": 0
        }
        
        # 认证存储
        self.sessions = {}
        self.tokens = {}
        self.login_attempts = {}
        self.blocked_ips = {}
        
        # 认证统计
        self.auth_stats = {
            "tokens_generated": 0,
            "sessions_created": 0,
            "sessions_expired": 0,
            "users_banned": 0,
            "auth_errors": 0
        }
        
        # 密钥管理
        self.secret_key = self._generate_secret_key()
        
        # 回调函数
        self.auth_callbacks = {
            "auth_success": [],
            "auth_failed": [],
            "session_created": [],
            "session_expired": [],
            "user_banned": [],
            "auth_error": []
        }
        
        # 时间戳记录
        self.last_session_cleanup = 0.0
        self.last_auth_event = 0.0
        
        print("✓ 认证管理器已创建")
        
    def initialize(self) -> bool:
        """
        初始化认证管理器
        
        Returns:
            是否初始化成功
        """
        try:
            print("正在初始化认证管理器...")
            
            # 生成密钥
            self.secret_key = self._generate_secret_key()
            
            self.initialized = True
            print("✓ 认证管理器初始化完成")
            return True
            
        except Exception as e:
            print(f"✗ 认证管理器初始化失败: {e}")
            self.auth_stats["auth_errors"] += 1
            import traceback
            traceback.print_exc()
            return False
            
    def _generate_secret_key(self) -> str:
        """
        生成密钥
        
        Returns:
            生成的密钥
        """
        try:
            return secrets.token_hex(32)
        except Exception as e:
            print(f"✗ 密钥生成失败: {e}")
            # 使用默认密钥（仅用于开发环境）
            return "default_secret_key_for_development_purposes_only"
            
    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.auth_stats["auth_errors"] += 1
            import traceback
            traceback.print_exc()
            return False
            
    def disable(self):
        """禁用认证管理器"""
        try:
            self.enabled = False
            
            # 清理会话和令牌
            self.sessions.clear()
            self.tokens.clear()
            
            print("✓ 认证管理器已禁用")
            
        except Exception as e:
            print(f"✗ 认证管理器禁用失败: {e}")
            self.auth_stats["auth_errors"] += 1
            import traceback
            traceback.print_exc()
            
    def finalize(self):
        """清理认证管理器资源"""
        try:
            # 禁用认证管理器
            if self.enabled:
                self.disable()
                
            # 清理回调
            self.auth_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_session_cleanup > 300:  # 每5分钟清理一次
                self._cleanup_expired_sessions(current_time)
                self.last_session_cleanup = current_time
                
            # 定期清理登录尝试记录
            self._cleanup_login_attempts(current_time)
            
            self.last_auth_event = current_time
            
        except Exception as e:
            print(f"✗ 认证管理器更新失败: {e}")
            self.auth_stats["auth_errors"] += 1
            import traceback
            traceback.print_exc()
            
    def _cleanup_expired_sessions(self, current_time: float):
        """清理过期会话"""
        try:
            expired_sessions = []
            for session_id, session_data in self.sessions.items():
                if current_time - session_data["login_time"] > self.auth_config["session_timeout"]:
                    expired_sessions.append(session_id)
                    
            for session_id in expired_sessions:
                del self.sessions[session_id]
                self.auth_state["active_sessions"] -= 1
                self.auth_stats["sessions_expired"] += 1
                
                # 触发会话过期回调
                self._trigger_auth_callback("session_expired", {
                    "session_id": session_id,
                    "timestamp": current_time
                })
                
        except Exception as e:
            print(f"✗ 过期会话清理失败: {e}")
            self.auth_stats["auth_errors"] += 1
            
    def _cleanup_login_attempts(self, current_time: float):
        """清理登录尝试记录"""
        try:
            expired_attempts = []
            for ip_address, attempt_data in self.login_attempts.items():
                if current_time - attempt_data["last_attempt"] > self.auth_config["login_lockout_duration"]:
                    expired_attempts.append(ip_address)
                    
            for ip_address in expired_attempts:
                del self.login_attempts[ip_address]
                
        except Exception as e:
            print(f"✗ 登录尝试记录清理失败: {e}")
            self.auth_stats["auth_errors"] += 1
            
    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 or not self.auth_config["enable_authentication"]:
                # 如果未启用认证，直接通过
                return True
                
            # 检查IP是否被阻止
            client_ip = auth_data.get("client_ip", "")
            if self._is_ip_blocked(client_ip):
                self.auth_stats["failed_authentications"] += 1
                return False
                
            # 检查登录尝试次数
            if self._is_login_blocked(client_ip):
                self.auth_stats["failed_authentications"] += 1
                return False
                
            # 执行认证
            auth_result = self._perform_authentication(client_id, auth_data)
            
            if auth_result:
                self.auth_state["successful_authentications"] += 1
                self.auth_state["total_authentications"] += 1
                
                # 触发认证成功回调
                self._trigger_auth_callback("auth_success", {
                    "client_id": client_id,
                    "auth_data": auth_data,
                    "timestamp": time.time()
                })
                
                # 记录审计日志
                if self.auth_config["enable_audit_logging"]:
                    self._log_auth_event("auth_success", client_id, client_ip)
                    
            else:
                self.auth_state["failed_authentications"] += 1
                self.auth_state["total_authentications"] += 1
                
                # 记录失败的登录尝试
                self._record_failed_login(client_ip)
                
                # 触发认证失败回调
                self._trigger_auth_callback("auth_failed", {
                    "client_id": client_id,
                    "auth_data": auth_data,
                    "timestamp": time.time()
                })
                
                # 记录审计日志
                if self.auth_config["enable_audit_logging"]:
                    self._log_auth_event("auth_failed", client_id, client_ip)
                    
            return auth_result
            
        except Exception as e:
            print(f"✗ 客户端认证失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return False
            
    def _is_ip_blocked(self, client_ip: str) -> bool:
        """
        检查IP是否被阻止
        
        Args:
            client_ip: 客户端IP
            
        Returns:
            IP是否被阻止
        """
        try:
            if not self.auth_config["enable_ip_filtering"]:
                return False
                
            if client_ip in self.blocked_ips:
                block_data = self.blocked_ips[client_ip]
                if time.time() - block_data["block_time"] < block_data["duration"]:
                    return True
                else:
                    # 阻止时间已过期，移除
                    del self.blocked_ips[client_ip]
                    
            return False
            
        except Exception as e:
            print(f"✗ IP阻止检查失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return False
            
    def _is_login_blocked(self, client_ip: str) -> bool:
        """
        检查登录是否被阻止
        
        Args:
            client_ip: 客户端IP
            
        Returns:
            登录是否被阻止
        """
        try:
            if client_ip in self.login_attempts:
                attempts = self.login_attempts[client_ip]
                if (attempts["count"] >= self.auth_config["max_login_attempts"] and
                    time.time() - attempts["last_attempt"] < self.auth_config["login_lockout_duration"]):
                    return True
                    
            return False
            
        except Exception as e:
            print(f"✗ 登录阻止检查失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return False
            
    def _record_failed_login(self, client_ip: str):
        """
        记录失败的登录尝试
        
        Args:
            client_ip: 客户端IP
        """
        try:
            current_time = time.time()
            
            if client_ip not in self.login_attempts:
                self.login_attempts[client_ip] = {
                    "count": 1,
                    "last_attempt": current_time
                }
            else:
                self.login_attempts[client_ip]["count"] += 1
                self.login_attempts[client_ip]["last_attempt"] = current_time
                
            # 如果超过最大尝试次数，阻止IP
            if (self.login_attempts[client_ip]["count"] >= 
                self.auth_config["max_login_attempts"]):
                self._block_ip(client_ip, self.auth_config["login_lockout_duration"])
                
        except Exception as e:
            print(f"✗ 失败登录记录失败: {e}")
            self.auth_stats["auth_errors"] += 1
            
    def _perform_authentication(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
        """
        执行认证
        
        Args:
            client_id: 客户端ID
            auth_data: 认证数据
            
        Returns:
            是否认证成功
        """
        try:
            # 检查认证类型
            auth_type = auth_data.get("auth_type", "token")
            
            if auth_type == "token":
                return self._authenticate_with_token(client_id, auth_data)
            elif auth_type == "password":
                return self._authenticate_with_password(client_id, auth_data)
            elif auth_type == "session":
                return self._authenticate_with_session(client_id, auth_data)
            else:
                # 默认认证方式
                return self._authenticate_with_token(client_id, auth_data)
                
        except Exception as e:
            print(f"✗ 认证执行失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return False
            
    def _authenticate_with_token(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
        """
        使用令牌认证
        
        Args:
            client_id: 客户端ID
            auth_data: 认证数据
            
        Returns:
            是否认证成功
        """
        try:
            token = auth_data.get("token")
            if not token:
                return False
                
            # 验证令牌
            if token in self.tokens:
                token_data = self.tokens[token]
                if time.time() - token_data["created_time"] < self.auth_config["token_lifetime"]:
                    # 令牌有效，创建会话
                    self._create_session(client_id, auth_data)
                    return True
                else:
                    # 令牌过期，移除
                    del self.tokens[token]
                    
            return False
            
        except Exception as e:
            print(f"✗ 令牌认证失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return False
            
    def _authenticate_with_password(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
        """
        使用密码认证
        
        Args:
            client_id: 客户端ID
            auth_data: 认证数据
            
        Returns:
            是否认证成功
        """
        try:
            username = auth_data.get("username")
            password = auth_data.get("password")
            
            if not username or not password:
                return False
                
            # 验证密码（简化实现）
            # 在实际应用中，这里应该连接到用户数据库验证用户名和密码
            if username == "test_user" and password == "test_password":
                # 创建会话
                self._create_session(client_id, auth_data)
                return True
            else:
                return False
                
        except Exception as e:
            print(f"✗ 密码认证失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return False
            
    def _authenticate_with_session(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
        """
        使用会话认证
        
        Args:
            client_id: 客户端ID
            auth_data: 认证数据
            
        Returns:
            是否认证成功
        """
        try:
            session_id = auth_data.get("session_id")
            if not session_id:
                return False
                
            # 检查会话是否存在且有效
            if session_id in self.sessions:
                session_data = self.sessions[session_id]
                if time.time() - session_data["login_time"] < self.auth_config["session_timeout"]:
                    # 更新会话最后活动时间
                    session_data["last_activity"] = time.time()
                    return True
                    
            return False
            
        except Exception as e:
            print(f"✗ 会话认证失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return False
            
    def _create_session(self, client_id: str, auth_data: Dict[str, Any]):
        """
        创建会话
        
        Args:
            client_id: 客户端ID
            auth_data: 认证数据
        """
        try:
            session_id = self._generate_session_id()
            
            session_data = {
                "client_id": client_id,
                "login_time": time.time(),
                "last_activity": time.time(),
                "user_id": auth_data.get("user_id", ""),
                "username": auth_data.get("username", ""),
                "permissions": auth_data.get("permissions", [])
            }
            
            self.sessions[session_id] = session_data
            self.auth_state["active_sessions"] += 1
            self.auth_stats["sessions_created"] += 1
            
            # 触发会话创建回调
            self._trigger_auth_callback("session_created", {
                "session_id": session_id,
                "client_id": client_id,
                "auth_data": auth_data,
                "timestamp": time.time()
            })
            
        except Exception as e:
            print(f"✗ 会话创建失败: {e}")
            self.auth_stats["auth_errors"] += 1
            
    def _generate_session_id(self) -> str:
        """
        生成会话ID
        
        Returns:
            生成的会话ID
        """
        try:
            return secrets.token_urlsafe(32)
        except Exception as e:
            print(f"✗ 会话ID生成失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return f"session_{int(time.time() * 1000000)}"
            
    def generate_token(self, user_id: str, permissions: List[str] = None) -> str:
        """
        生成令牌
        
        Args:
            user_id: 用户ID
            permissions: 权限列表
            
        Returns:
            生成的令牌
        """
        try:
            token = secrets.token_urlsafe(64)
            
            self.tokens[token] = {
                "user_id": user_id,
                "permissions": permissions or [],
                "created_time": time.time()
            }
            
            self.auth_stats["tokens_generated"] += 1
            
            return token
            
        except Exception as e:
            print(f"✗ 令牌生成失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return ""
            
    def validate_token(self, token: str) -> bool:
        """
        验证令牌
        
        Args:
            token: 令牌
            
        Returns:
            令牌是否有效
        """
        try:
            if not token:
                return False
                
            if token in self.tokens:
                token_data = self.tokens[token]
                if time.time() - token_data["created_time"] < self.auth_config["token_lifetime"]:
                    return True
                else:
                    # 令牌过期，移除
                    del self.tokens[token]
                    
            return False
            
        except Exception as e:
            print(f"✗ 令牌验证失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return False
            
    def hash_password(self, password: str, salt: str = None) -> Dict[str, str]:
        """
        哈希密码
        
        Args:
            password: 密码
            salt: 盐值（可选）
            
        Returns:
            包含哈希值和盐值的字典
        """
        try:
            if salt is None:
                salt = secrets.token_hex(16)
                
            # 使用PBKDF2哈希密码
            password_hash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt.encode('utf-8'), 100000)
            return {
                "hash": password_hash.hex(),
                "salt": salt
            }
            
        except Exception as e:
            print(f"✗ 密码哈希失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return {}
            
    def verify_password(self, password: str, password_hash: str, salt: str) -> bool:
        """
        验证密码
        
        Args:
            password: 密码
            password_hash: 密码哈希值
            salt: 盐值
            
        Returns:
            密码是否正确
        """
        try:
            # 重新哈希密码
            new_hash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt.encode('utf-8'), 100000)
            return hmac.compare_digest(new_hash.hex(), password_hash)
            
        except Exception as e:
            print(f"✗ 密码验证失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return False
            
    def _block_ip(self, client_ip: str, duration: float):
        """
        阻止IP地址
        
        Args:
            client_ip: 客户端IP
            duration: 阻止持续时间（秒）
        """
        try:
            self.blocked_ips[client_ip] = {
                "block_time": time.time(),
                "duration": duration
            }
            
            # 触发用户禁止回调
            self._trigger_auth_callback("user_banned", {
                "ip_address": client_ip,
                "duration": duration,
                "timestamp": time.time()
            })
            
            # 记录审计日志
            if self.auth_config["enable_audit_logging"]:
                self._log_auth_event("ip_blocked", None, client_ip)
                
            print(f"✓ IP地址已被阻止: {client_ip} (持续 {duration} 秒)")
            
        except Exception as e:
            print(f"✗ IP阻止失败: {e}")
            self.auth_stats["auth_errors"] += 1
            
    def unblock_ip(self, client_ip: str) -> bool:
        """
        解除IP阻止
        
        Args:
            client_ip: 客户端IP
            
        Returns:
            是否解除成功
        """
        try:
            if client_ip in self.blocked_ips:
                del self.blocked_ips[client_ip]
                print(f"✓ IP地址阻止已解除: {client_ip}")
                return True
            else:
                print(f"✗ IP地址未被阻止: {client_ip}")
                return False
                
        except Exception as e:
            print(f"✗ IP阻止解除失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return False
            
    def _log_auth_event(self, event_type: str, client_id: str = None, client_ip: str = None):
        """
        记录认证事件
        
        Args:
            event_type: 事件类型
            client_id: 客户端ID（可选）
            client_ip: 客户端IP（可选）
        """
        try:
            if not self.auth_config["enable_audit_logging"]:
                return
                
            event = {
                "event_type": event_type,
                "client_id": client_id,
                "client_ip": client_ip,
                "timestamp": time.time()
            }
            
            # 在实际实现中，这里会将事件记录到日志文件或数据库
            print(f"[认证日志] {event_type} - 客户端: {client_id}, IP: {client_ip}")
            
        except Exception as e:
            print(f"✗ 认证事件记录失败: {e}")
            self.auth_stats["auth_errors"] += 1
            
    def get_active_sessions(self) -> Dict[str, Any]:
        """
        获取活跃会话
        
        Returns:
            活跃会话字典
        """
        try:
            return self.sessions.copy()
        except Exception as e:
            print(f"✗ 获取活跃会话失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return {}
            
    def get_blocked_ips(self) -> Dict[str, Any]:
        """
        获取被阻止的IP地址
        
        Returns:
            被阻止的IP地址字典
        """
        try:
            return self.blocked_ips.copy()
        except Exception as e:
            print(f"✗ 获取被阻止的IP地址失败: {e}")
            self.auth_stats["auth_errors"] += 1
            return {}
            
    def get_auth_stats(self) -> Dict[str, Any]:
        """
        获取认证统计信息
        
        Returns:
            认证统计字典
        """
        return {
            "state": self.auth_state.copy(),
            "stats": self.auth_stats.copy(),
            "config": self.auth_config.copy()
        }
        
    def reset_stats(self):
        """重置认证统计信息"""
        try:
            self.auth_stats = {
                "tokens_generated": 0,
                "sessions_created": 0,
                "sessions_expired": 0,
                "users_banned": 0,
                "auth_errors": 0
            }
            print("✓ 认证统计信息已重置")
        except Exception as e:
            print(f"✗ 认证统计信息重置失败: {e}")
            
    def set_auth_config(self, config: Dict[str, Any]) -> bool:
        """
        设置认证配置
        
        Args:
            config: 认证配置字典
            
        Returns:
            是否设置成功
        """
        try:
            self.auth_config.update(config)
            print(f"✓ 认证配置已更新: {self.auth_config}")
            return True
        except Exception as e:
            print(f"✗ 认证配置设置失败: {e}")
            return False
            
    def get_auth_config(self) -> Dict[str, Any]:
        """
        获取认证配置
        
        Returns:
            认证配置字典
        """
        return self.auth_config.copy()
        
    def _trigger_auth_callback(self, callback_type: str, data: Dict[str, Any]):
        """
        触发认证回调
        
        Args:
            callback_type: 回调类型
            data: 回调数据
        """
        try:
            if callback_type in self.auth_callbacks:
                for callback in self.auth_callbacks[callback_type]:
                    try:
                        callback(data)
                    except Exception as e:
                        print(f"✗ 认证回调执行失败: {callback_type} - {e}")
        except Exception as e:
            print(f"✗ 认证回调触发失败: {e}")
            
    def register_auth_callback(self, callback_type: str, callback: callable):
        """
        注册认证回调
        
        Args:
            callback_type: 回调类型
            callback: 回调函数
        """
        try:
            if callback_type in self.auth_callbacks:
                self.auth_callbacks[callback_type].append(callback)
                print(f"✓ 认证回调已注册: {callback_type}")
            else:
                print(f"✗ 无效的回调类型: {callback_type}")
        except Exception as e:
            print(f"✗ 认证回调注册失败: {e}")
            
    def unregister_auth_callback(self, callback_type: str, callback: callable):
        """
        注销认证回调
        
        Args:
            callback_type: 回调类型
            callback: 回调函数
        """
        try:
            if callback_type in self.auth_callbacks:
                if callback in self.auth_callbacks[callback_type]:
                    self.auth_callbacks[callback_type].remove(callback)
                    print(f"✓ 认证回调已注销: {callback_type}")
            else:
                print(f"✗ 无效的回调类型: {callback_type}")
        except Exception as e:
            print(f"✗ 认证回调注销失败: {e}")