"""
地形优化和LOD系统
提供完整的地形优化功能，包括LOD控制、碰撞优化、渲染优化和性能监控
"""

from panda3d.core import BitMask32, GeoMipTerrain
import time
import psutil
import gc

class TerrainOptimization:
    """
    地形优化和LOD系统类
    提供完整的地形优化功能
    """
    
    def __init__(self, world):
        self.world = world
        self.lod_enabled = True
        self.lod_threshold = 50.0
        self.min_block_size = 16
        self.max_block_size = 64
        self.auto_lod_enabled = True
        self.performance_monitoring = True
        self.last_optimization_time = 0
        
    def enable_lod(self, enabled=True):
        """
        启用或禁用LOD
        """
        self.lod_enabled = enabled
        print(f"LOD系统已{'启用' if enabled else '禁用'}")
        
    def set_lod_threshold(self, threshold):
        """
        设置LOD阈值
        """
        self.lod_threshold = max(1.0, min(1000.0, float(threshold)))
        print(f"LOD阈值设置为: {self.lod_threshold}")
        
    def set_auto_lod(self, enabled=True):
        """
        启用或禁用自动LOD调整
        """
        self.auto_lod_enabled = enabled
        print(f"自动LOD调整已{'启用' if enabled else '禁用'}")
        
    def update_terrain_lod(self, terrain_info):
        """
        更新单个地形的LOD
        """
        if not self.lod_enabled:
            return
            
        try:
            if terrain_info in self.world.terrain_manager.terrains:
                terrain = terrain_info['terrain']
                if hasattr(terrain, 'setNearFarThreshold'):
                    # 设置LOD阈值
                    near_threshold = self.lod_threshold
                    far_threshold = self.lod_threshold * 2
                    terrain.setNearFarThreshold(near_threshold, far_threshold)
                    
                    # 如果启用自动LOD，根据距离动态调整
                    if self.auto_lod_enabled:
                        distance = self._calculate_terrain_distance(terrain_info)
                        if distance > 200:
                            # 远距离时使用更大的块
                            block_size = min(self.max_block_size, int(distance / 10))
                        else:
                            # 近距离时使用更小的块
                            block_size = max(self.min_block_size, int(64 - distance / 5))
                            
                        self.set_terrain_block_size(terrain_info, block_size)
                        
        except Exception as e:
            print(f"更新地形LOD时出错: {e}")
            
    def update_all_terrains_lod(self):
        """
        更新所有地形的LOD
        """
        if not self.lod_enabled:
            return
            
        if hasattr(self.world, 'terrain_manager'):
            for terrain_info in self.world.terrain_manager.terrains:
                self.update_terrain_lod(terrain_info)
                
    def optimize_terrain_collision(self, terrain_info):
        """
        优化地形碰撞体
        """
        try:
            terrain_node = terrain_info['node']
            if terrain_node:
                # 清除现有的碰撞体
                for child in terrain_node.getChildren():
                    if child.getName().startswith("terrain_collision_"):
                        child.removeNode()
                        
                # 设置地形节点的碰撞掩码
                terrain_node.setCollideMask(BitMask32.bit(2))
                
                # 为地形的所有子节点也设置碰撞掩码
                for child in terrain_node.getChildren():
                    child.setCollideMask(BitMask32.bit(2))
                    
                # 如果地形很大，可以考虑创建简化的碰撞网格
                if self._should_simplify_collision(terrain_info):
                    self._create_simplified_collision(terrain_info)
                    
                print("地形碰撞体已优化")
                return True
        except Exception as e:
            print(f"优化地形碰撞体时出错: {e}")
            return False
            
    def _should_simplify_collision(self, terrain_info):
        """
        判断是否需要简化碰撞体
        """
        try:
            heightfield = terrain_info.get('heightfield')
            if heightfield:
                width = heightfield.getXSize()
                height = heightfield.getYSize()
                # 如果地形分辨率很高，考虑简化碰撞
                return width > 256 or height > 256
            return False
        except:
            return False
            
    def _create_simplified_collision(self, terrain_info):
        """
        创建简化的碰撞体
        """
        print("创建简化的地形碰撞体")
        # 这里可以实现创建低分辨率碰撞网格的逻辑
        
    def optimize_terrain_rendering(self, terrain_info):
        """
        优化地形渲染
        """
        try:
            terrain_node = terrain_info['node']
            if terrain_node:
                # 如果使用RenderPipeline，应用优化效果
                if hasattr(self.world, 'render_pipeline'):
                    try:
                        # 根据距离选择不同的效果
                        distance = self._calculate_terrain_distance(terrain_info)
                        if distance > 100:
                            # 远距离使用简化效果
                            effect_file = "effects/terrain_far.yaml"
                        else:
                            # 近距离使用高质量效果
                            effect_file = "effects/terrain_near.yaml"
                            
                        self.world.render_pipeline.set_effect(
                            terrain_node,
                            effect_file,
                            {
                                "normal_mapping": distance < 50,  # 近距离启用法线贴图
                                "parallax_mapping": distance < 30,  # 很近距离启用视差贴图
                                "lod_rendering": self.lod_enabled,
                                "distance": distance
                            },
                            15  # 排序值
                        )
                        print(f"应用优化的地形渲染效果: {effect_file}")
                    except Exception as e:
                        print(f"应用优化渲染效果失败: {e}")
                        
                # 设置渲染优先级
                terrain_node.setBin("background", 0)
                terrain_node.setDepthWrite(True)
                
                return True
        except Exception as e:
            print(f"优化地形渲染时出错: {e}")
            return False
            
    def get_terrain_performance_stats(self, terrain_info):
        """
        获取地形性能统计信息
        """
        stats = {
            'lod_enabled': self.lod_enabled,
            'lod_threshold': self.lod_threshold,
            'vertices': 0,
            'triangles': 0,
            'memory_usage': 0,
            'block_size': 32,
            'distance': 0
        }
        
        try:
            terrain = terrain_info['terrain']
            if terrain:
                # 获取地形几何信息
                if hasattr(terrain, 'getRoot'):
                    root_node = terrain.getRoot()
                    if root_node:
                        # 估算顶点和三角形数量
                        heightfield = terrain_info.get('heightfield')
                        if heightfield:
                            width = heightfield.getXSize()
                            height = heightfield.getYSize()
                            stats['vertices'] = width * height
                            stats['triangles'] = (width - 1) * (height - 1) * 2
                            
                # 获取块大小
                if hasattr(terrain, 'getBlockSize'):
                    stats['block_size'] = terrain.getBlockSize()
                    
                # 计算距离
                stats['distance'] = self._calculate_terrain_distance(terrain_info)
                        
        except Exception as e:
            print(f"获取地形性能统计时出错: {e}")
            
        return stats
        
    def auto_optimize_terrains(self):
        """
        自动优化所有地形
        """
        if not hasattr(self.world, 'terrain_manager'):
            return
            
        # 检查是否需要优化（避免过于频繁的优化）
        current_time = time.time()
        if current_time - self.last_optimization_time < 1.0:  # 至少间隔1秒
            return
            
        self.last_optimization_time = current_time
        
        optimized_count = 0
        for terrain_info in self.world.terrain_manager.terrains:
            # 优化碰撞体
            if self.optimize_terrain_collision(terrain_info):
                optimized_count += 1
                
            # 优化渲染
            if self.optimize_terrain_rendering(terrain_info):
                optimized_count += 1
                
            # 更新LOD
            self.update_terrain_lod(terrain_info)
            
        # 更新所有地形的LOD
        self.update_all_terrains_lod()
        
        # 执行垃圾回收
        if optimized_count > 0:
            gc.collect()
            
        print(f"自动优化完成，优化了 {optimized_count} 个项目")
        
    def set_terrain_block_size(self, terrain_info, block_size):
        """
        设置地形块大小（影响LOD效果）
        """
        try:
            # 限制块大小范围
            block_size = max(self.min_block_size, min(self.max_block_size, int(block_size)))
            
            terrain = terrain_info['terrain']
            if hasattr(terrain, 'setBlockSize'):
                terrain.setBlockSize(block_size)
                print(f"地形块大小设置为: {block_size}")
                return True
        except Exception as e:
            print(f"设置地形块大小时出错: {e}")
            return False
        return False
        
    def set_block_size_range(self, min_size, max_size):
        """
        设置块大小范围
        """
        self.min_block_size = max(8, min(128, int(min_size)))
        self.max_block_size = max(8, min(128, int(max_size)))
        print(f"地形块大小范围设置为: {self.min_block_size} - {self.max_block_size}")
        
    def _calculate_terrain_distance(self, terrain_info):
        """
        计算地形到相机的距离
        """
        try:
            terrain_node = terrain_info['node']
            if terrain_node and hasattr(self.world, 'cam'):
                terrain_pos = terrain_node.getPos()
                camera_pos = self.world.cam.getPos()
                distance = (terrain_pos - camera_pos).length()
                return distance
            return 50.0  # 默认距离
        except:
            return 50.0
            
    def enable_performance_monitoring(self, enabled=True):
        """
        启用或禁用性能监控
        """
        self.performance_monitoring = enabled
        print(f"性能监控已{'启用' if enabled else '禁用'}")
        
    def get_system_performance_stats(self):
        """
        获取系统性能统计信息
        """
        try:
            # 获取内存使用情况
            process = psutil.Process()
            memory_info = process.memory_info()
            
            # 获取CPU使用率
            cpu_percent = process.cpu_percent()
            
            return {
                'memory_rss': memory_info.rss,
                'memory_vms': memory_info.vms,
                'cpu_percent': cpu_percent,
                'terrain_count': len(self.world.terrain_manager.terrains) if hasattr(self.world, 'terrain_manager') else 0
            }
        except Exception as e:
            print(f"获取系统性能统计时出错: {e}")
            return {}
            
    def optimize_memory_usage(self):
        """
        优化内存使用
        """
        try:
            # 执行垃圾回收
            collected = gc.collect()
            print(f"执行垃圾回收，清理了 {collected} 个对象")
            
            # 优化纹理内存使用
            if hasattr(self.world, 'texture_cache'):
                self.world.texture_cache.clear_unused()
                
            return True
        except Exception as e:
            print(f"优化内存使用时出错: {e}")
            return False
            
    def set_render_distance(self, distance):
        """
        设置渲染距离
        """
        try:
            if hasattr(self.world, 'camLens'):
                self.world.camLens.setNearFar(0.1, float(distance))
                print(f"渲染距离设置为: {distance}")
                return True
        except Exception as e:
            print(f"设置渲染距离时出错: {e}")
            return False
        return False
        
    def enable_frustum_culling(self, enabled=True):
        """
        启用或禁用视锥体剔除
        """
        try:
            if hasattr(self.world, 'terrain_manager'):
                for terrain_info in self.world.terrain_manager.terrains:
                    terrain_node = terrain_info['node']
                    if terrain_node:
                        if enabled:
                            terrain_node.setAttrib(CullFaceAttrib.makePanda())
                        else:
                            terrain_node.clearAttrib(CullFaceAttrib.getClassType())
                            
                print(f"视锥体剔除已{'启用' if enabled else '禁用'}")
                return True
        except Exception as e:
            print(f"设置视锥体剔除时出错: {e}")
            return False
        return False