"""
Morphing和变形动画插件 - 网络同步模块
提供多人环境中动画状态的同步功能
"""

import json
import time
from typing import Dict, List, Tuple, Optional, Any, Callable
from dataclasses import dataclass, field
from enum import Enum

from panda3d.core import *
from direct.distributed.ClockDelta import globalClockDelta
from direct.showbase.DirectObject import DirectObject

# 导入核心模块
from .core import MorphingCore

# 定义常量
NETWORK_SETTINGS = {
    'sync_interval': 0.1,
    'interpolation_buffer': 0.1,
    'max_buffer_size': 100,
    'enable_compression': True
}

# 枚举定义
class NetworkMode(Enum):
    """网络模式枚举"""
    DISABLED = 0      # 禁用
    SERVER = 1        # 服务器模式
    CLIENT = 2        # 客户端模式
    PEER_TO_PEER = 3  # 点对点模式

class SyncMode(Enum):
    """同步模式枚举"""
    STATE_SYNC = 0        # 状态同步
    INPUT_SYNC = 1        # 输入同步
    INTERPOLATION = 2     # 插值同步

class InterpolationMode(Enum):
    """插值模式枚举"""
    LINEAR = 0            # 线性插值
    SPLINE = 1            # 样条插值
    HERMITE = 2           # 埃尔米特插值

@dataclass
class NetworkState:
    """网络状态数据类"""
    model_id: str
    morph_weights: Dict[str, float]  # {target_name: weight}
    timestamp: float
    sequence_number: int

@dataclass
class StateBufferEntry:
    """状态缓冲区条目"""
    state: NetworkState
    received_time: float

@dataclass
class NetworkConfig:
    """网络配置数据类"""
    mode: NetworkMode = NetworkMode.DISABLED
    sync_mode: SyncMode = SyncMode.STATE_SYNC
    sync_interval: float = NETWORK_SETTINGS['sync_interval']
    interpolation_mode: InterpolationMode = InterpolationMode.LINEAR
    enable_compression: bool = NETWORK_SETTINGS['enable_compression']
    max_buffer_size: int = NETWORK_SETTINGS['max_buffer_size']

class AnimationNetworkSync(DirectObject):
    """
    动画网络同步系统
    处理网络环境中的动画同步
    """
    
    def __init__(self, world, morphing_core: MorphingCore):
        """
        初始化动画网络同步系统
        :param world: 世界对象
        :param morphing_core: Morphing核心系统
        """
        super().__init__()
        self.world = world
        self.morphing_core = morphing_core
        self.config = NetworkConfig()
        self.network_id_map: Dict[str, str] = {}  # {local_model_id: network_id}
        self.local_id_map: Dict[str, str] = {}    # {network_id: local_model_id}
        self.state_buffers: Dict[str, List[StateBufferEntry]] = {}  # {network_id: [StateBufferEntry]}
        self.sequence_numbers: Dict[str, int] = {}  # {network_id: sequence_number}
        self.is_syncing = False
        self.sync_task = None
        self.last_sync_time = 0.0
        self.network_interface = None  # 网络接口（需要根据具体网络库实现）
        
        print("动画网络同步系统初始化完成")
        
    def set_network_mode(self, mode: NetworkMode) -> None:
        """
        设置网络模式
        :param mode: 网络模式
        """
        self.config.mode = mode
        print(f"网络模式设置为: {mode.name}")
        
    def set_sync_mode(self, mode: SyncMode) -> None:
        """
        设置同步模式
        :param mode: 同步模式
        """
        self.config.sync_mode = mode
        print(f"同步模式设置为: {mode.name}")
        
    def set_sync_interval(self, interval: float) -> None:
        """
        设置同步间隔
        :param interval: 同步间隔（秒）
        """
        self.config.sync_interval = interval
        print(f"同步间隔设置为: {interval}秒")
        
    def set_interpolation_mode(self, mode: InterpolationMode) -> None:
        """
        设置插值模式
        :param mode: 插值模式
        """
        self.config.interpolation_mode = mode
        print(f"插值模式设置为: {mode.name}")
        
    def enable_compression(self, enabled: bool = True) -> None:
        """
        启用/禁用压缩
        :param enabled: 是否启用
        """
        self.config.enable_compression = enabled
        print(f"压缩已{'启用' if enabled else '禁用'}")
        
    def register_model_for_sync(self, model_id: str, network_id: Optional[str] = None) -> str:
        """
        注册模型以进行网络同步
        :param model_id: 本地模型ID
        :param network_id: 网络ID，如果为None则自动生成
        :return: 网络ID
        """
        if self.config.mode == NetworkMode.DISABLED:
            print("错误: 网络同步已禁用")
            return ""
            
        if model_id not in self.morphing_core.model_data:
            print(f"错误: 模型 {model_id} 未注册到Morphing核心系统")
            return ""
            
        if network_id is None:
            network_id = f"net_model_{len(self.network_id_map)}"
            
        # 检查ID是否已存在
        if network_id in self.local_id_map:
            print(f"警告: 网络ID {network_id} 已存在，将被替换")
            old_local_id = self.local_id_map[network_id]
            if old_local_id in self.network_id_map:
                del self.network_id_map[old_local_id]
                
        # 建立映射关系
        self.network_id_map[model_id] = network_id
        self.local_id_map[network_id] = model_id
        
        # 初始化状态缓冲区
        self.state_buffers[network_id] = []
        self.sequence_numbers[network_id] = 0
        
        print(f"模型已注册网络同步: {model_id} -> {network_id}")
        return network_id
        
    def unregister_model_from_sync(self, model_id: str) -> bool:
        """
        从网络同步中注销模型
        :param model_id: 本地模型ID
        :return: 是否成功注销
        """
        if model_id not in self.network_id_map:
            print(f"错误: 模型 {model_id} 未注册网络同步")
            return False
            
        network_id = self.network_id_map[model_id]
        
        # 清理相关数据
        del self.network_id_map[model_id]
        if network_id in self.local_id_map:
            del self.local_id_map[network_id]
        if network_id in self.state_buffers:
            del self.state_buffers[network_id]
        if network_id in self.sequence_numbers:
            del self.sequence_numbers[network_id]
            
        print(f"模型已注销网络同步: {model_id} -> {network_id}")
        return True
        
    def send_model_state(self, model_id: str) -> bool:
        """
        发送模型状态
        :param model_id: 本地模型ID
        :return: 是否成功发送
        """
        if self.config.mode not in [NetworkMode.SERVER, NetworkMode.PEER_TO_PEER]:
            print("错误: 当前网络模式不支持发送状态")
            return False
            
        if model_id not in self.network_id_map:
            print(f"错误: 模型 {model_id} 未注册网络同步")
            return False
            
        network_id = self.network_id_map[model_id]
        
        # 获取模型的当前状态
        morph_weights = {}
        if model_id in self.morphing_core.morph_targets:
            for target_name, morph_target in self.morphing_core.morph_targets[model_id].items():
                # 使用平均权重作为代表值
                if morph_target.weights:
                    morph_weights[target_name] = sum(morph_target.weights) / len(morph_target.weights)
                    
        # 创建网络状态
        state = NetworkState(
            model_id=network_id,
            morph_weights=morph_weights,
            timestamp=globalClockDelta.getRealNetworkTime(bits=32),
            sequence_number=self.sequence_numbers.get(network_id, 0)
        )
        
        # 更新序列号
        self.sequence_numbers[network_id] = self.sequence_numbers.get(network_id, 0) + 1
        
        # 压缩状态数据（如果启用）
        state_data = self._serialize_state(state)
        if self.config.enable_compression:
            state_data = self._compress_state_data(state_data)
            
        # 发送状态数据（需要根据具体网络库实现）
        if self.network_interface:
            try:
                self.network_interface.send_state(network_id, state_data)
                print(f"模型状态已发送: {model_id} -> {network_id}")
                return True
            except Exception as e:
                print(f"发送模型状态时出错: {e}")
                return False
        else:
            # 模拟发送（用于测试）
            print(f"模拟发送模型状态: {model_id} -> {network_id}")
            print(f"  状态数据: {state_data}")
            return True
            
    def receive_model_state(self, network_id: str, state_data: bytes) -> bool:
        """
        接收模型状态
        :param network_id: 网络ID
        :param state_data: 状态数据
        :return: 是否成功接收
        """
        if self.config.mode not in [NetworkMode.CLIENT, NetworkMode.PEER_TO_PEER]:
            print("错误: 当前网络模式不支持接收状态")
            return False
            
        if network_id not in self.local_id_map:
            print(f"警告: 未知的网络ID {network_id}，忽略状态数据")
            return False
            
        local_id = self.local_id_map[network_id]
        
        # 解压缩状态数据（如果启用）
        if self.config.enable_compression:
            state_data = self._decompress_state_data(state_data)
            
        # 反序列化状态
        state = self._deserialize_state(state_data)
        if not state:
            print(f"错误: 无法反序列化状态数据")
            return False
            
        # 验证序列号
        last_sequence = self.sequence_numbers.get(network_id, -1)
        if state.sequence_number <= last_sequence:
            print(f"警告: 过期的状态数据 (序列号: {state.sequence_number} <= {last_sequence})")
            return False
            
        # 更新序列号
        self.sequence_numbers[network_id] = state.sequence_number
        
        # 添加到状态缓冲区
        buffer_entry = StateBufferEntry(
            state=state,
            received_time=globalClock.getRealTime()
        )
        
        if network_id not in self.state_buffers:
            self.state_buffers[network_id] = []
            
        self.state_buffers[network_id].append(buffer_entry)
        
        # 限制缓冲区大小
        if len(self.state_buffers[network_id]) > self.config.max_buffer_size:
            self.state_buffers[network_id].pop(0)
            
        # 应用状态（根据同步模式）
        if self.config.sync_mode == SyncMode.STATE_SYNC:
            self._apply_state_immediately(local_id, state)
        elif self.config.sync_mode == SyncMode.INTERPOLATION:
            # 插值模式下暂不立即应用，等待插值更新
            pass
            
        print(f"模型状态已接收: {network_id} -> {local_id}")
        return True
        
    def _serialize_state(self, state: NetworkState) -> bytes:
        """
        序列化网络状态
        :param state: 网络状态
        :return: 序列化后的数据
        """
        state_dict = {
            'model_id': state.model_id,
            'morph_weights': state.morph_weights,
            'timestamp': state.timestamp,
            'sequence_number': state.sequence_number
        }
        
        return json.dumps(state_dict).encode('utf-8')
        
    def _deserialize_state(self, state_data: bytes) -> Optional[NetworkState]:
        """
        反序列化网络状态
        :param state_data: 状态数据
        :return: 网络状态对象
        """
        try:
            state_dict = json.loads(state_data.decode('utf-8'))
            
            return NetworkState(
                model_id=state_dict['model_id'],
                morph_weights=state_dict['morph_weights'],
                timestamp=state_dict['timestamp'],
                sequence_number=state_dict['sequence_number']
            )
        except Exception as e:
            print(f"反序列化状态数据时出错: {e}")
            return None
            
    def _compress_state_data(self, state_data: bytes) -> bytes:
        """
        压缩状态数据
        :param state_data: 状态数据
        :return: 压缩后的数据
        """
        # 简化实现，实际项目中可以使用zlib等压缩库
        return state_data
        
    def _decompress_state_data(self, state_data: bytes) -> bytes:
        """
        解压缩状态数据
        :param state_data: 压缩的状态数据
        :return: 解压后的数据
        """
        # 简化实现，实际项目中需要对应解压
        return state_data
        
    def _apply_state_immediately(self, model_id: str, state: NetworkState) -> None:
        """
        立即应用网络状态
        :param model_id: 本地模型ID
        :param state: 网络状态
        """
        # 应用Morph目标权重
        for target_name, weight in state.morph_weights.items():
            self.morphing_core.set_morph_target_weight(model_id, target_name, weight)
            
    def _interpolate_states(self, network_id: str) -> None:
        """
        插值状态
        :param network_id: 网络ID
        """
        if network_id not in self.state_buffers or len(self.state_buffers[network_id]) < 2:
            return
            
        local_id = self.local_id_map[network_id]
        buffer = self.state_buffers[network_id]
        
        # 获取当前时间
        current_time = globalClock.getRealTime()
        interpolation_time = current_time - NETWORK_SETTINGS['interpolation_buffer']
        
        # 找到要插值的两个状态
        prev_state = None
        next_state = None
        
        for entry in buffer:
            if entry.received_time <= interpolation_time:
                prev_state = entry.state
            else:
                next_state = entry.state
                break
                
        if not prev_state or not next_state:
            return
            
        # 计算插值因子
        time_diff = next_state.timestamp - prev_state.timestamp
        if time_diff <= 0:
            return
            
        t = (interpolation_time - prev_state.timestamp) / time_diff
        t = max(0.0, min(1.0, t))  # 限制在0-1范围内
        
        # 根据插值模式调整因子
        if self.config.interpolation_mode == InterpolationMode.SPLINE:
            t = t * t * (3.0 - 2.0 * t)
        elif self.config.interpolation_mode == InterpolationMode.HERMITE:
            t = t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
            
        # 插值Morph目标权重
        all_targets = set(prev_state.morph_weights.keys()) | set(next_state.morph_weights.keys())
        
        for target_name in all_targets:
            prev_weight = prev_state.morph_weights.get(target_name, 0.0)
            next_weight = next_state.morph_weights.get(target_name, 0.0)
            
            # 计算插值权重
            interpolated_weight = prev_weight * (1.0 - t) + next_weight * t
            
            # 应用权重
            self.morphing_core.set_morph_target_weight(local_id, target_name, interpolated_weight)
            
    def start_sync_task(self) -> None:
        """
        启动同步任务
        """
        if self.is_syncing:
            return
            
        self.is_syncing = True
        
        # 启动同步任务
        self.sync_task = self.world.taskMgr.add(
            self._sync_task, 
            "morphing_network_sync",
            sort=40
        )
        
        print("动画网络同步任务已启动")
        
    def stop_sync_task(self) -> None:
        """
        停止同步任务
        """
        if not self.is_syncing:
            return
            
        self.is_syncing = False
        
        # 停止同步任务
        if self.sync_task:
            self.world.taskMgr.remove(self.sync_task)
            self.sync_task = None
            
        print("动画网络同步任务已停止")
        
    def _sync_task(self, task) -> int:
        """
        网络同步任务
        :param task: 任务对象
        :return: 任务状态
        """
        current_time = globalClock.getRealTime()
        
        # 检查同步间隔
        if current_time - self.last_sync_time < self.config.sync_interval:
            return task.cont
            
        self.last_sync_time = current_time
        
        # 根据网络模式执行相应操作
        if self.config.mode == NetworkMode.SERVER:
            # 服务器模式：发送所有注册模型的状态
            for model_id in self.network_id_map.keys():
                self.send_model_state(model_id)
                
        elif self.config.mode == NetworkMode.CLIENT:
            # 客户端模式：接收状态并应用插值（如果启用）
            if self.config.sync_mode == SyncMode.INTERPOLATION:
                for network_id in self.state_buffers.keys():
                    self._interpolate_states(network_id)
                    
        elif self.config.mode == NetworkMode.PEER_TO_PEER:
            # 点对点模式：发送和接收状态
            for model_id in self.network_id_map.keys():
                self.send_model_state(model_id)
                
            if self.config.sync_mode == SyncMode.INTERPOLATION:
                for network_id in self.state_buffers.keys():
                    self._interpolate_states(network_id)
                    
        return task.cont
        
    def get_network_info(self) -> Dict[str, Any]:
        """
        获取网络同步信息
        :return: 网络信息字典
        """
        return {
            'mode': self.config.mode.name,
            'sync_mode': self.config.sync_mode.name,
            'sync_interval': self.config.sync_interval,
            'interpolation_mode': self.config.interpolation_mode.name,
            'compression_enabled': self.config.enable_compression,
            'registered_models': len(self.network_id_map),
            'network_ids': list(self.network_id_map.values()),
            'sync_status': 'active' if self.is_syncing else 'inactive'
        }
        
    def get_model_network_info(self, model_id: str) -> Optional[Dict[str, Any]]:
        """
        获取模型网络信息
        :param model_id: 本地模型ID
        :return: 模型网络信息字典
        """
        if model_id not in self.network_id_map:
            print(f"错误: 模型 {model_id} 未注册网络同步")
            return None
            
        network_id = self.network_id_map[model_id]
        
        return {
            'local_id': model_id,
            'network_id': network_id,
            'sequence_number': self.sequence_numbers.get(network_id, 0),
            'buffer_size': len(self.state_buffers.get(network_id, [])),
            'last_state': self.state_buffers.get(network_id, [])[-1].state if self.state_buffers.get(network_id) else None
        }
        
    def set_network_interface(self, network_interface) -> None:
        """
        设置网络接口
        :param network_interface: 网络接口对象
        """
        self.network_interface = network_interface
        print("网络接口已设置")

# 网络接口基类（需要根据具体网络库实现）
class NetworkInterface:
    """
    网络接口基类
    需要根据具体使用的网络库（如PyNetGames、Panda3D的PyClientRepository等）进行实现
    """
    
    def __init__(self):
        """初始化网络接口"""
        pass
        
    def send_state(self, network_id: str, state_data: bytes) -> bool:
        """
        发送状态数据
        :param network_id: 网络ID
        :param state_data: 状态数据
        :return: 是否成功发送
        """
        # 需要根据具体网络库实现
        raise NotImplementedError("需要在子类中实现send_state方法")
        
    def receive_state(self, network_id: str) -> Optional[bytes]:
        """
        接收状态数据
        :param network_id: 网络ID
        :return: 状态数据
        """
        # 需要根据具体网络库实现
        raise NotImplementedError("需要在子类中实现receive_state方法")
        
    def connect(self, address: str, port: int) -> bool:
        """
        连接到服务器
        :param address: 服务器地址
        :param port: 服务器端口
        :return: 是否成功连接
        """
        # 需要根据具体网络库实现
        raise NotImplementedError("需要在子类中实现connect方法")
        
    def disconnect(self) -> None:
        """
        断开连接
        """
        # 需要根据具体网络库实现
        raise NotImplementedError("需要在子类中实现disconnect方法")

# 使用示例和测试代码
def example_network_usage(world, morphing_core):
    """
    动画网络同步系统使用示例
    """
    print("=== 动画网络同步系统使用示例 ===")
    
    # 创建网络同步系统
    network_sync = AnimationNetworkSync(world, morphing_core)
    
    # 设置网络模式
    network_sync.set_network_mode(NetworkMode.SERVER)
    
    # 设置同步模式
    network_sync.set_sync_mode(SyncMode.STATE_SYNC)
    
    # 设置同步间隔
    network_sync.set_sync_interval(0.05)  # 50ms
    
    # 启用压缩
    network_sync.enable_compression(True)
    
    # 启动同步任务
    network_sync.start_sync_task()
    
    print("网络同步系统配置完成")
    print("=== 动画网络同步系统示例结束 ===\n")
    
    return network_sync

if __name__ == "__main__":
    print("动画网络同步模块加载完成")