using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json.Linq;

namespace NavisworksTransport.UnitTests.Integration
{
    /// <summary>
    /// 自动路径障碍绕行集成测试（覆盖计划 T07）。
    ///
    /// 构造起终点直线连线穿过障碍物的场景（跨越大半模型），验证：
    /// - AutoPlanPath 成功规划绕行路径（blockedSampleCount == 0，路径不穿过不可通行网格）
    /// - 规划长度 > 起终点直线距离（确实绕行，而非直线硬穿）
    ///
    /// 起终点坐标来自模型内已验证可用的区域（测试基准起点 → 自动测试_Ground 终点），
    /// 直线距离由测试按服务端返回的 metersToModelUnits 换算（不硬编码文档单位）。
    /// </summary>
    [TestClass]
    [TestCategory("NavisworksIntegration")]
    public class AutoPathObstacleDetourAutomationTests
    {
        private const string RouteName = "障碍绕行_测试";

        // 模型单位坐标：跨越大半模型的起终点（直线连线穿过障碍区域）
        private const double StartX = -204.608;
        private const double StartY = 14.833;
        private const double StartZ = 19.250;
        private const double EndX = -177.130;
        private const double EndY = 14.833;
        private const double EndZ = -4.383;

        private const double ObjectLengthInMeters = 0.4;
        private const double ObjectWidthInMeters = 0.4;
        private const double SafetyMarginInMeters = 0.05;
        private const double GridSizeInMeters = 0.3;

        [TestMethod]
        [Timeout(240000)]
        public async Task GroundAutoPath_ObstacleRoute_DetoursAroundObstacles()
        {
            using (var client = new NavisworksTestAutomationClient())
            {
                await client.EnsureServiceReadyAsync(TimeSpan.FromSeconds(90)).ConfigureAwait(false);

                string tempDir = Path.Combine(Path.GetTempPath(), "NavisworksTransportIntegrationTests", Guid.NewGuid().ToString("N"));
                Directory.CreateDirectory(tempDir);
                try
                {
                    // 1. 导入障碍起终点路径（overwrite 保证可重复执行）
                    string filePath = Path.Combine(tempDir, "obstacle-route.json");
                    File.WriteAllText(filePath, BuildObstacleRouteJson(), new UTF8Encoding(false));

                    JObject importResponse = await client.ImportRouteFileAsync(filePath, overwrite: true).ConfigureAwait(false);
                    Assert.IsTrue(importResponse.Value<bool>("ok"), "导入障碍路径失败: " + (string)importResponse["error"]);
                    double metersToModelUnits = importResponse["data"].Value<double>("metersToModelUnits");

                    // 2. 自动路径规划
                    JObject response = await client.RunAutoPathAsync(
                        "Ground",
                        RouteName,
                        ObjectLengthInMeters,
                        ObjectWidthInMeters,
                        SafetyMarginInMeters,
                        GridSizeInMeters).ConfigureAwait(false);
                    Assert.IsTrue(response.Value<bool>("ok"), "自动路径规划失败: " + (string)response["error"]);

                    JObject data = (JObject)response["data"];

                    // 3. 路径成功绕行：不穿过不可通行网格
                    JObject segmentValidation = (JObject)data["segmentValidation"];
                    Assert.IsNotNull(segmentValidation, "缺少 segmentValidation");
                    Assert.AreEqual(0, (int)segmentValidation["blockedSampleCount"], "绕行路径仍穿过不可通行网格");
                    Assert.AreEqual(0, (int)segmentValidation["invalidSampleCount"], "绕行路径存在落在网格外的采样点");

                    // 4. 确实绕行：规划长度 > 起终点直线距离（换算为米）
                    double straightLineModelUnits = Math.Sqrt(
                        (EndX - StartX) * (EndX - StartX) +
                        (EndY - StartY) * (EndY - StartY) +
                        (EndZ - StartZ) * (EndZ - StartZ));
                    double straightLineMeters = straightLineModelUnits / metersToModelUnits;

                    double plannedLength = (double)data["generatedRoute"]["length"];
                    Assert.IsTrue(
                        plannedLength > straightLineMeters * 1.02,
                        $"规划路径长度 {plannedLength:F3}m 应明显大于直线距离 {straightLineMeters:F3}m（未绕行？）");
                }
                finally
                {
                    SafeDelete(tempDir);
                }
            }
        }

        [TestMethod]
        [Timeout(240000)]
        public async Task GroundAutoPath_Strategies_ShortestAndStraightestBothSucceed()
        {
            using (var client = new NavisworksTestAutomationClient())
            {
                await client.EnsureServiceReadyAsync(TimeSpan.FromSeconds(90)).ConfigureAwait(false);

                string tempDir = Path.Combine(Path.GetTempPath(), "NavisworksTransportIntegrationTests", Guid.NewGuid().ToString("N"));
                Directory.CreateDirectory(tempDir);
                try
                {
                    string filePath = Path.Combine(tempDir, "obstacle-route.json");
                    File.WriteAllText(filePath, BuildObstacleRouteJson(), new UTF8Encoding(false));

                    JObject importResponse = await client.ImportRouteFileAsync(filePath, overwrite: true).ConfigureAwait(false);
                    Assert.IsTrue(importResponse.Value<bool>("ok"), "导入障碍路径失败: " + (string)importResponse["error"]);

                    // Shortest 策略
                    JObject shortest = await client.RunAutoPathAsync(
                        "Ground", RouteName,
                        ObjectLengthInMeters, ObjectWidthInMeters, SafetyMarginInMeters, GridSizeInMeters,
                        strategy: "Shortest").ConfigureAwait(false);
                    Assert.IsTrue(shortest.Value<bool>("ok"), "Shortest 策略规划失败: " + (string)shortest["error"]);

                    // Straightest 策略
                    JObject straightest = await client.RunAutoPathAsync(
                        "Ground", RouteName,
                        ObjectLengthInMeters, ObjectWidthInMeters, SafetyMarginInMeters, GridSizeInMeters,
                        strategy: "Straightest").ConfigureAwait(false);
                    Assert.IsTrue(straightest.Value<bool>("ok"), "Straightest 策略规划失败: " + (string)straightest["error"]);

                    // 策略参数回传正确
                    Assert.AreEqual("Shortest", (string)shortest["data"]["planningParameters"]["strategy"], "Shortest 策略参数未回传");
                    Assert.AreEqual("Straightest", (string)straightest["data"]["planningParameters"]["strategy"], "Straightest 策略参数未回传");

                    // 两种策略均规划出有效路径（不穿过障碍）
                    AssertValidPlannedPath(shortest, "Shortest");
                    AssertValidPlannedPath(straightest, "Straightest");
                }
                finally
                {
                    SafeDelete(tempDir);
                }
            }
        }

        private static void AssertValidPlannedPath(JObject response, string strategyName)
        {
            JObject data = (JObject)response["data"];
            JObject generatedRoute = (JObject)data["generatedRoute"];
            Assert.IsTrue((int)generatedRoute["pointCount"] >= 2, $"{strategyName} 路径至少应包含起点和终点");
            Assert.IsTrue((double)generatedRoute["length"] > 0, $"{strategyName} 路径长度必须大于 0");

            JObject segmentValidation = (JObject)data["segmentValidation"];
            Assert.AreEqual(0, (int)segmentValidation["blockedSampleCount"], $"{strategyName} 路径穿过不可通行网格");
            Assert.AreEqual(0, (int)segmentValidation["invalidSampleCount"], $"{strategyName} 路径存在网格外采样点");
        }

        private static string BuildObstacleRouteJson()
        {
            return string.Format(
                System.Globalization.CultureInfo.InvariantCulture,
                @"{{""PathPlanningData"":{{""version"":""1.0"",""generator"":""integration-test"",""timestamp"":""2026-08-04T21:30:00"",""ProjectInfo"":{{""name"":""test"",""description"":""test"",""units"":""meters"",""coordinateSystem"":""Global""}},""Routes"":[{{""id"":""obstacle-route-{0}"",""name"":""{1}"",""description"":"""",""pathType"":""Ground"",""totalLength"":40.0,""objectLimits"":{{""maxLength"":0,""maxWidth"":0,""maxHeight"":0,""safetyMargin"":0}},""gridSize"":1.0,""liftHeight"":0.0,""created"":""2026-08-04T21:30:00"",""points"":[{{""id"":""ob-p1"",""name"":""start"",""type"":""StartPoint"",""index"":0,""x"":{2},""y"":{3},""z"":{4},""created"":""2026-08-04T21:30:00""}},{{""id"":""ob-p2"",""name"":""end"",""type"":""EndPoint"",""index"":1,""x"":{5},""y"":{6},""z"":{7},""created"":""2026-08-04T21:30:00""}}]}}]}}}}",
                Guid.NewGuid().ToString("N"),
                RouteName,
                StartX, StartY, StartZ,
                EndX, EndY, EndZ);
        }

        private static void SafeDelete(string directory)
        {
            if (!Directory.Exists(directory))
            {
                return;
            }

            try
            {
                Directory.Delete(directory, true);
            }
            catch
            {
            }
        }
    }
}
