using System;
using System.Collections.Generic;
using g4;

namespace NavisworksTransport.Core.Spatial
{
    /// <summary>
    /// 自定义3D空间哈希网格
    /// 用于高效的空间范围查询，复杂度 O(1) 平均
    ///
    /// 设计参考 geometry3Sharp 的 PointHashGrid3d，但提供了以下增强：
    /// 1. 支持返回范围内的所有对象（而不仅是最近的一个）
    /// 2. 支持直接访问网格单元（GetObjectsInCell）
    /// 3. 提供详细的统计信息用于性能分析
    /// 4. 使用 ScaleGridIndexer3 实现更清晰的坐标转换
    /// </summary>
    /// <typeparam name="T">存储的对象类型</typeparam>
    public class SpatialHashGrid<T>
    {
        private readonly Dictionary<Vector3i, List<T>> _grid;
        private readonly ScaleGridIndexer3 _indexer;

        /// <summary>
        /// 创建空间哈希网格
        /// </summary>
        /// <param name="cellSize">格子大小（模型单位）</param>
        public SpatialHashGrid(double cellSize)
        {
            if (cellSize <= 0)
                throw new ArgumentException("格子大小必须大于0", nameof(cellSize));

            _indexer = new ScaleGridIndexer3() { CellSize = cellSize };
            _grid = new Dictionary<Vector3i, List<T>>();
        }

        /// <summary>
        /// 格子大小（模型单位）
        /// </summary>
        public double CellSize => _indexer.CellSize;

        /// <summary>
        /// 格子总数
        /// </summary>
        public int CellCount => _grid.Count;

        /// <summary>
        /// 对象总数
        /// </summary>
        public int ObjectCount
        {
            get
            {
                int count = 0;
                foreach (var list in _grid.Values)
                {
                    count += list.Count;
                }
                return count;
            }
        }

        /// <summary>
        /// 插入对象到空间哈希网格（边界框版本）
        /// 对象将被插入到其边界框覆盖的所有格子中
        /// </summary>
        /// <param name="item">要插入的对象</param>
        /// <param name="boundsMin">边界框最小点</param>
        /// <param name="boundsMax">边界框最大点</param>
        public void Insert(T item, Vector3d boundsMin, Vector3d boundsMax)
        {
            // 计算边界框覆盖的格子范围
            var minGridCell = _indexer.ToGrid(boundsMin);
            var maxGridCell = _indexer.ToGrid(boundsMax);

            // 遍历边界框覆盖的所有格子
            for (int x = minGridCell.x; x <= maxGridCell.x; x++)
            {
                for (int y = minGridCell.y; y <= maxGridCell.y; y++)
                {
                    for (int z = minGridCell.z; z <= maxGridCell.z; z++)
                    {
                        var gridCell = new Vector3i(x, y, z);

                        if (!_grid.TryGetValue(gridCell, out var cellList))
                        {
                            cellList = new List<T>();
                            _grid[gridCell] = cellList;
                        }

                        cellList.Add(item);
                    }
                }
            }
        }

        

        /// <summary>
        /// 插入对象到空间哈希网格（使用 Navisworks BoundingBox3D）
        /// 对象将被插入到其边界框覆盖的所有格子中
        /// </summary>
        /// <param name="item">要插入的对象</param>
        /// <param name="bounds">Navisworks 边界框</param>
        public void Insert(T item, Autodesk.Navisworks.Api.BoundingBox3D bounds)
        {
            var boundsMin = new Vector3d(bounds.Min.X, bounds.Min.Y, bounds.Min.Z);
            var boundsMax = new Vector3d(bounds.Max.X, bounds.Max.Y, bounds.Max.Z);
            Insert(item, boundsMin, boundsMax);
        }

        

        /// <summary>
        /// 批量插入对象
        /// </summary>
        /// <param name="items">对象和边界框的键值对</param>
        public void InsertRange(IEnumerable<KeyValuePair<T, (Vector3d min, Vector3d max)>> items)
        {
            foreach (var kvp in items)
            {
                Insert(kvp.Key, kvp.Value.min, kvp.Value.max);
            }
        }

        /// <summary>
        /// 获取指定格子中的所有对象
        /// </summary>
        /// <param name="gridCell">格子坐标</param>
        /// <returns>该格子中的对象列表</returns>
        public List<T> GetObjectsInCell(Vector3i gridCell)
        {
            if (_grid.TryGetValue(gridCell, out var list))
            {
                return new List<T>(list); // 返回副本，避免外部修改
            }
            return new List<T>();
        }

        /// <summary>
        /// 范围查询：查找指定位置附近指定半径内的所有对象
        /// 注意：由于对象可能被插入到多个格子中，使用 HashSet 自动去重
        /// </summary>
        /// <param name="center">查询中心位置</param>
        /// <param name="radius">查询半径（模型单位）</param>
        /// <param name="distanceFunc">可选的距离计算函数（用于精确过滤）</param>
        /// <returns>范围内的对象列表（自动去重）</returns>
        public List<T> FindInRadius(
            Vector3d center,
            double radius,
            Func<T, double> distanceFunc = null)
        {
            var results = new HashSet<T>();

            // 计算需要检查的格子范围
            int gridRadius = (int)Math.Ceiling(radius / _indexer.CellSize);
            var centerGrid = _indexer.ToGrid(center);

            // 优化：提前创建忽略函数，避免在循环中检查 null（借鉴 PointHashGrid3d）
            bool hasDistanceCheck = (distanceFunc != null);

            // 遍历查询范围内的所有格子
            for (int dx = -gridRadius; dx <= gridRadius; dx++)
            {
                for (int dy = -gridRadius; dy <= gridRadius; dy++)
                {
                    for (int dz = -gridRadius; dz <= gridRadius; dz++)
                    {
                        var gridCell = new Vector3i(
                            centerGrid.x + dx,
                            centerGrid.y + dy,
                            centerGrid.z + dz
                        );

                        // 使用 TryGetValue 避免两次字典查找（借鉴 PointHashGrid3d）
                        if (_grid.TryGetValue(gridCell, out var cellObjects))
                        {
                            foreach (var obj in cellObjects)
                            {
                                // 如果提供了距离函数，进行精确距离检查
                                if (hasDistanceCheck)
                                {
                                    double distance = distanceFunc(obj);
                                    if (distance <= radius)
                                    {
                                        results.Add(obj);
                                    }
                                }
                                else
                                {
                                    // 否则直接添加（假设格子内的对象都在范围内）
                                    results.Add(obj);
                                }
                            }
                        }
                    }
                }
            }

            return new List<T>(results);
        }

        /// <summary>
        /// 范围查询（带精确距离检查）
        /// </summary>
        /// <param name="center">查询中心</param>
        /// <param name="radius">查询半径</param>
        /// <param name="getPositionFunc">获取对象位置的函数</param>
        /// <returns>范围内的对象列表</returns>
        public List<T> FindInRadiusExact(
            Vector3d center,
            double radius,
            Func<T, Vector3d> getPositionFunc)
        {
            if (getPositionFunc == null)
                throw new ArgumentNullException(nameof(getPositionFunc));

            // 🔥 修改：不做距离过滤，只返回格子范围内的所有对象
            // 原因：使用中心点距离过滤会漏检包围盒很大的对象（如墙）
            return FindInRadius(center, radius, distanceFunc: null);
        }

        /// <summary>
        /// AABB范围查询：查找与指定AABB相交格子中的所有对象
        /// 比球形查询更精确，避免球体扩大的无效范围
        /// </summary>
        /// <param name="boundsMin">AABB最小点</param>
        /// <param name="boundsMax">AABB最大点</param>
        /// <returns>范围内的对象列表（自动去重）</returns>
        public List<T> FindInAABB(Vector3d boundsMin, Vector3d boundsMax)
        {
            var results = new HashSet<T>();

            // 计算AABB覆盖的格子范围
            var minGrid = _indexer.ToGrid(boundsMin);
            var maxGrid = _indexer.ToGrid(boundsMax);

            // 只遍历AABB覆盖的格子（比球形查询更精确）
            for (int x = minGrid.x; x <= maxGrid.x; x++)
            {
                for (int y = minGrid.y; y <= maxGrid.y; y++)
                {
                    for (int z = minGrid.z; z <= maxGrid.z; z++)
                    {
                        var gridCell = new Vector3i(x, y, z);

                        if (_grid.TryGetValue(gridCell, out var cellObjects))
                        {
                            foreach (var obj in cellObjects)
                            {
                                results.Add(obj);
                            }
                        }
                    }
                }
            }

            return new List<T>(results);
        }

        /// <summary>
        /// AABB范围查询（使用Navisworks BoundingBox3D）
        /// </summary>
        public List<T> FindInAABB(Autodesk.Navisworks.Api.BoundingBox3D bounds)
        {
            var min = new Vector3d(bounds.Min.X, bounds.Min.Y, bounds.Min.Z);
            var max = new Vector3d(bounds.Max.X, bounds.Max.Y, bounds.Max.Z);
            return FindInAABB(min, max);
        }

        /// <summary>
        /// 清空所有数据
        /// </summary>
        public void Clear()
        {
            _grid.Clear();
        }

        /// <summary>
        /// 获取网格统计信息（用于调试和性能分析）
        /// </summary>
        /// <returns>统计信息字符串</returns>
        public string GetStatistics()
        {
            int totalObjects = 0;
            int maxObjectsPerCell = 0;
            int minObjectsPerCell = int.MaxValue;
            int emptyCount = 0;

            foreach (var list in _grid.Values)
            {
                int count = list.Count;
                totalObjects += count;

                if (count == 0)
                    emptyCount++;

                if (count > maxObjectsPerCell)
                    maxObjectsPerCell = count;

                if (count < minObjectsPerCell && count > 0)
                    minObjectsPerCell = count;
            }

            double avgObjectsPerCell = _grid.Count > 0 ? (double)totalObjects / _grid.Count : 0;

            if (minObjectsPerCell == int.MaxValue)
                minObjectsPerCell = 0;

            return $"空间哈希网格统计:\n" +
                   $"  格子大小: {_indexer.CellSize:F2} 模型单位\n" +
                   $"  总格子数: {_grid.Count}\n" +
                   $"  总对象数: {totalObjects}\n" +
                   $"  平均每格对象数: {avgObjectsPerCell:F2}\n" +
                   $"  最大每格对象数: {maxObjectsPerCell}\n" +
                   $"  最小每格对象数: {minObjectsPerCell}\n" +
                   $"  空格子数: {emptyCount}";
        }
    }
}
