using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Autodesk.Navisworks.Api;

namespace NavisworksTransport.PathPlanning
{
    /// <summary>
    /// GridMap缓存键，用于标识唯一的GridMap生成配置
    /// 基于所有物流属性构件、物体尺寸、网格尺寸等关键参数
    /// </summary>
    public class GridMapCacheKey : IEquatable<GridMapCacheKey>
    {
        /// <summary>
        /// 物流数据哈希值（所有物流属性构件，包括通道、门、无关项等）
        /// </summary>
        public string LogisticsDataHash { get; set; }

        /// <summary>
        /// 边界范围哈希
        /// </summary>
        public string BoundsHash { get; set; }

        /// <summary>
        /// 网格单元大小（模型单位）
        /// </summary>
        public double CellSize { get; set; }

        /// <summary>
        /// 物体半径（米）
        /// </summary>
        public double ObjectRadius { get; set; }

        /// <summary>
        /// 安全间隙（米）
        /// </summary>
        public double SafetyMargin { get; set; }

        /// <summary>
        /// 物体高度（米）
        /// </summary>
        public double ObjectHeight { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        public GridMapCacheKey(string logisticsDataHash, string boundsHash, double cellSize,
                              double objectRadius, double safetyMargin, double objectHeight)
        {
            LogisticsDataHash = logisticsDataHash ?? throw new ArgumentNullException(nameof(logisticsDataHash));
            BoundsHash = boundsHash ?? throw new ArgumentNullException(nameof(boundsHash));
            CellSize = cellSize;
            ObjectRadius = objectRadius;
            SafetyMargin = safetyMargin;
            ObjectHeight = objectHeight;
        }

        /// <summary>
        /// 检查两个缓存键是否相等
        /// </summary>
        public bool Equals(GridMapCacheKey other)
        {
            if (other == null) return false;
            if (ReferenceEquals(this, other)) return true;

            return LogisticsDataHash == other.LogisticsDataHash &&
                   BoundsHash == other.BoundsHash &&
                   Math.Abs(CellSize - other.CellSize) < 1e-6 &&
                   Math.Abs(ObjectRadius - other.ObjectRadius) < 1e-6 &&
                   Math.Abs(SafetyMargin - other.SafetyMargin) < 1e-6 &&
                   Math.Abs(ObjectHeight - other.ObjectHeight) < 1e-6;
        }

        /// <summary>
        /// 重写Equals方法
        /// </summary>
        public override bool Equals(object obj)
        {
            return Equals(obj as GridMapCacheKey);
        }

        /// <summary>
        /// 计算哈希码，用于Dictionary键
        /// </summary>
        public override int GetHashCode()
        {
            unchecked
            {
                int hash = 17;
                hash = hash * 23 + (LogisticsDataHash?.GetHashCode() ?? 0);
                hash = hash * 23 + (BoundsHash?.GetHashCode() ?? 0);
                hash = hash * 23 + CellSize.GetHashCode();
                hash = hash * 23 + ObjectRadius.GetHashCode();
                hash = hash * 23 + SafetyMargin.GetHashCode();
                hash = hash * 23 + ObjectHeight.GetHashCode();
                return hash;
            }
        }

        /// <summary>
        /// 生成可读的字符串表示
        /// </summary>
        public override string ToString()
        {
            var logisticsPreview = LogisticsDataHash != null ?
                LogisticsDataHash.Substring(0, Math.Min(8, LogisticsDataHash.Length)) :
                "NULL";
            var boundsPreview = BoundsHash != null ?
                BoundsHash.Substring(0, Math.Min(8, BoundsHash.Length)) :
                "NULL";

            return $"GridMapKey[Logistics={logisticsPreview}, Bounds={boundsPreview}, " +
                   $"Cell={CellSize:F2}, OR={ObjectRadius:F1}m, SM={SafetyMargin:F1}m, OH={ObjectHeight:F1}m]";
        }

        /// <summary>
        /// 根据参数生成GridMap缓存键
        /// </summary>
        /// <param name="bounds">边界范围</param>
        /// <param name="cellSize">网格大小</param>
        /// <param name="objectRadius">物体半径（米）</param>
        /// <param name="safetyMargin">安全间隙（米）</param>
        /// <param name="objectHeight">物体高度（米）</param>
        /// <returns>缓存键</returns>
        public static GridMapCacheKey CreateFrom(BoundingBox3D bounds,
                                               double cellSize, double objectRadius,
                                               double safetyMargin, double objectHeight)
        {
            var logisticsDataHash = ComputeLogisticsDataHash();
            var boundsHash = ComputeBoundsHash(bounds);

            return new GridMapCacheKey(logisticsDataHash, boundsHash, cellSize,
                                     objectRadius, safetyMargin, objectHeight);
        }

        /// <summary>
        /// 计算物流数据哈希值
        /// 基于所有物流属性构件（包括通道、门、无关项等）的ID、属性、几何等信息
        /// </summary>
        /// <returns>物流数据哈希</returns>
        private static string ComputeLogisticsDataHash()
        {
            try
            {
                using (var sha256 = SHA256.Create())
                {
                    var hashBuilder = new StringBuilder();

                    // 获取所有有物流属性的模型项（不仅仅是可通行项）
                    var allLogisticsItems = CategoryAttributeManager.GetAllLogisticsItems();

                    // 按InstanceGuid排序确保一致性
                    var sortedItems = allLogisticsItems.OrderBy(item => item.InstanceGuid.ToString()).ToList();

                    hashBuilder.Append($"LogisticsCount:{sortedItems.Count}|");

                    foreach (var item in sortedItems)
                    {
                        // 基本标识信息
                        hashBuilder.Append($"ID:{item.InstanceGuid}|");
                        hashBuilder.Append($"DisplayName:{item.DisplayName ?? "NULL"}|");

                        // 几何信息（包围盒）
                        var bbox = item.BoundingBox();
                        if (bbox != null)
                        {
                            hashBuilder.Append($"BBox:{bbox.Min.X:F3},{bbox.Min.Y:F3},{bbox.Min.Z:F3}-");
                            hashBuilder.Append($"{bbox.Max.X:F3},{bbox.Max.Y:F3},{bbox.Max.Z:F3}|");
                        }

                        // 物流类型属性
                        var logisticsType = CategoryAttributeManager.GetCategoryId(item);
                        hashBuilder.Append($"LogType:{logisticsType}|");

                        // Transform信息（如果有变换）
                        var transform = item.Transform;
                        if (transform != null)
                        {
                            // 只包含关键的变换信息
                            hashBuilder.Append($"TX:{transform.Translation.X:F3},{transform.Translation.Y:F3},{transform.Translation.Z:F3}|");
                        }
                    }

                    // 计算最终哈希
                    var hashInput = hashBuilder.ToString();
                    var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(hashInput));

                    var hexBuilder = new StringBuilder();
                    foreach (byte b in hashBytes)
                    {
                        hexBuilder.Append(b.ToString("x2"));
                    }

                    return hexBuilder.ToString();
                }
            }
            catch (Exception ex)
            {
                LogManager.Warning($"[物流哈希] 计算物流数据哈希失败: {ex.Message}，使用时间戳标识");
                return $"LOGISTICS_HASH_FAILED_{DateTime.Now.Ticks}";
            }
        }

        /// <summary>
        /// 计算边界范围哈希值
        /// </summary>
        /// <param name="bounds">边界范围</param>
        /// <returns>边界哈希</returns>
        private static string ComputeBoundsHash(BoundingBox3D bounds)
        {
            try
            {
                using (var sha256 = SHA256.Create())
                {
                    var boundsString = $"Bounds:{bounds.Min.X:F6},{bounds.Min.Y:F6},{bounds.Min.Z:F6}-" +
                                     $"{bounds.Max.X:F6},{bounds.Max.Y:F6},{bounds.Max.Z:F6}";

                    var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(boundsString));

                    var hexBuilder = new StringBuilder();
                    foreach (byte b in hashBytes)
                    {
                        hexBuilder.Append(b.ToString("x2"));
                    }

                    return hexBuilder.ToString();
                }
            }
            catch (Exception ex)
            {
                LogManager.Warning($"[边界哈希] 计算边界哈希失败: {ex.Message}，使用时间戳标识");
                return $"BOUNDS_HASH_FAILED_{DateTime.Now.Ticks}";
            }
        }
    }
}