using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
using NavisworksTransport.Utils.CoordinateSystem;

namespace NavisworksTransport.PathPlanning
{
    /// <summary>
    /// 基于通道的网格构建器
    /// 实现A*算法改进方案中的通道优先策略和2.5D垂直扫描
    /// 
    /// 术语说明：
    /// - "通道"指所有可通行的建筑结构（楼板、走廊、过道等）
    /// - 楼板：物体在其顶面行驶，底面用于结构支撑
    /// - 走廊/过道：传统意义的通道空间
    /// </summary>
    public class ChannelBasedGridBuilder
    {
        private ChannelHeightDetector _heightDetector;
        private readonly ICoordinateSystem _coordinateSystem;
        
        /// <summary>
        /// 通道几何类型
        /// </summary>
        private enum ChannelGeometryType
        {
            /// <summary>
            /// 水平通道（楼板）
            /// </summary>
            Horizontal,
            
            /// <summary>
            /// 倾斜通道（楼梯、坡道）
            /// </summary>
            Inclined,
            
            /// <summary>
            /// 复杂形状
            /// </summary>
            Complex
        }
        
        /// <summary>
        /// 构造函数（自动使用当前坐标系）
        /// </summary>
        public ChannelBasedGridBuilder() : this(CoordinateSystemManager.Instance.Current)
        {
        }
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="coordinateSystem">坐标系</param>
        public ChannelBasedGridBuilder(ICoordinateSystem coordinateSystem)
        {
            _coordinateSystem = coordinateSystem ?? throw new ArgumentNullException(nameof(coordinateSystem));
            _heightDetector = new ChannelHeightDetector(_coordinateSystem);
            LogManager.Info($"[通道网格构建器] 初始化完成，坐标系: {_coordinateSystem.Type}");
        }

        /// <summary>
        /// 构建基于通道的精确覆盖网格
        /// </summary>
        /// <param name="gridSize">网格单元格大小</param>
        /// <param name="document">当前文档</param>
        /// <returns>通道覆盖信息</returns>
        public ChannelCoverage BuildChannelCoverage(double gridSize)
        {
            LogManager.Info("[通道网格构建器] 开始构建通道覆盖网格");

            // 1. 获取所有通行相关的物品（通道 + 楼梯 + 电梯）
            var channelItems = new List<ModelItem>();

            // 获取通道
            var channels = CategoryAttributeManager.GetLogisticsItemsByType(
                "通道");
            channelItems.AddRange(channels);

            // 获取楼梯
            var stairs = CategoryAttributeManager.GetLogisticsItemsByType(
                "楼梯");
            channelItems.AddRange(stairs);

            // 获取电梯
            var elevators = CategoryAttributeManager.GetLogisticsItemsByType(
                "电梯");
            channelItems.AddRange(elevators);

            if (!channelItems.Any())
            {
                LogManager.Warning("[通道网格构建器] 未找到任何通行物品（通道/楼梯/电梯）");
                return CreateEmptyChannelCoverage();
            }

            LogManager.Info($"[通道网格构建器] 找到通行物品: 通道{channels.Count}个, 楼梯{stairs.Count}个, 电梯{elevators.Count}个, 总计{channelItems.Count}个");

            // 2. 计算通道总边界
            var totalBounds = BoundingBoxGeometryUtils.CalculateTotalBounds(channelItems);
            LogManager.Info($"[通道网格构建器] 通道总边界: {FormatBounds(totalBounds)}");

            // 3. 创建网格地图
            // 必须继续传递当前构建器绑定的坐标系，避免同一轮流程里
            // ChannelBasedGridBuilder、GridMap、ChannelHeightDetector 各自重新抓取 Current。
            var gridMap = new GridMap(totalBounds, gridSize, _coordinateSystem);

            // 4. 为每个通道生成精确投影
            var processedChannels = new List<ModelItem>();
            foreach (var channel in channelItems)
            {
                try
                {
                    ProjectChannelToGrid(channel, gridMap);
                    processedChannels.Add(channel);
                }
                catch (Exception ex)
                {
                    LogManager.Error($"[通道网格构建器] 投影通道失败 '{channel.DisplayName}': {ex.Message}");
                }
            }

            LogManager.Info($"[通道网格构建器] 成功投影 {processedChannels.Count}/{channelItems.Count} 个通道");

            // 5. 计算可通行网格的Z值范围
            var (walkableMinZ, walkableMaxZ, walkableCount) = CalculateWalkableGridZRange(gridMap);

            return new ChannelCoverage
            {
                GridMap = gridMap,
                ChannelItems = processedChannels,
                TotalBounds = totalBounds,
                WalkableMinZ = walkableMinZ,
                WalkableMaxZ = walkableMaxZ,
                WalkableGridCount = walkableCount
            };
        }

        /// <summary>
        /// 计算可通行网格的Z值范围
        /// 遍历所有可通行网格，基于实际WorldPosition.Z坐标计算最小值和最大值
        /// </summary>
        /// <param name="gridMap">网格地图</param>
        /// <returns>包含最小Z值、最大Z值和可通行网格数量的元组</returns>
        private (double minZ, double maxZ, int walkableCount) CalculateWalkableGridZRange(GridMap gridMap)
        {
            double minZ = double.MaxValue;
            double maxZ = double.MinValue;
            int walkableCount = 0;
            var elevationCounts = new Dictionary<double, int>();

            LogManager.Info("[通道Z值计算] 开始计算可通行网格Z值范围");

            for (int x = 0; x < gridMap.Width; x++)
            {
                for (int y = 0; y < gridMap.Height; y++)
                {
                    var cell = gridMap.Cells[x, y];
                    
                    // 只计算可通行的网格
                    if (cell.HasAnyWalkableLayer())
                    {
                        walkableCount++;
                        double cellZ = cell.HeightLayers != null && cell.HeightLayers.Count > 0
                            ? cell.HeightLayers[0].Z
                            : 0;
                        
                        if (cellZ < minZ)
                            minZ = cellZ;
                        if (cellZ > maxZ)
                            maxZ = cellZ;

                        double roundedElevation = Math.Round(cellZ, 3);
                        if (elevationCounts.ContainsKey(roundedElevation))
                        {
                            elevationCounts[roundedElevation]++;
                        }
                        else
                        {
                            elevationCounts[roundedElevation] = 1;
                        }
                    }
                }
            }

            // 如果没有可通行网格，返回默认值
            if (walkableCount == 0)
            {
                LogManager.Warning("[通道Z值计算] 未找到可通行网格，使用默认Z值范围");
                minZ = 0.0;
                maxZ = 0.0;
            }

            LogManager.Info($"[通道Z值计算] 计算完成 - 可通行网格: {walkableCount}个, Z范围: [{minZ:F2}, {maxZ:F2}], 高度差: {maxZ - minZ:F2}");
            if (elevationCounts.Count > 0)
            {
                string distributionSummary = string.Join(
                    ", ",
                    elevationCounts
                        .OrderByDescending(kvp => kvp.Value)
                        .ThenBy(kvp => kvp.Key)
                        .Take(8)
                        .Select(kvp => $"{kvp.Key:F3}:{kvp.Value}"));
                LogManager.Info($"[通道Z值计算] 可通行格高程分布样本(Top8): {distributionSummary}");
            }

            return (minZ, maxZ, walkableCount);
        }


        /// <summary>
        /// 将通道投影到网格
        /// 统一投影方式：基于三角形几何的精确投影，解决楼板洞口和不规则形状问题
        /// </summary>
        /// <param name="channel">通道物品</param>
        /// <param name="gridMap">目标网格地图</param>
        private void ProjectChannelToGrid(ModelItem channel, GridMap gridMap)
        {
            LogManager.Info($"[通道网格构建器] 投影通道: {channel.DisplayName}");

            // 获取通道限速（一次性查询，避免重复COM API调用）
            double channelSpeedLimit = CategoryAttributeManager.GetSpeedLimit(channel);

            // 提取三角形几何
            var triangles = GeometryHelper.ExtractTriangles(new[] { channel });
            if (triangles.Count == 0)
            {
                LogManager.Warning($"[通道网格构建器] 未能从 '{channel.DisplayName}' 提取到三角形");
                return;
            }

            double upwardTriangleMinElevation = double.MaxValue;
            double upwardTriangleMaxElevation = double.MinValue;

            // 统一投影处理
            int processedTriangles = 0;
            foreach (var triangle in triangles)
            {
                var normal = ComputeTriangleNormal(triangle);

                // 根据法向量决定处理方式（使用坐标系判断向上）
                if (GetUpComponent(normal) > 0)  // 朝上的面
                {
                    upwardTriangleMinElevation = Math.Min(
                        upwardTriangleMinElevation,
                        Math.Min(
                            _coordinateSystem.GetElevation(triangle.Point1),
                            Math.Min(_coordinateSystem.GetElevation(triangle.Point2), _coordinateSystem.GetElevation(triangle.Point3))));
                    upwardTriangleMaxElevation = Math.Max(
                        upwardTriangleMaxElevation,
                        Math.Max(
                            _coordinateSystem.GetElevation(triangle.Point1),
                            Math.Max(_coordinateSystem.GetElevation(triangle.Point2), _coordinateSystem.GetElevation(triangle.Point3))));

                    RasterizeTriangleToGrid(gridMap, triangle, channel, channelSpeedLimit);
                    processedTriangles++;
                }
                // 垂直面和朝下的面不投影
            }
            
            LogManager.Info($"[通道网格构建器] 投影完成：{processedTriangles}/{triangles.Count} 个三角形");
            if (processedTriangles > 0)
            {
                LogManager.Info(
                    $"[通道网格构建器] 朝上三角高程范围: [{upwardTriangleMinElevation:F2}, {upwardTriangleMaxElevation:F2}]");
            }
        }

        /// <summary>
        /// 计算三角形法向量
        /// </summary>
        /// <param name="triangle">三角形</param>
        /// <returns>法向量</returns>
        private Point3D ComputeTriangleNormal(Triangle3D triangle)
        {
            var edge1 = new Point3D(
                triangle.Point2.X - triangle.Point1.X,
                triangle.Point2.Y - triangle.Point1.Y,
                triangle.Point2.Z - triangle.Point1.Z);
            
            var edge2 = new Point3D(
                triangle.Point3.X - triangle.Point1.X,
                triangle.Point3.Y - triangle.Point1.Y,
                triangle.Point3.Z - triangle.Point1.Z);

            // 计算叉积
            var normal = new Point3D(
                edge1.Y * edge2.Z - edge1.Z * edge2.Y,
                edge1.Z * edge2.X - edge1.X * edge2.Z,
                edge1.X * edge2.Y - edge1.Y * edge2.X);

            // 归一化
            double length = Math.Sqrt(normal.X * normal.X + normal.Y * normal.Y + normal.Z * normal.Z);
            if (length > 0.0001)
            {
                normal = new Point3D(normal.X / length, normal.Y / length, normal.Z / length);
            }

            return normal;
        }
        
        /// <summary>
        /// 获取向上轴的分量（根据坐标系）
        /// </summary>
        private double GetUpComponent(Point3D vector)
        {
            return _coordinateSystem.GetElevation(vector);
        }




        /// <summary>
        /// 将三角形光栅化到网格
        /// </summary>
        /// <param name="gridMap">网格地图</param>
        /// <param name="triangle">三角形</param>
        /// <param name="channel">通道模型项</param>
        /// <param name="channelSpeedLimit">预计算的通道限速</param>
        private void RasterizeTriangleToGrid(GridMap gridMap, Triangle3D triangle, ModelItem channel, double channelSpeedLimit)
        {
            // 获取三角形的2D投影边界框（使用水平坐标）
            var (p1h1, p1h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point1);
            var (p2h1, p2h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point2);
            var (p3h1, p3h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point3);
            
            var minH1 = Math.Min(p1h1, Math.Min(p2h1, p3h1));
            var maxH1 = Math.Max(p1h1, Math.Max(p2h1, p3h1));
            var minH2 = Math.Min(p1h2, Math.Min(p2h2, p3h2));
            var maxH2 = Math.Max(p1h2, Math.Max(p2h2, p3h2));

            var minGrid = gridMap.WorldToGrid(_coordinateSystem.CreatePoint(minH1, minH2, 0));
            var maxGrid = gridMap.WorldToGrid(_coordinateSystem.CreatePoint(maxH1, maxH2, 0));

            // 遍历边界框内的所有网格点
            for (int x = minGrid.X; x <= maxGrid.X; x++)
            {
                for (int y = minGrid.Y; y <= maxGrid.Y; y++)
                {
                    var gridPos = new GridPoint2D(x, y);
                    if (gridMap.IsValidGridPosition(gridPos))
                    {
                        var worldPos = gridMap.GridToWorld3D(gridPos);
                        
                        // 检查点是否在三角形内部（使用2D水平投影）
                        if (IsPointInTriangleHorizontal(worldPos, triangle))
                        {
                            // 计算网格中心点在三角形平面上的精确高度
                            double gridCenterElevation = GetElevationAtPoint(triangle, worldPos);

                            // 创建高度层（追加模式，不覆盖）
                            var channelType = CategoryAttributeManager.GetCategoryId(channel);
                            var layer = new HeightLayer(
                                z: gridCenterElevation,
                                passableHeight: new HeightInterval(0, 0), // 初始化，后续由SetChannelPassableHeights设置
                                sourceItem: channel,
                                speedLimit: channelSpeedLimit,
                                type: channelType
                            );

                            // 追加高度层（支持同一网格多个高度）
                            gridMap.AddHeightLayer(gridPos, layer);
                        }
                    }
                }
            }
        }
        
        /// <summary>
        /// 检查点是否在三角形的水平投影内
        /// </summary>
        private bool IsPointInTriangleHorizontal(Point3D point, Triangle3D triangle)
        {
            var (ph1, ph2) = _coordinateSystem.GetHorizontalCoords(point);
            var (p1h1, p1h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point1);
            var (p2h1, p2h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point2);
            var (p3h1, p3h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point3);
            
            // 使用叉积法判断点是否在三角形内
            double Cross(double ax, double ay, double bx, double by) => ax * by - ay * bx;
            
            var d1 = Cross(ph1 - p1h1, ph2 - p1h2, p2h1 - p1h1, p2h2 - p1h2);
            var d2 = Cross(ph1 - p2h1, ph2 - p2h2, p3h1 - p2h1, p3h2 - p2h2);
            var d3 = Cross(ph1 - p3h1, ph2 - p3h2, p1h1 - p3h1, p1h2 - p3h2);
            
            bool hasNeg = (d1 < 0) || (d2 < 0) || (d3 < 0);
            bool hasPos = (d1 > 0) || (d2 > 0) || (d3 > 0);
            
            return !(hasNeg && hasPos);
        }
        
        /// <summary>
        /// 计算点在三角形平面上的高度值（根据当前坐标系）
        /// </summary>
        private double GetElevationAtPoint(Triangle3D triangle, Point3D point)
        {
            var normal = ComputeTriangleNormal(triangle);
            
            // 获取向上轴的分量
            double upComponent = GetUpComponent(normal);
            
            // 如果向上分量接近0，说明是垂直面，返回第一个点的Z值
            if (Math.Abs(upComponent) < 0.0001)
            {
                return _coordinateSystem.GetElevation(triangle.Point1);
            }
            
            // 获取各点的水平坐标
            var (p1h1, p1h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point1);
            var (ph1, ph2) = _coordinateSystem.GetHorizontalCoords(point);
            
            // 获取向上轴的索引来正确计算
            int upAxis = _coordinateSystem.UpAxisIndex;
            
            // 使用平面方程计算点的高度
            // n_x(x-x0) + n_y(y-y0) + n_z(z-z0) = 0
            // 解出高度值
            double elevation;
            if (upAxis == 2) // Z-up
            {
                elevation = triangle.Point1.Z - (normal.X * (ph1 - p1h1) + normal.Y * (ph2 - p1h2)) / normal.Z;
            }
            else // Y-up
            {
                elevation = triangle.Point1.Y - (normal.X * (ph1 - p1h1) + normal.Z * (ph2 - p1h2)) / normal.Y;
            }
            
            return elevation;
        }




        /// <summary>
        /// 创建空的通道覆盖
        /// </summary>
        /// <returns>空的通道覆盖</returns>
        private ChannelCoverage CreateEmptyChannelCoverage()
        {
            var emptyBounds = new BoundingBox3D(new Point3D(0, 0, 0), new Point3D(0, 0, 0));
            return new ChannelCoverage
            {
                GridMap = new GridMap(emptyBounds, 1.0, _coordinateSystem),
                ChannelItems = new List<ModelItem>(),
                TotalBounds = emptyBounds
            };
        }

        /// <summary>
        /// 格式化边界框信息用于日志
        /// </summary>
        /// <param name="bounds">边界框</param>
        /// <returns>格式化字符串</returns>
        private string FormatBounds(BoundingBox3D bounds)
        {
            var (min1, max1, min2, max2) = _coordinateSystem.GetHorizontalRange(bounds);
            var (minElev, maxElev) = _coordinateSystem.GetHeightRange(bounds);
            return $"[H1:{min1:F2}-{max1:F2}, H2:{min2:F2}-{max2:F2}, Elev:{minElev:F2}-{maxElev:F2}]";
        }
    }


}
