using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Autodesk.Navisworks.Api;
using NavisworksTransport.PathPlanning;

namespace NavisworksTransport.Commands
{
    /// <summary>
    /// 体素网格 SDF 测试命令
    /// 使用 geometry4Sharp 的 MeshSignedDistanceGrid 进行精确体素化
    /// 用于对比性能：射线投射法 vs 签名距离场法
    /// </summary>
    public class VoxelGridSDFTestCommand : CommandBase
    {
        private readonly Document _document;
        private readonly double _cellSize;
        private readonly int _samplingRate;
        private readonly double _objectRadius;
        private readonly double _objectHeight;

        public VoxelGridSDFTestCommand(
            Document document,
            double cellSize,
            int samplingRate,
            double objectRadius,
            double objectHeight)
            : base("VoxelGridSDFTest", "体素网格SDF测试", "使用签名距离场进行精确体素化")
        {
            _document = document ?? throw new ArgumentNullException(nameof(document));
            _cellSize = cellSize;
            _samplingRate = samplingRate;
            _objectRadius = objectRadius;
            _objectHeight = objectHeight;
        }

        protected override PathPlanningResult ValidateParameters()
        {
            if (_document == null)
            {
                return PathPlanningResult.ValidationFailure("Navisworks 文档对象为空");
            }

            if (_cellSize <= 0)
            {
                return PathPlanningResult.ValidationFailure("体素大小必须大于0");
            }

            return PathPlanningResult.Success("参数验证通过");
        }

        protected override async Task<PathPlanningResult> ExecuteInternalAsync(CancellationToken cancellationToken)
        {
            try
            {
                LogInfo("=== 开始体素网格 SDF 测试 ===");
                LogInfo($"体素大小: {_cellSize}米");
                LogInfo($"物体半径: {_objectRadius}米");
                LogInfo($"物体高度: {_objectHeight}米");
                LogInfo($"采样率: {_samplingRate}");

                UpdateProgress(5, "正在获取模型空间范围...");

                // 步骤1: 获取整个模型空间的包围盒
                BoundingBox3D spaceBounds = GetSpaceBounds(_document);

                if (spaceBounds == null)
                {
                    return PathPlanningResult.Failure("无法获取模型空间范围");
                }

                LogInfo($"空间范围: Min={spaceBounds.Min}, Max={spaceBounds.Max}");

                UpdateProgress(15, "正在收集场景中的所有模型对象...");

                // 步骤2: 收集场景中所有带几何信息的对象
                var allModelItems = GetAllModelItems(_document);
                LogInfo($"场景中共有 {allModelItems.Count} 个带几何信息的模型对象");

                if (allModelItems.Count == 0)
                {
                    return PathPlanningResult.Failure("场景中没有找到任何带几何信息的模型对象");
                }

                UpdateProgress(25, "正在使用 MeshSignedDistanceGrid 生成体素网格...");

                // 步骤3: 使用 SDF 方法生成体素网格
                var generator = new VoxelGridGenerator();
                var voxelGrid = generator.GenerateFromBIMWithSDF(
                    spaceBounds,
                    _cellSize,
                    _objectRadius,
                    _objectHeight,
                    allModelItems);

                LogInfo($"体素网格生成完成: {voxelGrid.SizeX}×{voxelGrid.SizeY}×{voxelGrid.SizeZ} = {voxelGrid.TotalVoxels} 个体素");

                UpdateProgress(70, "正在统计体素分布...");

                // 步骤4: 统计结果
                var (total, passable, obstacle) = voxelGrid.GetStatistics();
                LogInfo($"体素统计: 总数={total}, 自由空间={passable} ({passable*100.0/total:F1}%), 障碍物={obstacle} ({obstacle*100.0/total:F1}%)");

                UpdateProgress(75, "正在生成可视化数据...");

                // 步骤5: 生成可视化
                var voxelPoints = VoxelGridVisualizer.VisualizeAsPoints(
                    voxelGrid,
                    samplingRate: _samplingRate,
                    showPassableOnly: false
                );

                LogInfo($"生成了 {voxelPoints.Count} 个可视化点（采样率: {_samplingRate}）");

                // 步骤6: 转换为 PathRoute 以便使用现有渲染系统
                var visualRoute = VoxelGridVisualizer.ConvertToPathRoute(
                    voxelPoints,
                    $"VoxelGrid_SDF_{DateTime.Now:HHmmss}"
                );

                LogInfo($"可视化路径已创建: {visualRoute.Name}");

                UpdateProgress(85, "正在渲染体素网格...");

                // 步骤7: 调用 PathPointRenderPlugin 进行渲染
                var renderPlugin = PathPointRenderPlugin.Instance;
                if (renderPlugin != null)
                {
                    // 设置网格大小（体素大小），让渲染器根据体素大小计算球体半径
                    renderPlugin.SetGridSize(_cellSize);
                    LogInfo($"已设置体素网格大小: {_cellSize}米");

                    renderPlugin.RenderPointOnly(visualRoute);
                    LogInfo("✓ 体素网格已成功渲染到3D视图");
                }
                else
                {
                    LogWarning("PathPointRenderPlugin 实例不可用，无法渲染体素网格");
                }

                UpdateProgress(95, "正在生成报告...");

                // 步骤8: 生成文本报告
                var report = VoxelGridVisualizer.GenerateVisualizationReport(voxelGrid);
                LogInfo("=== 体素网格 SDF 测试报告 ===");
                LogInfo(report);

                UpdateProgress(100, "体素网格 SDF 测试完成");

                return PathPlanningResult.Success($"体素网格 SDF 测试完成\n\n{report}");
            }
            catch (Exception ex)
            {
                LogError($"体素网格 SDF 测试失败: {ex.Message}", ex);
                return PathPlanningResult.Failure($"体素网格 SDF 测试失败: {ex.Message}", ex);
            }
        }

        #region 私有辅助方法

        /// <summary>
        /// 获取整个模型空间的包围盒
        /// </summary>
        private BoundingBox3D GetSpaceBounds(Document document)
        {
            try
            {
                // 计算所有模型的总包围盒
                LogInfo("正在计算所有模型的总包围盒...");
                return CalculateBoundsFromAllModels(document);
            }
            catch (Exception ex)
            {
                LogError($"获取空间范围失败: {ex.Message}", ex);
                return null;
            }
        }

        /// <summary>
        /// 计算所有模型的总包围盒
        /// </summary>
        private BoundingBox3D CalculateBoundsFromAllModels(Document document)
        {
            BoundingBox3D totalBounds = null;

            foreach (var model in document.Models)
            {
                if (model.RootItem != null)
                {
                    var modelBounds = model.RootItem.BoundingBox();
                    if (modelBounds != null)
                    {
                        if (totalBounds == null)
                        {
                            totalBounds = modelBounds;
                        }
                        else
                        {
                            totalBounds = ExpandBounds(totalBounds, modelBounds);
                        }
                    }
                }
            }

            return totalBounds;
        }

        /// <summary>
        /// 扩展包围盒以包含另一个包围盒
        /// </summary>
        private BoundingBox3D ExpandBounds(BoundingBox3D bounds1, BoundingBox3D bounds2)
        {
            var min = new Point3D(
                Math.Min(bounds1.Min.X, bounds2.Min.X),
                Math.Min(bounds1.Min.Y, bounds2.Min.Y),
                Math.Min(bounds1.Min.Z, bounds2.Min.Z)
            );
            var max = new Point3D(
                Math.Max(bounds1.Max.X, bounds2.Max.X),
                Math.Max(bounds1.Max.Y, bounds2.Max.Y),
                Math.Max(bounds1.Max.Z, bounds2.Max.Z)
            );
            return new BoundingBox3D(min, max);
        }

        /// <summary>
        /// 获取场景中所有带几何信息的模型对象
        /// </summary>
        private List<ModelItem> GetAllModelItems(Document document)
        {
            var items = new List<ModelItem>();

            // 遍历文档中的所有模型
            foreach (var model in document.Models)
            {
                if (model.RootItem != null)
                {
                    CollectAllItems(model.RootItem, items);
                }
            }

            return items;
        }

        /// <summary>
        /// 递归收集所有带几何信息的对象
        /// </summary>
        private void CollectAllItems(ModelItem item, List<ModelItem> result)
        {
            // 如果当前对象有几何信息，加入结果
            if (item.HasGeometry)
            {
                result.Add(item);
            }

            // 递归处理所有子对象
            foreach (var child in item.Children)
            {
                CollectAllItems(child, result);
            }
        }

        #endregion
    }
}
