namespace NavisworksTransport.PathPlanning
{
    /// <summary>
    /// 三角形空间哈希索引类
    /// 用于A*改进方案中的射线相交测试性能优化
    /// 
    /// 核心原理：
    /// - 将3D空间划分为2D哈希网格
    /// - 每个三角形根据其2D投影分配到对应的哈希格子中
    /// - 射线检测时只需检查相关格子内的三角形，大幅减少相交测试次数
    /// </summary>
    public class TriangleSpatialHash
    {
        private Dictionary<int, List<Triangle3D>> _spatialHash;
        private double _cellSize;
        private int _gridWidth;
        private BoundingBox3D _bounds;
        private Point3D _origin;

        // 统计信息
        private int _totalTriangles;
        private int _totalCells;
        private double _averageTrianglesPerCell;
        private int _maxTrianglesPerCell;

        /// <summary>
        /// 构造函数
        /// </summary>
        public TriangleSpatialHash()
        {
            _spatialHash = new Dictionary<int, List<Triangle3D>>();
            _gridWidth = 10000; // 用于哈希计算的网格宽度
            LogManager.Info("[空间哈希] 初始化完成");
        }

        /// <summary>
        /// 构建空间哈希索引
        /// </summary>
        /// <param name="triangles">三角形列表</param>
        /// <param name="gridSize">网格单元大小</param>
        /// <param name="bounds">边界框（可选，自动计算）</param>
        public void Build(List<Triangle3D> triangles, double gridSize, BoundingBox3D bounds = null)
        {
            if (triangles == null || !triangles.Any())
            {
                LogManager.Warning("[空间哈希] 输入三角形列表为空");
                return;
            }

            LogManager.Info($"[空间哈希] 开始构建空间索引：{triangles.Count} 个三角形");

            _totalTriangles = triangles.Count;
            if (gridSize <= 0)
                throw new ArgumentException("gridSize 必须大于0", nameof(gridSize));
            _cellSize = gridSize * 2; // 使用稍大的单元格减少重复
            _spatialHash.Clear();

            // 计算或使用提供的边界框
            _bounds = bounds ?? CalculateTrianglesBounds(triangles);
            _origin = _bounds.Min;

            LogManager.Info($"[空间哈希] 边界框: [{_bounds.Min.X:F1},{_bounds.Min.Y:F1}] - [{_bounds.Max.X:F1},{_bounds.Max.Y:F1}]");
            LogManager.Info($"[空间哈希] 单元格大小: {_cellSize:F2}m");

            // 为每个三角形分配到哈希格子
            var processedTriangles = 0;
            foreach (var triangle in triangles)
            {
                try
                {
                    AssignTriangleToHash(triangle);
                    processedTriangles++;
                }
                catch (Exception ex)
                {
                    LogManager.Warning($"[空间哈希] 分配三角形失败: {ex.Message}");
                }
            }

            // 计算统计信息
            CalculateStatistics();

            LogManager.Info($"[空间哈希] 构建完成：{processedTriangles}/{triangles.Count} 个三角形，{_totalCells} 个格子");
            LogManager.Info($"[空间哈希] 性能统计：平均 {_averageTrianglesPerCell:F1} 个三角形/格子，最大 {_maxTrianglesPerCell} 个");
        }

        /// <summary>
        /// 获取指定2D位置附近的三角形
        /// </summary>
        /// <param name="x">世界坐标X</param>
        /// <param name="y">世界坐标Y</param>
        /// <param name="searchRadius">搜索半径（格子数量）</param>
        /// <returns>附近的三角形列表</returns>
        public List<Triangle3D> GetTrianglesAt(double x, double y, int searchRadius = 0)
        {
            var result = new List<Triangle3D>();

            // 计算基准格子坐标
            int baseGridX = (int)Math.Floor((x - _origin.X) / _cellSize);
            int baseGridY = (int)Math.Floor((y - _origin.Y) / _cellSize);

            // 搜索指定范围内的格子
            for (int dx = -searchRadius; dx <= searchRadius; dx++)
            {
                for (int dy = -searchRadius; dy <= searchRadius; dy++)
                {
                    int gridX = baseGridX + dx;
                    int gridY = baseGridY + dy;
                    int hash = CalculateHash(gridX, gridY);

                    if (_spatialHash.ContainsKey(hash))
                    {
                        result.AddRange(_spatialHash[hash]);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 获取指定点的三角形（单个格子）
        /// </summary>
        /// <param name="point">世界坐标点</param>
        /// <returns>该位置的三角形列表</returns>
        public List<Triangle3D> GetTrianglesAt(Point3D point)
        {
            return GetTrianglesAt(point.X, point.Y);
        }

        /// <summary>
        /// 获取指定区域内的所有三角形
        /// </summary>
        /// <param name="minX">最小X坐标</param>
        /// <param name="minY">最小Y坐标</param>
        /// <param name="maxX">最大X坐标</param>
        /// <param name="maxY">最大Y坐标</param>
        /// <returns>区域内的三角形列表</returns>
        public List<Triangle3D> GetTrianglesInRegion(double minX, double minY, double maxX, double maxY)
        {
            var result = new List<Triangle3D>();
            var addedHashes = new HashSet<int>(); // 避免重复添加

            int minGridX = (int)Math.Floor((minX - _origin.X) / _cellSize);
            int maxGridX = (int)Math.Floor((maxX - _origin.X) / _cellSize);
            int minGridY = (int)Math.Floor((minY - _origin.Y) / _cellSize);
            int maxGridY = (int)Math.Floor((maxY - _origin.Y) / _cellSize);

            for (int gridX = minGridX; gridX <= maxGridX; gridX++)
            {
                for (int gridY = minGridY; gridY <= maxGridY; gridY++)
                {
                    int hash = CalculateHash(gridX, gridY);
                    
                    if (_spatialHash.ContainsKey(hash) && !addedHashes.Contains(hash))
                    {
                        result.AddRange(_spatialHash[hash]);
                        addedHashes.Add(hash);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 获取性能统计信息
        /// </summary>
        /// <returns>统计信息字符串</returns>
        public string GetStatistics()
        {
            if (_totalTriangles == 0)
                return "空间哈希未初始化";

            var memoryUsageKB = EstimateMemoryUsage() / 1024.0;
            var compressionRatio = _totalTriangles > 0 ? (double)_totalTriangles / _totalCells : 0;

            return $"空间哈希统计: {_totalTriangles} 个三角形分布在 {_totalCells} 个格子中, " +
                   $"平均密度 {_averageTrianglesPerCell:F1}, 峰值密度 {_maxTrianglesPerCell}, " +
                   $"压缩比 {compressionRatio:F1}:1, 内存占用 {memoryUsageKB:F1} KB";
        }

        /// <summary>
        /// 清除所有数据
        /// </summary>
        public void Clear()
        {
            _spatialHash.Clear();
            _totalTriangles = 0;
            _totalCells = 0;
            _averageTrianglesPerCell = 0;
            _maxTrianglesPerCell = 0;
            LogManager.Info("[空间哈希] 已清除所有数据");
        }

        /// <summary>
        /// 检查空间哈希是否为空
        /// </summary>
        /// <returns>是否为空</returns>
        public bool IsEmpty()
        {
            return _totalTriangles == 0 || !_spatialHash.Any();
        }

        /// <summary>
        /// 获取指定格子中的三角形数量
        /// </summary>
        /// <param name="x">世界坐标X</param>
        /// <param name="y">世界坐标Y</param>
        /// <returns>三角形数量</returns>
        public int GetTriangleCountAt(double x, double y)
        {
            int gridX = (int)Math.Floor((x - _origin.X) / _cellSize);
            int gridY = (int)Math.Floor((y - _origin.Y) / _cellSize);
            int hash = CalculateHash(gridX, gridY);

            return _spatialHash.ContainsKey(hash) ? _spatialHash[hash].Count : 0;
        }

        #region 私有方法

        /// <summary>
        /// 将三角形分配到哈希格子
        /// </summary>
        /// <param name="triangle">三角形</param>
        private void AssignTriangleToHash(Triangle3D triangle)
        {
            // 计算三角形2D投影的包围盒
            var minX = Math.Min(triangle.V1.X, Math.Min(triangle.V2.X, triangle.V3.X));
            var maxX = Math.Max(triangle.V1.X, Math.Max(triangle.V2.X, triangle.V3.X));
            var minY = Math.Min(triangle.V1.Y, Math.Min(triangle.V2.Y, triangle.V3.Y));
            var maxY = Math.Max(triangle.V1.Y, Math.Max(triangle.V2.Y, triangle.V3.Y));

            // 计算涉及的格子范围
            int minGridX = (int)Math.Floor((minX - _origin.X) / _cellSize);
            int maxGridX = (int)Math.Floor((maxX - _origin.X) / _cellSize);
            int minGridY = (int)Math.Floor((minY - _origin.Y) / _cellSize);
            int maxGridY = (int)Math.Floor((maxY - _origin.Y) / _cellSize);

            // 将三角形添加到所有覆盖的格子
            for (int gridX = minGridX; gridX <= maxGridX; gridX++)
            {
                for (int gridY = minGridY; gridY <= maxGridY; gridY++)
                {
                    int hash = CalculateHash(gridX, gridY);
                    
                    if (!_spatialHash.ContainsKey(hash))
                    {
                        _spatialHash[hash] = new List<Triangle3D>();
                    }
                    
                    _spatialHash[hash].Add(triangle);
                }
            }
        }

        /// <summary>
        /// 计算哈希值
        /// </summary>
        /// <param name="gridX">格子X坐标</param>
        /// <param name="gridY">格子Y坐标</param>
        /// <returns>哈希值</returns>
        private int CalculateHash(int gridX, int gridY)
        {
            // 使用简单的线性哈希，避免负数
            var adjustedX = gridX + _gridWidth / 2;
            var adjustedY = gridY + _gridWidth / 2;
            
            // 确保在合理范围内
            adjustedX = Math.Max(0, Math.Min(_gridWidth - 1, adjustedX));
            adjustedY = Math.Max(0, Math.Min(_gridWidth - 1, adjustedY));
            
            return adjustedX * _gridWidth + adjustedY;
        }

        /// <summary>
        /// 计算三角形列表的边界框
        /// </summary>
        /// <param name="triangles">三角形列表</param>
        /// <returns>边界框</returns>
        private BoundingBox3D CalculateTrianglesBounds(List<Triangle3D> triangles)
        {
            if (!triangles.Any())
                return new BoundingBox3D(Point3D.Zero, Point3D.Zero);

            var first = triangles.First();
            double minX = Math.Min(first.V1.X, Math.Min(first.V2.X, first.V3.X));
            double maxX = Math.Max(first.V1.X, Math.Max(first.V2.X, first.V3.X));
            double minY = Math.Min(first.V1.Y, Math.Min(first.V2.Y, first.V3.Y));
            double maxY = Math.Max(first.V1.Y, Math.Max(first.V2.Y, first.V3.Y));
            double minZ = Math.Min(first.V1.Z, Math.Min(first.V2.Z, first.V3.Z));
            double maxZ = Math.Max(first.V1.Z, Math.Max(first.V2.Z, first.V3.Z));

            foreach (var triangle in triangles.Skip(1))
            {
                minX = Math.Min(minX, Math.Min(triangle.V1.X, Math.Min(triangle.V2.X, triangle.V3.X)));
                maxX = Math.Max(maxX, Math.Max(triangle.V1.X, Math.Max(triangle.V2.X, triangle.V3.X)));
                minY = Math.Min(minY, Math.Min(triangle.V1.Y, Math.Min(triangle.V2.Y, triangle.V3.Y)));
                maxY = Math.Max(maxY, Math.Max(triangle.V1.Y, Math.Max(triangle.V2.Y, triangle.V3.Y)));
                minZ = Math.Min(minZ, Math.Min(triangle.V1.Z, Math.Min(triangle.V2.Z, triangle.V3.Z)));
                maxZ = Math.Max(maxZ, Math.Max(triangle.V1.Z, Math.Max(triangle.V2.Z, triangle.V3.Z)));
            }

            return new BoundingBox3D(
                new Point3D(minX, minY, minZ),
                new Point3D(maxX, maxY, maxZ));
        }

        /// <summary>
        /// 计算统计信息
        /// </summary>
        private void CalculateStatistics()
        {
            _totalCells = _spatialHash.Count;
            
            if (_totalCells == 0)
            {
                _averageTrianglesPerCell = 0;
                _maxTrianglesPerCell = 0;
                return;
            }

            var triangleCounts = _spatialHash.Values.Select(list => list.Count).ToList();
            _averageTrianglesPerCell = triangleCounts.Average();
            _maxTrianglesPerCell = triangleCounts.Max();
        }

        /// <summary>
        /// 估算内存使用量（字节）
        /// </summary>
        /// <returns>内存使用量估算</returns>
        private long EstimateMemoryUsage()
        {
            // Dictionary开销 + 每个List的开销 + 三角形数据
            // 粗略估算：每个Dictionary条目32字节，每个List开销24字节，每个三角形72字节
            var dictOverhead = _spatialHash.Count * 32L;
            var listOverhead = _spatialHash.Count * 24L;
            var triangleData = _totalTriangles * 72L; // 9个double值 × 8字节
            
            return dictOverhead + listOverhead + triangleData;
        }

        #endregion

        #region 调试和可视化方法

        /// <summary>
        /// 获取格子密度分布信息（用于调试）
        /// </summary>
        /// <returns>密度分布字典：密度区间 -> 格子数量</returns>
        public Dictionary<string, int> GetDensityDistribution()
        {
            var distribution = new Dictionary<string, int>
            {
                ["0"] = 0,
                ["1-5"] = 0,
                ["6-10"] = 0,
                ["11-20"] = 0,
                ["21-50"] = 0,
                ["50+"] = 0
            };

            foreach (var cellTriangles in _spatialHash.Values)
            {
                var count = cellTriangles.Count;
                if (count == 0) distribution["0"]++;
                else if (count <= 5) distribution["1-5"]++;
                else if (count <= 10) distribution["6-10"]++;
                else if (count <= 20) distribution["11-20"]++;
                else if (count <= 50) distribution["21-50"]++;
                else distribution["50+"]++;
            }

            return distribution;
        }

        /// <summary>
        /// 验证空间哈希的正确性（调试用）
        /// </summary>
        /// <param name="testPoint">测试点</param>
        /// <returns>验证结果信息</returns>
        public string ValidateAtPoint(Point3D testPoint)
        {
            var triangles = GetTrianglesAt(testPoint.X, testPoint.Y);
            var cellTriangleCount = GetTriangleCountAt(testPoint.X, testPoint.Y);
            
            int gridX = (int)Math.Floor((testPoint.X - _origin.X) / _cellSize);
            int gridY = (int)Math.Floor((testPoint.Y - _origin.Y) / _cellSize);
            int hash = CalculateHash(gridX, gridY);

            return $"点 ({testPoint.X:F2}, {testPoint.Y:F2}) -> " +
                   $"格子 ({gridX}, {gridY}), 哈希 {hash}, " +
                   $"三角形数量 {cellTriangleCount}, 实际获取 {triangles.Count} 个";
        }

        #endregion
    }
}