using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
using NavisworksTransport.Core.Config;
using static NavisworksTransport.CategoryAttributeManager;
using g4;

namespace NavisworksTransport.PathPlanning
{
    /// <summary>
    /// 体素网格生成器 - 从 Navisworks BIM 模型生成 3D 体素网格
    /// 使用 SDF (Signed Distance Field) 方法进行精确体素化
    /// </summary>
    public class VoxelGridGenerator
    {

        /// <summary>
        /// 获取模型元素的物流类型
        /// </summary>
        private LogisticsElementType GetLogisticsElementType(ModelItem item)
        {
            // 尝试从自定义属性读取
            try
            {
                var categories = item.PropertyCategories;
                foreach (var category in categories)
                {
                    if (category.DisplayName == LogisticsCategories.LOGISTICS ||
                        category.Name == LogisticsCategories.CATEGORY_INTERNAL_NAME)
                    {
                        foreach (var prop in category.Properties)
                        {
                            if (prop.DisplayName == LogisticsProperties.TYPE)
                            {
                                string typeStr = prop.Value.ToDisplayString();
                                if (Enum.TryParse<LogisticsElementType>(typeStr, out var parsedType))
                                {
                                    return parsedType;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.Debug($"读取物流属性失败: {ex.Message}");
            }

            // 默认：根据元素名称推断类型
            string displayName = item.DisplayName?.ToLower() ?? "";

            if (displayName.Contains("门") || displayName.Contains("door"))
                return LogisticsElementType.门;
            else if (displayName.Contains("楼梯") || displayName.Contains("stair"))
                return LogisticsElementType.楼梯;
            else if (displayName.Contains("电梯") || displayName.Contains("elevator"))
                return LogisticsElementType.电梯;
            else if (displayName.Contains("通道") || displayName.Contains("corridor"))
                return LogisticsElementType.通道;
            else
                return LogisticsElementType.障碍物; // 默认为障碍物
        }

        /// <summary>
        /// 判断物流类型是否为障碍物
        /// </summary>
        private bool IsObstacleType(LogisticsElementType type)
        {
            switch (type)
            {
                case LogisticsElementType.障碍物:
                    return true;

                case LogisticsElementType.门:
                case LogisticsElementType.通道:
                case LogisticsElementType.楼梯:
                case LogisticsElementType.电梯:
                case LogisticsElementType.装卸区:
                case LogisticsElementType.停车位:
                    return false;

                default:
                    return true; // 未知类型默认为障碍物
            }
        }

        /// <summary>
        /// 使用 MeshSignedDistanceGrid 从 BIM 模型生成体素网格（精确几何体方法）
        /// 阶段 1.4 版本：使用 geometry4Sharp 的签名距离场进行精确体素化
        /// </summary>
        /// <param name="bounds">网格边界（世界坐标，模型单位）</param>
        /// <param name="voxelSizeMeters">体素尺寸（米）</param>
        /// <param name="objectRadiusMeters">物体半径（米），用于安全间隙</param>
        /// <param name="objectHeightMeters">物体高度（米）</param>
        /// <param name="obstacleItems">障碍物模型元素列表</param>
        /// <returns>生成的体素网格</returns>
        public VoxelGrid GenerateFromBIMWithSDF(
            BoundingBox3D bounds,
            double voxelSizeMeters,
            double objectRadiusMeters,
            double objectHeightMeters,
            IEnumerable<ModelItem> obstacleItems)
        {
            var stopwatch = Stopwatch.StartNew();
            LogManager.Info("=== 开始体素网格生成（MeshSignedDistanceGrid 方法） ===");

            // 第一步：单位转换（米 → 模型单位）
            double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(
                Autodesk.Navisworks.Api.Application.ActiveDocument.Units);

            double voxelSizeInModelUnits = voxelSizeMeters * metersToModelUnits;
            double objectRadiusInModelUnits = objectRadiusMeters * metersToModelUnits;
            double objectHeightInModelUnits = objectHeightMeters * metersToModelUnits;
            double safetyMarginInModelUnits = objectRadiusInModelUnits; // 安全间隙 = 物体半径

            LogManager.Info($"单位转换系数: {metersToModelUnits:F4}");
            LogManager.Info($"体素尺寸: {voxelSizeMeters}米 = {voxelSizeInModelUnits:F2}模型单位");
            LogManager.Info($"安全间隙: {objectRadiusMeters}米 = {safetyMarginInModelUnits:F2}模型单位");

            // 第二步：创建体素网格
            var voxelGrid = new VoxelGrid(bounds, voxelSizeInModelUnits);
            LogManager.Info($"创建体素网格: {voxelGrid.SizeX} × {voxelGrid.SizeY} × {voxelGrid.SizeZ} = {voxelGrid.TotalVoxels:N0} 个体素");

            // 第三步：过滤模型元素 - 排除门，只保留真正的障碍物
            LogManager.Info("开始过滤模型元素（排除门）...");
            var filterStopwatch = Stopwatch.StartNew();

            int totalItemsCount = obstacleItems.Count();
            var filteredItems = obstacleItems.Where(item =>
            {
                var elementType = GetLogisticsElementType(item);
                // 排除门：门留出空洞，不作为障碍物
                // 保留真正的障碍物
                return elementType != LogisticsElementType.门 && IsObstacleType(elementType);
            }).ToList();

            filterStopwatch.Stop();
            LogManager.Info($"元素过滤完成，耗时: {filterStopwatch.ElapsedMilliseconds} ms");
            LogManager.Info($"元素统计: 总数={totalItemsCount}, 过滤后={filteredItems.Count}, 排除的门={totalItemsCount - filteredItems.Count}");

            // 第四步：提取障碍物几何体并转换为 DMesh3
            LogManager.Info("开始提取障碍物几何体...");
            var geometryStopwatch = Stopwatch.StartNew();

            // 使用几何体缓存
            DMesh3 obstacleMesh = null;
            var cacheManager = new GeometryCacheManager(Application.ActiveDocument.FileName);    
            try
            {
                LogManager.Info($"[体素网格] 从缓存中提取 {filteredItems.Count} 个过滤后项的几何体");
                var allTriangles = new List<Triangle3D>();
                
                int processedItems = 0;
                foreach (var item in filteredItems)
                {
                    var itemTriangles = cacheManager.GetTrianglesForModelItem(item);
                    allTriangles.AddRange(itemTriangles);
                    processedItems++;                    
                }
                
                LogManager.Info($"[体素网格] 从缓存中提取完成，总三角形数: {allTriangles.Count}");
                obstacleMesh = NavisworksToDMesh3Converter.Convert(allTriangles);
            }
            catch (Exception ex)
            {
                LogManager.Warning($"[体素网格] 使用几何体缓存失败: {ex.Message}，回退到传统方法");
                
                // 如果缓存不可用，则使用传统方法提取几何体
                obstacleMesh = NavisworksToDMesh3Converter.ConvertFromModelItems(filteredItems);
            }

            geometryStopwatch.Stop();
            LogManager.Info($"几何体提取完成，耗时: {geometryStopwatch.ElapsedMilliseconds} ms");

            if (obstacleMesh.TriangleCount == 0)
            {
                LogManager.Warning("警告：没有提取到任何障碍物几何体，所有体素将标记为可通行");
                return voxelGrid;
            }

            // 第四步：使用 MeshSignedDistanceGrid 计算签名距离场
            LogManager.Info("开始计算签名距离场（Signed Distance Field）...");
            var sdfStopwatch = Stopwatch.StartNew();

            try
            {
                // 计算需要的网格尺寸（基于包围盒和体素大小）
                var meshBounds = obstacleMesh.GetBounds();
                int numCellsX = (int)Math.Ceiling(meshBounds.Width / voxelSizeInModelUnits);
                int numCellsY = (int)Math.Ceiling(meshBounds.Height / voxelSizeInModelUnits);
                int numCellsZ = (int)Math.Ceiling(meshBounds.Depth / voxelSizeInModelUnits);

                LogManager.Info($"SDF 网格尺寸: {numCellsX} × {numCellsY} × {numCellsZ}");

                // 创建签名距离场
                MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(
                    obstacleMesh,
                    voxelSizeInModelUnits);

                // 计算距离场（这可能耗时较长）
                sdf.Compute();

                sdfStopwatch.Stop();
                LogManager.Info($"距离场计算完成，耗时: {sdfStopwatch.ElapsedMilliseconds} ms ({sdfStopwatch.Elapsed.TotalSeconds:F2} 秒)");

                // 第五步：使用距离场标记体素
                LogManager.Info("开始根据距离场标记体素...");
                var markingStopwatch = Stopwatch.StartNew();

                int obstacleCount = 0;
                int passableCount = 0;
                int boundaryCount = 0;

                // SDF阶段不使用安全间隙，只标记几何体内部为障碍物
                // 安全间隙在后续的XY平面膨胀阶段应用

                // 获取 SDF 网格的原点和单元尺寸
                Vector3f sdfOrigin = sdf.GridOrigin;
                float sdfCellSize = sdf.CellSize;
                var sdfDimensions = sdf.Dimensions;

                LogManager.Info($"SDF 网格信息: 原点=({sdfOrigin.x:F2}, {sdfOrigin.y:F2}, {sdfOrigin.z:F2}), " +
                    $"单元尺寸={sdfCellSize:F4}, 维度={sdfDimensions.x}×{sdfDimensions.y}×{sdfDimensions.z}");

                for (int x = 0; x < voxelGrid.SizeX; x++)
                {
                    for (int y = 0; y < voxelGrid.SizeY; y++)
                    {
                        for (int z = 0; z < voxelGrid.SizeZ; z++)
                        {
                            // 体素中心的世界坐标
                            Point3D worldPos = voxelGrid.VoxelToWorldCenter(x, y, z);

                            // 将世界坐标转换为 SDF 网格索引
                            int sdfX = (int)Math.Floor((worldPos.X - sdfOrigin.x) / sdfCellSize);
                            int sdfY = (int)Math.Floor((worldPos.Y - sdfOrigin.y) / sdfCellSize);
                            int sdfZ = (int)Math.Floor((worldPos.Z - sdfOrigin.z) / sdfCellSize);

                            // 查询距离场（使用整数索引）
                            double distance = 0.0;
                            if (sdfX >= 0 && sdfX < sdfDimensions.x &&
                                sdfY >= 0 && sdfY < sdfDimensions.y &&
                                sdfZ >= 0 && sdfZ < sdfDimensions.z)
                            {
                                distance = sdf[sdfX, sdfY, sdfZ];
                            }
                            else
                            {
                                // 超出 SDF 范围，认为是远离障碍物
                                distance = double.MaxValue;
                            }

                            var cell = voxelGrid.GetCell(x, y, z);
                            cell.Distance = distance;

                            // 判断可通行性 - SDF阶段只标记几何体内部为障碍物
                            // 距离 < 0: 在障碍物内部 → 不可通行
                            // 距离 >= 0: 在障碍物外部 → 可通行
                            if (distance < 0)
                            {
                                cell.SetAsObstacle();
                                cell.Type = LogisticsElementType.障碍物;
                                obstacleCount++;

                                // 统计边界体素（距离接近0的体素）
                                if (Math.Abs(distance) < voxelSizeInModelUnits * 0.5)
                                {
                                    boundaryCount++;
                                }
                            }
                            else
                            {
                                cell.IsPassable = true;
                                cell.Type = LogisticsElementType.通道;
                                passableCount++;
                            }
                        }
                    }
                }

                markingStopwatch.Stop();
                LogManager.Info($"体素标记完成，耗时: {markingStopwatch.ElapsedMilliseconds} ms");
                LogManager.Info($"标记统计: 障碍物={obstacleCount:N0}, 可通行={passableCount:N0}, 边界={boundaryCount:N0}");

                // 第六步：障碍物膨胀（可选）
                if (objectRadiusMeters > 0)
                {
                    LogManager.Info("开始障碍物膨胀...");
                    var inflationStopwatch = Stopwatch.StartNew();

                    int inflatedCount = voxelGrid.InflateObstacles(objectRadiusMeters, metersToModelUnits);

                    inflationStopwatch.Stop();
                    LogManager.Info($"障碍物膨胀完成，耗时: {inflationStopwatch.ElapsedMilliseconds} ms");
                    LogManager.Info($"膨胀统计: 新增障碍物体素={inflatedCount:N0}");
                }
                else
                {
                    LogManager.Info("跳过障碍物膨胀（物体半径为0）");
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"MeshSignedDistanceGrid 计算失败: {ex.Message}");
                LogManager.Error($"堆栈跟踪: {ex.StackTrace}");

                // 不使用 fallback，直接抛出异常让问题暴露
                throw new InvalidOperationException("SDF 体素网格生成失败，无法继续", ex);
            }

            // 第七步：统计信息
            var (total, passable, obstacle) = voxelGrid.GetStatistics();
            double passableRatio = (double)passable / total * 100.0;

            stopwatch.Stop();
            LogManager.Info($"=== 体素网格生成完成（SDF 方法） ===");
            LogManager.Info($"总体素数: {total:N0}");
            LogManager.Info($"可通行体素: {passable:N0} ({passableRatio:F1}%)");
            LogManager.Info($"障碍物体素: {obstacle:N0} ({100 - passableRatio:F1}%)");
            LogManager.Info($"总耗时: {stopwatch.ElapsedMilliseconds} ms ({stopwatch.Elapsed.TotalSeconds:F2} 秒)");

            return voxelGrid;
        }

        /// <summary>
        /// 快速测试方法 - 生成简单的测试场景体素网格
        /// </summary>
        /// <returns>测试用体素网格</returns>
        public static VoxelGrid CreateTestGrid()
        {
            // 创建 10m × 10m × 3m 的测试房间
            double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(
                Autodesk.Navisworks.Api.Application.ActiveDocument.Units);

            var bounds = new BoundingBox3D(
                new Point3D(0, 0, 0),
                new Point3D(10 * metersToModelUnits, 10 * metersToModelUnits, 3 * metersToModelUnits)
            );

            double voxelSize = ConfigManager.Instance.Current.PathEditing.CellSizeMeters * metersToModelUnits; // 使用配置的网格大小作为体素大小

            var grid = new VoxelGrid(bounds, voxelSize);

            LogManager.Info($"创建测试网格: {grid}");

            // 添加一个简单的障碍物（中心位置的柱子）
            int centerX = grid.SizeX / 2;
            int centerY = grid.SizeY / 2;

            for (int z = 0; z < grid.SizeZ; z++)
            {
                for (int dx = -1; dx <= 1; dx++)
                {
                    for (int dy = -1; dy <= 1; dy++)
                    {
                        int x = centerX + dx;
                        int y = centerY + dy;

                        if (grid.IsValidIndex(x, y, z))
                        {
                            var cell = grid.GetCell(x, y, z);
                            cell.SetAsObstacle();
                        }
                    }
                }
            }

            var (total, passable, obstacle) = grid.GetStatistics();
            LogManager.Info($"测试网格统计: 总={total}, 可通行={passable}, 障碍={obstacle}");

            return grid;
        }
    }
}
