using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Core.Config;
using NavisworksTransport.Utils;
using Newtonsoft.Json.Linq;

namespace NavisworksTransport.Core.Services
{
    /// <summary>
    /// 剖面盒自动检测器（F1，方案：doc/working/2026-08-04-sectionbox-batch-detection-plan.md）。
    ///
    /// 对"非指定碰撞对象"（DetectAllObjects=true，全模型检测）的批处理任务：
    /// 1. 计算路径包围盒 + 膨胀（物体尺寸 + 安全间隙）
    /// 2. 导出局部 NWD（剔除盒外对象，ExcludeHiddenItems=true）
    /// 3. 外部启动副 Navisworks 实例（端口隔离 TRANSPORTPLUGIN_TEST_PORT=18778）
    /// 4. 通过 HTTP 驱动副实例：导入路径 → 运行动画检测（虚拟物体）
    /// 5. 回传碰撞报告（统计 + 碰撞对象名字；PathId/位置映射属 F2）
    ///
    /// 原理：大模型全模型检测小时级 → 局部模型分钟级（E4 已验证链路）。
    /// 副实例通过环境变量 TRANSPORTPLUGIN_DISABLE_SECTIONBOX_BATCH=1 可整体禁用。
    /// </summary>
    public class SectionBoxBatchDetector
    {
        private const string DisableEnvironmentVariable = "TRANSPORTPLUGIN_DISABLE_SECTIONBOX_BATCH";

        public static bool Enabled
        {
            get
            {
                string raw = Environment.GetEnvironmentVariable(DisableEnvironmentVariable);
                return !string.Equals(raw, "1", StringComparison.OrdinalIgnoreCase);
            }
        }

        public class DetectionResult
        {
            public bool Success { get; set; }
            public int TotalCollisions { get; set; }
            public int UniqueCollidedObjectsCount { get; set; }
            public List<string> CollidedObjects { get; set; } = new List<string>();
            public int TotalFrames { get; set; }
            public string LocalModelPath { get; set; }
            public string ErrorMessage { get; set; }

            /// <summary>
            /// F2：碰撞对象映射（名称 → 主模型 PathId，按层级链匹配）
            /// </summary>
            public List<CollidedObjectMapping> CollidedObjectMappings { get; set; } = new List<CollidedObjectMapping>();
        }

        /// <summary>
        /// F2：碰撞对象映射（副实例 → 主模型）。
        /// </summary>
        public class CollidedObjectMapping
        {
            public string Name { get; set; }
            public string SecondaryPathId { get; set; }
            public string MainPathId { get; set; }
        }

        // F1 总流程硬超时：超时强制关闭副实例并失败，避免批处理无限等待
        private static readonly TimeSpan OverallTimeout = TimeSpan.FromMinutes(6);

        private static TimeSpan Remaining(DateTime overallDeadline)
        {
            TimeSpan remaining = overallDeadline - DateTime.UtcNow;
            return remaining > TimeSpan.Zero ? remaining : TimeSpan.Zero;
        }

        /// <summary>
        /// 执行剖面盒自动检测。必须在主 NW 的 UI 线程上下文调用（内部导出走 Dispatcher）。
        /// 副实例的启动/就绪/关闭委托 NavisworksInstanceManager（独立模块，多实例端口池分配）。
        /// 工作目录内文件名带 instanceId 唯一标识，支持多实例并行/重试同目录不冲突。
        /// </summary>
        public async Task<DetectionResult> RunAsync(
            PathRoute route,
            string instanceId,
            bool isVirtualObject,
            string movingObjectName,
            string expectedAncestorChain,
            int movingModelIndex,
            string movingObjectPathId,
            double virtualObjectLengthModelUnits,
            double virtualObjectWidthModelUnits,
            double virtualObjectHeightModelUnits,
            int frameRate,
            double durationSeconds,
            string workDirectory)
        {
            var result = new DetectionResult();
            DateTime overallDeadline = DateTime.UtcNow.Add(OverallTimeout);

            try
            {
                Document document = Application.ActiveDocument;
                if (document == null)
                {
                    result.ErrorMessage = "无活动文档";
                    return result;
                }

                Directory.CreateDirectory(workDirectory);
                string safeId = string.IsNullOrWhiteSpace(instanceId) ? Guid.NewGuid().ToString("N") : instanceId;
                string localModelPath = Path.Combine(workDirectory, $"model-{safeId}.nwd");
                string routeFilePath = Path.Combine(workDirectory, $"route-{safeId}.json");
                string secondaryDbPath = Path.Combine(workDirectory, $"secondary-{safeId}.db");

                // 1. 路径剖面盒（复用产品路径盒语义：路径点 + 虚拟物体高度附加点 + 水平 4m/高度 2m 扩展）
                //    与 LogisticsControlViewModel.EnableClipBoxForCurrentRoute 一致（地面路径点上方、空中路径下方加物体高度）
                var adjustedPoints = route.Points
                    .Select(p => new Point3D(p.X, p.Y, p.Z))
                    .ToList();
                double objectHeightModelUnits = isVirtualObject ? virtualObjectHeightModelUnits : 0.0;
                if (objectHeightModelUnits > 0)
                {
                    foreach (var p in route.Points)
                    {
                        double delta = route.PathType == PathType.Ground ? objectHeightModelUnits : -objectHeightModelUnits;
                        adjustedPoints.Add(new Point3D(p.X, p.Y, p.Z + delta));
                    }
                }

                BoundingBox3D bounds = SectionClipHelper.CalculatePathClipBox(adjustedPoints, 4.0, 2.0);

                // 2. 导出局部 NWD（UI 线程：NW API + 导出）；同时构建盒内对象映射（chain→主PathId，F2 用）
                bool exported = false;
                var chainToMainPathId = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
                try
                {
                    exported = System.Windows.Application.Current.Dispatcher.Invoke(() =>
                    {
                        // 导出前：把移动物体恢复到路径起点（加入批处理时的位置），确保导出包含移动物体。
                        // 真实物体可能已被后续操作移回 CAD 原位置（甚至不在路径剖面盒内）。
                        if (!isVirtualObject && !string.IsNullOrWhiteSpace(movingObjectPathId))
                        {
                            try
                            {
                                var pathAnim = Core.Animation.PathAnimationManager.GetInstance();
                                if (pathAnim != null && route != null)
                                {
                                    pathAnim.SetRoute(route);
                                    var movingItem = document.Models.ResolvePathId(new Autodesk.Navisworks.Api.DocumentParts.ModelItemPathId
                                    {
                                        ModelIndex = movingModelIndex,
                                        PathId = movingObjectPathId
                                    });
                                    if (movingItem != null)
                                    {
                                        pathAnim.MoveObjectToPathStart(
                                            movingItem, route.Points.Select(p => p.Position).ToList());
                                        LogManager.Info($"[剖面盒批检测] 移动物体已恢复到路径起点: {movingItem.DisplayName}");
                                    }
                                    else
                                    {
                                        LogManager.Warning($"[剖面盒批检测] 无法解析移动物体 ModelItem（{movingObjectPathId}），导出可能不包含该物体");
                                    }
                                }
                            }
                            catch (Exception moveEx)
                            {
                                LogManager.Warning($"[剖面盒批检测] 移动物体恢复到起点失败: {moveEx.Message}");
                            }
                        }

                        var exporter = new SectionBoxExporter();
                        var traversal = exporter.GetObjectsAndHiddenItems(document, bounds);
                        if (traversal.ObjectsInBox.Count == 0)
                        {
                            LogManager.Warning($"[剖面盒批检测] 路径包围盒内无对象: {route.Name}");
                            return false;
                        }

                        // F2：记录盒内对象映射（层级链去根 → 主模型 PathId）
                        foreach (ModelItem boxItem in traversal.ObjectsInBox)
                        {
                            string chain = BuildAncestorChain(boxItem);
                            if (string.IsNullOrWhiteSpace(chain))
                            {
                                continue;
                            }

                            try
                            {
                                var path = document.Models.CreatePathId(boxItem);
                                chainToMainPathId[TrimRootFromChain(chain)] = path.PathId;
                            }
                            catch
                            {
                            }
                        }
                        LogManager.Info($"[剖面盒批检测] 盒内对象映射: {chainToMainPathId.Count} 条");

                        string exportedPath = exporter.ExportToNwd(document, traversal, localModelPath);
                        return !string.IsNullOrEmpty(exportedPath) && File.Exists(exportedPath);
                    });
                }
                catch (Exception ex)
                {
                    result.ErrorMessage = $"导出局部 NWD 失败: {ex.Message}";
                    return result;
                }

                if (!exported)
                {
                    result.ErrorMessage = "路径包围盒内无对象或 NWD 导出失败";
                    return result;
                }
                result.LocalModelPath = localModelPath;

                // 3. 导出路径文件（JSON，副实例导入用）
                new PathDataManager().ExportToJson(new List<PathRoute> { route }, routeFilePath);

                // 4. 通过 NavisworksInstanceManager 启动副实例（独立模块：端口池分配/进程定位/关闭清理）
                //    注入临时库路径：导出模型无同名 .db，检测记录需落库才能生成报告
                using (var handle = NavisworksInstanceManager.Instance.LaunchInstance(localModelPath, secondaryDbPath))
                {
                    if (handle == null)
                    {
                        result.ErrorMessage = "副实例启动失败（端口池耗尽或进程未定位）";
                        return result;
                    }

                    // 就绪等待（ping + 路径数据库 + 进程存活监控，InstanceManager 内置）
                    if (!await handle.WaitReadyAsync(Remaining(overallDeadline)).ConfigureAwait(false))
                    {
                        result.ErrorMessage = "副实例就绪失败（服务/数据库未就绪或进程退出）";
                        return result;
                    }

                    using (var client = handle.CreateClient())
                    {
                        if (!await ImportRouteAsync(client, handle, routeFilePath).ConfigureAwait(false))
                        {
                            result.ErrorMessage = "副实例导入路径失败";
                            return result;
                        }

                        // 真实物体运动体：在副实例中按层级链（导出保留树结构，去掉根后与主模型一致）解析 PathId
                        string animatedObjectPath = null;
                        if (!isVirtualObject)
                        {
                            animatedObjectPath = await ResolveRealObjectPathIdAsync(
                                client, route, movingObjectName, expectedAncestorChain).ConfigureAwait(false);
                            if (string.IsNullOrWhiteSpace(animatedObjectPath))
                            {
                                result.ErrorMessage = $"副实例中无法解析真实物体: {movingObjectName}";
                                return result;
                            }
                        }

                        return await RunDetectionAsync(
                            client, route, isVirtualObject, animatedObjectPath,
                            virtualObjectLengthModelUnits, virtualObjectWidthModelUnits,
                            virtualObjectHeightModelUnits, frameRate, durationSeconds, result,
                            chainToMainPathId, handle, overallDeadline).ConfigureAwait(false);
                    }
                }
            }
            catch (Exception ex)
            {
                result.ErrorMessage = ex.Message;
                LogManager.Error($"[剖面盒批检测] 失败: {ex.Message}", ex);
            }

            return result;
        }

        /// <summary>
        /// 向副实例导入路径文件（route.json），供检测使用。
        /// </summary>
        private static async Task<bool> ImportRouteAsync(HttpClient client, NavisworksInstanceHandle handle, string routeFilePath)
        {
            // 副实例进程已退出 → 立即失败
            if (handle != null && !handle.IsRunning)
            {
                LogManager.Warning("[剖面盒批检测] 副实例进程已退出，导入路径中止");
                return false;
            }

            string requestUri = "/api/test/import-route-file?path=" + Uri.EscapeDataString(routeFilePath) + "&overwrite=true";
            using (var response = await client.PostAsync(requestUri, new StringContent(string.Empty)).ConfigureAwait(false))
            {
                if (!response.IsSuccessStatusCode)
                {
                    return false;
                }

                string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                JObject payload = JObject.Parse(content);
                return payload.Value<bool?>("ok") == true;
            }
        }

        /// <summary>
        /// <summary>
        /// 在副实例中解析真实物体运动体：优先按层级链匹配（导出剖面盒保留节点树结构，
        /// 去掉根文件名后主/副实例 ancestorChain 一致），fallback 按名字 + 离路径起点最近。
        /// </summary>
        private static async Task<string> ResolveRealObjectPathIdAsync(
            HttpClient client, PathRoute route, string movingObjectName, string expectedAncestorChain)
        {
            if (string.IsNullOrWhiteSpace(movingObjectName))
            {
                return null;
            }

            Point3D start = route.Points?.OrderBy(p => p.Index).FirstOrDefault()?.Position;
            string expectedTail = TrimRootFromChain(expectedAncestorChain);

            for (int attempt = 0; attempt < 15; attempt++)
            {
                string requestUri = "/api/test/list-model-items?name=" + Uri.EscapeDataString(movingObjectName) + "&maxResults=100";
                try
                {
                    using (var response = await client.GetAsync(requestUri).ConfigureAwait(false))
                    {
                        if (!response.IsSuccessStatusCode)
                        {
                            await Task.Delay(2000).ConfigureAwait(false);
                            continue;
                        }

                        string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                        JObject payload = JObject.Parse(content);
                        if (payload.Value<bool?>("ok") != true)
                        {
                            await Task.Delay(2000).ConfigureAwait(false);
                            continue;
                        }

                        JArray items = (JArray)((JObject)payload["data"])["items"];
                        if (items == null || items.Count == 0)
                        {
                            LogManager.Info($"[剖面盒批检测] 副实例解析移动物体第 {attempt + 1} 次未找到: {movingObjectName}");
                            await Task.Delay(2000).ConfigureAwait(false);
                            continue;
                        }

                        // 优先层级链匹配（去掉根后一致）
                        if (!string.IsNullOrWhiteSpace(expectedTail))
                        {
                            foreach (JToken token in items)
                            {
                                string chain = (string)token["ancestorChain"];
                                string pathId = (string)token["pathId"];
                                if (string.IsNullOrWhiteSpace(chain) || string.IsNullOrWhiteSpace(pathId))
                                {
                                    continue;
                                }

                                if (string.Equals(TrimRootFromChain(chain), expectedTail, StringComparison.OrdinalIgnoreCase))
                                {
                                    LogManager.Info($"[剖面盒批检测] 副实例按层级链匹配成功: {movingObjectName} -> {pathId}");
                                    return pathId;
                                }
                            }
                        }

                        // fallback：离路径起点最近的实例
                        if (start != null)
                        {
                            string bestPathId = null;
                            double bestDistanceSq = double.MaxValue;
                            foreach (JToken token in items)
                            {
                                JObject item = (JObject)token;
                                JObject center = (JObject)item["boundingBoxCenter"];
                                string pathId = (string)item["pathId"];
                                if (center == null || string.IsNullOrWhiteSpace(pathId))
                                {
                                    continue;
                                }

                                double dx = (double)center["x"] - start.X;
                                double dy = (double)center["y"] - start.Y;
                                double dz = (double)center["z"] - start.Z;
                                double distanceSq = dx * dx + dy * dy + dz * dz;
                                if (distanceSq < bestDistanceSq)
                                {
                                    bestDistanceSq = distanceSq;
                                    bestPathId = pathId;
                                }
                            }

                            if (!string.IsNullOrWhiteSpace(bestPathId))
                            {
                                LogManager.Info($"[剖面盒批检测] 副实例按位置匹配成功: {movingObjectName} -> {bestPathId}");
                                return bestPathId;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Warning($"[剖面盒批检测] 副实例解析移动物体异常: {ex.Message}");
                }

                await Task.Delay(2000).ConfigureAwait(false);
            }

            return null;
        }

        /// <summary>
        /// 去掉 ancestorChain 的第一个段（根模型文件名），剩余部分主/副实例一致（导出保留树结构）。
        /// </summary>
        private static string TrimRootFromChain(string chain)
        {
            if (string.IsNullOrWhiteSpace(chain))
            {
                return null;
            }

            string[] segments = chain.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
            if (segments.Length <= 1)
            {
                return chain.Trim();
            }

            return string.Join(" / ", segments.Skip(1).Select(s => s.Trim()));
        }

        /// <summary>
        /// 构造 ModelItem 的层级链（AncestorsAndSelf 的 DisplayName，'/' 分隔）。
        /// </summary>
        private static string BuildAncestorChain(ModelItem item)
        {
            try
            {
                var segments = new List<string>();
                var current = item;
                int guard = 0;

                while (current != null && guard < 15)
                {
                    var name = current.DisplayName;
                    if (!string.IsNullOrWhiteSpace(name))
                    {
                        segments.Add(name.Trim());
                    }
                    current = current.Parent;
                    guard++;
                }

                segments.Reverse();
                return string.Join(" / ", segments);
            }
            catch
            {
                return null;
            }
        }

        private static async Task<DetectionResult> RunDetectionAsync(
            HttpClient client,
            PathRoute route,
            bool isVirtualObject,
            string animatedObjectPath,
            double objectLengthModelUnits,
            double objectWidthModelUnits,
            double objectHeightModelUnits,
            int frameRate,
            double durationSeconds,
            DetectionResult result,
            Dictionary<string, string> chainToMainPathId,
            NavisworksInstanceHandle handle,
            DateTime overallDeadline)
        {
            // 副实例进程已退出 → 立即失败
            if (handle != null && !handle.IsRunning)
            {
                result.ErrorMessage = "副实例进程已退出，检测中止";
                return result;
            }

            // 动画参数从模型单位换算回米（副实例 config 以米存储）
            double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor();
            double lengthMeters = objectLengthModelUnits / metersToModelUnits;
            double widthMeters = objectWidthModelUnits / metersToModelUnits;
            double heightMeters = objectHeightModelUnits / metersToModelUnits;

            string requestUri = string.Format(
                System.Globalization.CultureInfo.InvariantCulture,
                "/api/test/run-virtual-collision-test?pathType={0}&routeName={1}&useVirtualObject={2}&frameRate={3}&durationSeconds={4}&timeoutSeconds=240",
                Uri.EscapeDataString(route.PathType.ToString()),
                Uri.EscapeDataString(route.Name),
                isVirtualObject ? "true" : "false",
                frameRate,
                durationSeconds);

            if (!isVirtualObject && !string.IsNullOrWhiteSpace(animatedObjectPath))
            {
                requestUri += "&animatedObjectPath=" + Uri.EscapeDataString(animatedObjectPath);
            }

            // 副实例进程存活监控 + 总 deadline：进程退出或超时 → 取消挂起的检测请求（避免批处理无限等待）
            using (var cts = new CancellationTokenSource())
            {
                TimeSpan remaining = Remaining(overallDeadline);
                if (remaining <= TimeSpan.Zero)
                {
                    result.ErrorMessage = "F1 总流程超时，检测中止";
                    return result;
                }

                cts.CancelAfter(remaining);

                var httpTask = client.PostAsync(requestUri, new StringContent(string.Empty), cts.Token);
                var processMonitorTask = Task.Run(async () =>
                {
                    try
                    {
                        while (!cts.IsCancellationRequested)
                        {
                            if (handle != null && !handle.IsRunning)
                            {
                                LogManager.Warning("[剖面盒批检测] 副实例进程退出，取消检测请求");
                                cts.Cancel();
                                return;
                            }

                            await Task.Delay(500, cts.Token).ConfigureAwait(false);
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        // 取消是预期的（总超时/进程退出触发），不作为未观察异常
                    }
                }, cts.Token);

                try
                {
                    using (var response = await httpTask.ConfigureAwait(false))
                    {
                        if (!response.IsSuccessStatusCode)
                        {
                            result.ErrorMessage = $"副实例检测失败: HTTP {(int)response.StatusCode}";
                            return result;
                        }

                        string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                        JObject payload = JObject.Parse(content);
                        if (payload.Value<bool?>("ok") != true)
                        {
                            result.ErrorMessage = $"副实例检测失败: {payload["error"]}";
                            return result;
                        }

                        JObject data = (JObject)payload["data"];
                        result.TotalFrames = (int)((JObject)data["animation"])["totalFrames"];

                        JObject report = (JObject)data["report"];
                        if (report != null)
                        {
                            result.TotalCollisions = (int)report["totalCollisions"];
                            result.UniqueCollidedObjectsCount = (int)report["uniqueCollidedObjectsCount"];
                            JArray collided = (JArray)report["collidedObjects"];
                            if (collided != null)
                            {
                                foreach (JToken token in collided)
                                {
                                    JObject obj = (JObject)token;
                                    string name = (string)obj["name"];
                                    if (string.IsNullOrWhiteSpace(name))
                                    {
                                        continue;
                                    }

                                    var mapping = new CollidedObjectMapping
                                    {
                                        Name = name,
                                        SecondaryPathId = (string)obj["pathId"]
                                    };

                                    // F2：按层级链（去根）查盒内对象映射 → 主模型 PathId
                                    string chain = (string)obj["ancestorChain"];
                                    if (!string.IsNullOrWhiteSpace(chain))
                                    {
                                        string tail = TrimRootFromChain(chain);
                                        if (tail != null && chainToMainPathId != null && chainToMainPathId.TryGetValue(tail, out string mainPathId))
                                        {
                                            mapping.MainPathId = mainPathId;
                                        }
                                    }

                                    result.CollidedObjects.Add(name);
                                    result.CollidedObjectMappings.Add(mapping);
                                }
                            }
                        }

                        result.Success = true;
                        return result;
                    }
                }
                catch (OperationCanceledException)
                {
                    // 副实例进程退出或总 deadline 超时（cts.Cancel）
                    bool processExited = handle != null && !handle.IsRunning;
                    result.ErrorMessage = processExited
                        ? "副实例进程在检测中退出"
                        : "副实例检测超时（总 deadline 到达）";
                    return result;
                }
                catch (Exception ex)
                {
                    result.ErrorMessage = $"副实例检测异常: {ex.Message}";
                    return result;
                }
                finally
                {
                    // 通知 processMonitorTask 退出（cts 取消），再 await 观察残余异常，避免 UnobservedTaskException
                    try { cts.Cancel(); } catch { }
                    try
                    {
                        await processMonitorTask.ConfigureAwait(false);
                    }
                    catch
                    {
                    }
                }
            }
        }
    }
}
