"""
导航网格分析工具
提供导航网格质量分析、优化建议和性能评估功能
"""

import math
import time
from typing import List, Dict, Tuple, Optional, Set
from collections import defaultdict, deque
import json
from panda3d.core import Point3

class NavMeshAnalyzer:
    """
    导航网格分析器
    提供导航网格质量分析、优化建议和性能评估功能
    """
    
    def __init__(self, navmesh_manager):
        """
        初始化导航网格分析器
        
        Args:
            navmesh_manager: 导航网格管理器实例
        """
        self.navmesh_manager = navmesh_manager
        self.analysis_results = {}
        self.optimization_suggestions = []
        
    def analyze_mesh_quality(self) -> Dict:
        """
        分析导航网格质量
        
        Returns:
            质量分析结果
        """
        if not self.navmesh_manager or not self.navmesh_manager.polygons:
            return {}
            
        results = {
            'polygon_count': len(self.navmesh_manager.polygons),
            'vertex_count': 0,
            'edge_count': 0,
            'isolated_polygons': 0,
            'overlapping_polygons': 0,
            'small_polygons': 0,
            'irregular_polygons': 0,
            'connectivity_issues': 0,
            'portal_issues': 0,
            'area_statistics': {},
            'vertex_statistics': {},
            'performance_metrics': {}
        }
        
        # 统计顶点和边
        total_vertices = 0
        total_edges = 0
        polygon_areas = []
        vertex_counts = []
        isolated_count = 0
        small_polygon_count = 0
        irregular_polygon_count = 0
        overlapping_count = 0
        connectivity_issues = 0
        portal_issues = 0
        
        # 分析每个多边形
        for polygon_id, polygon in self.navmesh_manager.polygons.items():
            vertex_count = len(polygon.vertices)
            total_vertices += vertex_count
            vertex_counts.append(vertex_count)
            
            # 边数等于顶点数
            total_edges += vertex_count
            
            # 面积统计
            area = polygon.area
            polygon_areas.append(area)
            
            # 检查小多边形
            if area < 0.1:  # 面积极小阈值
                small_polygon_count += 1
                
            # 检查不规则多边形（顶点数过多）
            if vertex_count > 8:  # 顶点数过多阈值
                irregular_polygon_count += 1
                
            # 检查孤立多边形（没有邻居）
            if not polygon.neighbors:
                isolated_count += 1
                
            # 检查连接性问题
            for neighbor_id in polygon.neighbors:
                if neighbor_id not in self.navmesh_manager.polygons:
                    connectivity_issues += 1
                    
            # 检查门户点问题
            for neighbor_id, portal_points in polygon.portal_points.items():
                if neighbor_id not in polygon.neighbors:
                    portal_issues += 1
                    
        # 计算面积统计
        if polygon_areas:
            results['area_statistics'] = {
                'total_area': sum(polygon_areas),
                'average_area': sum(polygon_areas) / len(polygon_areas),
                'min_area': min(polygon_areas),
                'max_area': max(polygon_areas),
                'area_variance': self._calculate_variance(polygon_areas)
            }
            
        # 计算顶点统计
        if vertex_counts:
            results['vertex_statistics'] = {
                'total_vertices': total_vertices,
                'average_vertices': sum(vertex_counts) / len(vertex_counts),
                'min_vertices': min(vertex_counts),
                'max_vertices': max(vertex_counts),
                'vertex_variance': self._calculate_variance(vertex_counts)
            }
            
        # 设置结果
        results['vertex_count'] = total_vertices
        results['edge_count'] = total_edges
        results['isolated_polygons'] = isolated_count
        results['small_polygons'] = small_polygon_count
        results['irregular_polygons'] = irregular_polygon_count
        results['overlapping_polygons'] = overlapping_count
        results['connectivity_issues'] = connectivity_issues
        results['portal_issues'] = portal_issues
        
        self.analysis_results = results
        return results
        
    def _calculate_variance(self, values: List[float]) -> float:
        """计算方差"""
        if not values:
            return 0.0
            
        mean = sum(values) / len(values)
        variance = sum((x - mean) ** 2 for x in values) / len(values)
        return variance
        
    def suggest_optimizations(self) -> List[Dict]:
        """
        提供优化建议
        
        Returns:
            优化建议列表
        """
        suggestions = []
        
        if not self.analysis_results:
            self.analyze_mesh_quality()
            
        results = self.analysis_results
        
        # 检查多边形数量
        if results.get('polygon_count', 0) > 10000:
            suggestions.append({
                'type': 'performance',
                'severity': 'high',
                'description': '导航网格包含过多的多边形',
                'recommendation': '考虑简化网格或使用分层寻路'
            })
            
        # 检查孤立多边形
        if results.get('isolated_polygons', 0) > 0:
            suggestions.append({
                'type': 'connectivity',
                'severity': 'medium',
                'description': '存在孤立的多边形',
                'recommendation': '检查并连接孤立的多边形或移除它们'
            })
            
        # 检查小多边形
        if results.get('small_polygons', 0) > results.get('polygon_count', 0) * 0.1:
            suggestions.append({
                'type': 'quality',
                'severity': 'medium',
                'description': '存在过多极小的多边形',
                'recommendation': '合并相邻的小多边形或移除它们'
            })
            
        # 检查不规则多边形
        if results.get('irregular_polygons', 0) > results.get('polygon_count', 0) * 0.2:
            suggestions.append({
                'type': 'quality',
                'severity': 'low',
                'description': '存在过多顶点的不规则多边形',
                'recommendation': '简化复杂多边形以提高性能'
            })
            
        # 检查连接性问题
        if results.get('connectivity_issues', 0) > 0:
            suggestions.append({
                'type': 'correctness',
                'severity': 'high',
                'description': '存在连接性问题',
                'recommendation': '修复多边形间的连接关系'
            })
            
        # 检查门户点问题
        if results.get('portal_issues', 0) > 0:
            suggestions.append({
                'type': 'correctness',
                'severity': 'high',
                'description': '存在门户点问题',
                'recommendation': '重新计算多边形间的门户点'
            })
            
        self.optimization_suggestions = suggestions
        return suggestions
        
    def analyze_pathfinding_performance(self, sample_count: int = 100) -> Dict:
        """
        分析寻路性能
        
        Args:
            sample_count: 采样次数
            
        Returns:
            性能分析结果
        """
        if not self.navmesh_manager or not hasattr(self.navmesh_manager, 'world'):
            return {}
            
        from .pathfinder import Pathfinder
        pathfinder = Pathfinder(self.navmesh_manager)
        
        performance_results = {
            'total_time': 0.0,
            'average_time': 0.0,
            'min_time': float('inf'),
            'max_time': 0.0,
            'success_count': 0,
            'failure_count': 0,
            'average_path_length': 0.0,
            'path_lengths': []
        }
        
        total_length = 0.0
        path_lengths = []
        
        # 执行多次寻路测试
        for _ in range(sample_count):
            start_point = self.navmesh_manager.get_random_point()
            end_point = self.navmesh_manager.get_random_point()
            
            if start_point and end_point:
                start_time = time.time()
                path = pathfinder.find_path(start_point, end_point)
                end_time = time.time()
                
                search_time = end_time - start_time
                performance_results['total_time'] += search_time
                performance_results['min_time'] = min(performance_results['min_time'], search_time)
                performance_results['max_time'] = max(performance_results['max_time'], search_time)
                
                if path:
                    performance_results['success_count'] += 1
                    path_length = sum((path[i+1] - path[i]).length() for i in range(len(path)-1))
                    total_length += path_length
                    path_lengths.append(path_length)
                else:
                    performance_results['failure_count'] += 1
                    
        # 计算平均值
        if sample_count > 0:
            performance_results['average_time'] = performance_results['total_time'] / sample_count
            
        if path_lengths:
            performance_results['average_path_length'] = total_length / len(path_lengths)
            performance_results['path_lengths'] = path_lengths
            
        return performance_results
        
    def detect_bottlenecks(self) -> List[Dict]:
        """
        检测导航网格中的瓶颈区域
        
        Returns:
            瓶颈区域列表
        """
        bottlenecks = []
        
        if not self.navmesh_manager or not self.navmesh_manager.polygons:
            return bottlenecks
            
        # 计算每个多边形的"狭窄度"
        for polygon_id, polygon in self.navmesh_manager.polygons.items():
            # 狭窄度基于面积和周长的比值
            if len(polygon.vertices) >= 3:
                perimeter = self._calculate_perimeter(polygon.vertices)
                if perimeter > 0:
                    compactness = polygon.area / (perimeter ** 2)
                    
                    # 如果紧凑度很低，可能是狭窄区域
                    if compactness < 0.01:  # 阈值需要根据实际情况调整
                        bottlenecks.append({
                            'polygon_id': polygon_id,
                            'position': polygon.center,
                            'compactness': compactness,
                            'area': polygon.area,
                            'perimeter': perimeter
                        })
                        
        # 按紧凑度排序
        bottlenecks.sort(key=lambda x: x['compactness'])
        
        return bottlenecks[:10]  # 返回最狭窄的10个区域
        
    def _calculate_perimeter(self, vertices: List[Point3]) -> float:
        """计算多边形周长"""
        if len(vertices) < 2:
            return 0.0
            
        perimeter = 0.0
        for i in range(len(vertices)):
            p1 = vertices[i]
            p2 = vertices[(i + 1) % len(vertices)]
            perimeter += (p2 - p1).length()
            
        return perimeter
        
    def analyze_coverage(self) -> Dict:
        """
        分析导航网格覆盖情况
        
        Returns:
            覆盖情况分析结果
        """
        coverage_results = {
            'covered_area': 0.0,
            'total_area': 0.0,
            'coverage_ratio': 0.0,
            'uncovered_regions': []
        }
        
        if not self.navmesh_manager or not self.navmesh_manager.polygons:
            return coverage_results
            
        # 计算总覆盖面积（简单近似）
        total_area = 0.0
        for polygon in self.navmesh_manager.polygons.values():
            total_area += polygon.area
            
        coverage_results['covered_area'] = total_area
        coverage_results['total_area'] = total_area  # 简化处理
        coverage_results['coverage_ratio'] = 1.0 if total_area > 0 else 0.0
        
        return coverage_results
        
    def generate_report(self) -> Dict:
        """
        生成完整的分析报告
        
        Returns:
            分析报告
        """
        report = {
            'timestamp': time.time(),
            'mesh_quality': self.analyze_mesh_quality(),
            'optimization_suggestions': self.suggest_optimizations(),
            'coverage_analysis': self.analyze_coverage(),
            'bottlenecks': self.detect_bottlenecks()
        }
        
        return report
        
    def export_report(self, filepath: str) -> bool:
        """
        导出分析报告到文件
        
        Args:
            filepath: 导出文件路径
            
        Returns:
            是否导出成功
        """
        try:
            report = self.generate_report()
            
            # 转换不可序列化的对象
            serializable_report = self._make_serializable(report)
            
            with open(filepath, 'w', encoding='utf-8') as f:
                json.dump(serializable_report, f, indent=2, ensure_ascii=False)
                
            return True
        except Exception as e:
            print(f"导出报告失败: {e}")
            return False
            
    def _make_serializable(self, obj):
        """将对象转换为可序列化的格式"""
        if isinstance(obj, dict):
            return {key: self._make_serializable(value) for key, value in obj.items()}
        elif isinstance(obj, list):
            return [self._make_serializable(item) for item in obj]
        elif isinstance(obj, Point3):
            return [obj.x, obj.y, obj.z]
        elif isinstance(obj, float) and (math.isnan(obj) or math.isinf(obj)):
            return str(obj)
        else:
            return obj
            
    def get_complexity_score(self) -> float:
        """
        计算导航网格复杂度评分
        
        Returns:
            复杂度评分 (0-100)
        """
        if not self.analysis_results:
            self.analyze_mesh_quality()
            
        results = self.analysis_results
        score = 50.0  # 基础分数
        
        # 根据多边形数量调整
        polygon_count = results.get('polygon_count', 0)
        if polygon_count > 5000:
            score += min(30, (polygon_count - 5000) / 1000)
        elif polygon_count < 1000:
            score -= min(20, (1000 - polygon_count) / 100)
            
        # 根据问题数量调整
        issues = (results.get('isolated_polygons', 0) +
                 results.get('connectivity_issues', 0) +
                 results.get('portal_issues', 0))
        score += min(20, issues / 10)
        
        # 根据不规则多边形调整
        irregular = results.get('irregular_polygons', 0)
        score += min(10, irregular / 50)
        
        return max(0, min(100, score))
        
    def recommend_simplification(self) -> Dict:
        """
        推荐网格简化策略
        
        Returns:
            简化策略建议
        """
        if not self.analysis_results:
            self.analyze_mesh_quality()
            
        results = self.analysis_results
        recommendations = {
            'should_simplify': False,
            'reasons': [],
            'simplification_level': 'none',  # none, light, medium, heavy
            'target_polygon_count': results.get('polygon_count', 0)
        }
        
        polygon_count = results.get('polygon_count', 0)
        isolated_count = results.get('isolated_polygons', 0)
        small_count = results.get('small_polygons', 0)
        irregular_count = results.get('irregular_polygons', 0)
        
        # 检查是否需要简化
        if polygon_count > 5000:
            recommendations['should_simplify'] = True
            recommendations['reasons'].append('多边形数量过多')
            
        if isolated_count > polygon_count * 0.05:
            recommendations['should_simplify'] = True
            recommendations['reasons'].append('存在大量孤立多边形')
            
        if small_count > polygon_count * 0.1:
            recommendations['should_simplify'] = True
            recommendations['reasons'].append('存在大量极小多边形')
            
        if irregular_count > polygon_count * 0.2:
            recommendations['should_simplify'] = True
            recommendations['reasons'].append('存在大量不规则多边形')
            
        # 确定简化级别
        if recommendations['should_simplify']:
            if polygon_count > 10000:
                recommendations['simplification_level'] = 'heavy'
                recommendations['target_polygon_count'] = int(polygon_count * 0.5)
            elif polygon_count > 5000:
                recommendations['simplification_level'] = 'medium'
                recommendations['target_polygon_count'] = int(polygon_count * 0.7)
            else:
                recommendations['simplification_level'] = 'light'
                recommendations['target_polygon_count'] = int(polygon_count * 0.8)
                
        return recommendations