"""
导航网格优化器
提供自动优化导航网格的功能，包括多边形合并、简化和重构
"""

import math
from typing import List, Dict, Set, Tuple, Optional
from panda3d.core import Point3

class NavMeshOptimizer:
    """
    导航网格优化器
    提供自动优化导航网格的功能
    """
    
    def __init__(self, navmesh_manager):
        """
        初始化导航网格优化器
        
        Args:
            navmesh_manager: 导航网格管理器实例
        """
        self.navmesh_manager = navmesh_manager
        self.optimization_settings = {
            'merge_threshold': 0.5,  # 合并阈值
            'simplify_threshold': 0.1,  # 简化阈值
            'min_polygon_area': 0.01,  # 最小多边形面积
            'max_vertices_per_polygon': 8,  # 每个多边形最大顶点数
            'preserve_boundaries': True,  # 是否保留边界
            'preserve_portals': True  # 是否保留门户点
        }
        
    def set_optimization_settings(self, settings: Dict):
        """
        设置优化参数
        
        Args:
            settings: 优化参数字典
        """
        self.optimization_settings.update(settings)
        
    def get_optimization_settings(self) -> Dict:
        """
        获取优化参数
        
        Returns:
            优化参数字典
        """
        return self.optimization_settings.copy()
        
    def merge_adjacent_polygons(self) -> int:
        """
        合并相邻的多边形
        
        Returns:
            合并的多边形数量
        """
        if not self.navmesh_manager or not self.navmesh_manager.polygons:
            return 0
            
        merged_count = 0
        processed_polygons = set()
        
        # 创建多边形ID列表的副本，避免在迭代时修改字典
        polygon_ids = list(self.navmesh_manager.polygons.keys())
        
        for polygon_id in polygon_ids:
            if polygon_id in processed_polygons:
                continue
                
            if polygon_id not in self.navmesh_manager.polygons:
                continue
                
            polygon = self.navmesh_manager.polygons[polygon_id]
            
            # 检查是否可以与其他多边形合并
            for neighbor_id in polygon.neighbors[:]:  # 使用副本避免修改时的问题
                if neighbor_id in processed_polygons:
                    continue
                    
                if neighbor_id not in self.navmesh_manager.polygons:
                    continue
                    
                neighbor = self.navmesh_manager.polygons[neighbor_id]
                
                # 检查合并条件
                if self._can_merge_polygons(polygon, neighbor):
                    # 执行合并
                    if self._merge_two_polygons(polygon_id, neighbor_id):
                        merged_count += 1
                        processed_polygons.add(polygon_id)
                        processed_polygons.add(neighbor_id)
                        break
                        
        # 重新计算连接关系
        if merged_count > 0:
            self.navmesh_manager._calculate_polygon_connections()
            self.navmesh_manager._calculate_portal_points()
            self.navmesh_manager._update_navmesh_visualization()
            
        return merged_count
        
    def _can_merge_polygons(self, polygon1, polygon2) -> bool:
        """
        检查两个多边形是否可以合并
        
        Args:
            polygon1: 第一个多边形
            polygon2: 第二个多边形
            
        Returns:
            是否可以合并
        """
        # 检查是否有共享边
        if not self._polygons_share_full_edge(polygon1, polygon2):
            return False
            
        # 检查合并后的多边形是否过于复杂
        merged_vertices = self._get_merged_vertices(polygon1, polygon2)
        if len(merged_vertices) > self.optimization_settings['max_vertices_per_polygon']:
            return False
            
        # 检查面积
        merged_area = self._calculate_polygon_area(merged_vertices)
        if merged_area < self.optimization_settings['min_polygon_area']:
            return False
            
        return True
        
    def _polygons_share_full_edge(self, polygon1, polygon2) -> bool:
        """
        检查两个多边形是否共享完整的一条边
        
        Args:
            polygon1: 第一个多边形
            polygon2: 第二个多边形
            
        Returns:
            是否共享完整边
        """
        threshold = 0.01  # 点重合阈值
        
        # 检查polygon1的每条边
        for i in range(len(polygon1.vertices)):
            v1_start = polygon1.vertices[i]
            v1_end = polygon1.vertices[(i + 1) % len(polygon1.vertices)]
            
            # 检查polygon2的每条边
            for j in range(len(polygon2.vertices)):
                v2_start = polygon2.vertices[j]
                v2_end = polygon2.vertices[(j + 1) % len(polygon2.vertices)]
                
                # 检查边是否重合（方向相同）
                if (self._points_equal(v1_start, v2_start, threshold) and 
                    self._points_equal(v1_end, v2_end, threshold)):
                    return True
                    
                # 检查边是否重合（方向相反）
                if (self._points_equal(v1_start, v2_end, threshold) and 
                    self._points_equal(v1_end, v2_start, threshold)):
                    return True
                    
        return False
        
    def _points_equal(self, p1: Point3, p2: Point3, threshold: float) -> bool:
        """检查两点是否相等（在阈值范围内）"""
        return (p1 - p2).length() < threshold
        
    def _get_merged_vertices(self, polygon1, polygon2) -> List[Point3]:
        """
        获取两个多边形合并后的顶点
        
        Args:
            polygon1: 第一个多边形
            polygon2: 第二个多边形
            
        Returns:
            合并后的顶点列表
        """
        # 这是一个简化的实现
        # 实际应用中需要正确处理多边形合并的几何运算
        merged_vertices = []
        merged_vertices.extend(polygon1.vertices)
        merged_vertices.extend(polygon2.vertices)
        return merged_vertices
        
    def _calculate_polygon_area(self, vertices: List[Point3]) -> float:
        """计算多边形面积（使用鞋带公式）"""
        if len(vertices) < 3:
            return 0.0
            
        area = 0.0
        n = len(vertices)
        for i in range(n):
            j = (i + 1) % n
            area += vertices[i].x * vertices[j].z
            area -= vertices[j].x * vertices[i].z
        return abs(area) / 2.0
        
    def _merge_two_polygons(self, polygon1_id: int, polygon2_id: int) -> bool:
        """
        合并两个多边形
        
        Args:
            polygon1_id: 第一个多边形ID
            polygon2_id: 第二个多边形ID
            
        Returns:
            是否合并成功
        """
        try:
            if (polygon1_id not in self.navmesh_manager.polygons or
                polygon2_id not in self.navmesh_manager.polygons):
                return False
                
            polygon1 = self.navmesh_manager.polygons[polygon1_id]
            polygon2 = self.navmesh_manager.polygons[polygon2_id]
            
            # 创建合并后的新多边形
            merged_vertices = self._merge_polygon_vertices(polygon1, polygon2)
            if not merged_vertices:
                return False
                
            # 移除旧的多边形
            self.navmesh_manager.remove_polygon(polygon2_id)
            
            # 更新第一个多边形
            polygon1.vertices = merged_vertices
            polygon1.center = polygon1._calculate_center()
            polygon1.area = polygon1._calculate_area()
            polygon1.bounding_box = polygon1._calculate_bounding_box()
            
            return True
            
        except Exception as e:
            print(f"合并多边形失败: {e}")
            return False
            
    def _merge_polygon_vertices(self, polygon1, polygon2) -> List[Point3]:
        """
        合并两个多边形的顶点
        
        Args:
            polygon1: 第一个多边形
            polygon2: 第二个多边形
            
        Returns:
            合并后的顶点列表
        """
        # 这是一个简化的实现
        # 实际应用中需要正确处理多边形合并的几何运算
        # 包括移除共享边，正确排序顶点等
        
        # 简单合并所有顶点
        merged_vertices = []
        merged_vertices.extend(polygon1.vertices)
        merged_vertices.extend(polygon2.vertices)
        
        # 去除重复顶点（简化处理）
        unique_vertices = []
        for vertex in merged_vertices:
            is_duplicate = False
            for existing_vertex in unique_vertices:
                if self._points_equal(vertex, existing_vertex, 0.01):
                    is_duplicate = True
                    break
            if not is_duplicate:
                unique_vertices.append(vertex)
                
        return unique_vertices[:self.optimization_settings['max_vertices_per_polygon']]
        
    def simplify_polygons(self) -> int:
        """
        简化多边形（移除不必要的顶点）
        
        Returns:
            简化的顶点数量
        """
        if not self.navmesh_manager or not self.navmesh_manager.polygons:
            return 0
            
        simplified_count = 0
        
        for polygon in self.navmesh_manager.polygons.values():
            original_vertex_count = len(polygon.vertices)
            simplified_vertices = self._simplify_polygon(polygon.vertices)
            
            if len(simplified_vertices) < original_vertex_count:
                polygon.vertices = simplified_vertices
                polygon.center = polygon._calculate_center()
                polygon.area = polygon._calculate_area()
                polygon.bounding_box = polygon._calculate_bounding_box()
                simplified_count += original_vertex_count - len(simplified_vertices)
                
        # 重新计算连接关系
        if simplified_count > 0:
            self.navmesh_manager._calculate_polygon_connections()
            self.navmesh_manager._calculate_portal_points()
            self.navmesh_manager._update_navmesh_visualization()
            
        return simplified_count
        
    def _simplify_polygon(self, vertices: List[Point3]) -> List[Point3]:
        """
        简化单个多边形
        
        Args:
            vertices: 多边形顶点列表
            
        Returns:
            简化后的顶点列表
        """
        if len(vertices) <= 3:
            return vertices
            
        simplified = [vertices[0]]  # 保留第一个顶点
        i = 0
        
        while i < len(vertices):
            # 找到下一个需要保留的顶点
            next_i = self._find_next_significant_vertex(vertices, i)
            if next_i >= len(vertices):
                break
                
            simplified.append(vertices[next_i])
            i = next_i
            
        # 确保至少有3个顶点
        if len(simplified) < 3:
            return vertices[:3]
            
        return simplified
        
    def _find_next_significant_vertex(self, vertices: List[Point3], start_index: int) -> int:
        """
        找到下一个重要的顶点（需要保留的顶点）
        
        Args:
            vertices: 顶点列表
            start_index: 起始索引
            
        Returns:
            下一个重要顶点的索引
        """
        threshold = self.optimization_settings['simplify_threshold']
        
        # 简化处理：每隔几个顶点保留一个
        step = max(1, int(len(vertices) / 8))  # 保持最多8个顶点
        next_index = min(start_index + step, len(vertices) - 1)
        
        return next_index
        
    def remove_small_polygons(self) -> int:
        """
        移除极小的多边形
        
        Returns:
            移除的多边形数量
        """
        if not self.navmesh_manager or not self.navmesh_manager.polygons:
            return 0
            
        min_area = self.optimization_settings['min_polygon_area']
        removed_count = 0
        
        # 创建需要移除的多边形ID列表
        to_remove = []
        for polygon_id, polygon in self.navmesh_manager.polygons.items():
            if polygon.area < min_area:
                to_remove.append(polygon_id)
                
        # 移除多边形
        for polygon_id in to_remove:
            self.navmesh_manager.remove_polygon(polygon_id)
            removed_count += 1
            
        # 更新连接关系
        if removed_count > 0:
            self.navmesh_manager._calculate_polygon_connections()
            self.navmesh_manager._calculate_portal_points()
            self.navmesh_manager._update_navmesh_visualization()
            
        return removed_count
        
    def optimize_mesh(self, optimization_level: str = 'medium') -> Dict:
        """
        执行完整的网格优化
        
        Args:
            optimization_level: 优化级别 ('light', 'medium', 'heavy')
            
        Returns:
            优化结果统计
        """
        results = {
            'merged_polygons': 0,
            'simplified_vertices': 0,
            'removed_polygons': 0,
            'total_optimizations': 0
        }
        
        # 根据优化级别设置参数
        if optimization_level == 'heavy':
            self.optimization_settings['merge_threshold'] = 0.3
            self.optimization_settings['simplify_threshold'] = 0.2
            self.optimization_settings['min_polygon_area'] = 0.05
        elif optimization_level == 'light':
            self.optimization_settings['merge_threshold'] = 0.7
            self.optimization_settings['simplify_threshold'] = 0.05
            self.optimization_settings['min_polygon_area'] = 0.005
            
        # 执行优化步骤
        if optimization_level in ['medium', 'heavy']:
            results['merged_polygons'] = self.merge_adjacent_polygons()
            
        results['simplified_vertices'] = self.simplify_polygons()
        results['removed_polygons'] = self.remove_small_polygons()
        
        results['total_optimizations'] = (results['merged_polygons'] + 
                                        results['simplified_vertices'] + 
                                        results['removed_polygons'])
        
        return results
        
    def fill_gaps(self) -> int:
        """
        填补导航网格中的空隙
        
        Returns:
            填补的多边形数量
        """
        # 这是一个复杂的功能，需要分析未覆盖的区域并生成新的多边形
        # 简化实现：返回0
        return 0
        
    def smooth_boundaries(self) -> int:
        """
        平滑多边形边界
        
        Returns:
            平滑处理的边数
        """
        # 这需要复杂的几何运算来平滑多边形边界
        # 简化实现：返回0
        return 0
        
    def balance_polygon_sizes(self) -> int:
        """
        平衡多边形大小
        
        Returns:
            调整的多边形数量
        """
        # 这需要分析多边形大小分布并调整过大或过小的多边形
        # 简化实现：返回0
        return 0