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>
    /// 路径导出→导入回环集成测试（覆盖计划 T12）。
    ///
    /// 验证路径导出（XML/JSON）与导入的完整回环：
    /// - 导出路径文件成功（文件存在、格式正确）
    /// - 重新导入后属性一致：名称、路径类型、点数、总长度（米）
    /// </summary>
    [TestClass]
    [TestCategory("NavisworksIntegration")]
    public class ExportImportRoundTripAutomationTests
    {
        private const string RouteName = "导出回环_测试";

        [TestMethod]
        [Timeout(240000)]
        public async Task ExportImportRoundTrip_Xml_PropertiesConsistent()
        {
            await RunRoundTripAsync("xml").ConfigureAwait(false);
        }

        [TestMethod]
        [Timeout(240000)]
        public async Task ExportImportRoundTrip_Json_PropertiesConsistent()
        {
            await RunRoundTripAsync("json").ConfigureAwait(false);
        }

        private static async Task RunRoundTripAsync(string format)
        {
            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. 准备一条临时路径（2 点 Ground，坐标取自测试基准区域）
                    string sourceFile = Path.Combine(tempDir, "source-route.json");
                    File.WriteAllText(sourceFile, BuildSourceRouteJson(), new UTF8Encoding(false));
                    JObject importSource = await client.ImportRouteFileAsync(sourceFile, overwrite: true).ConfigureAwait(false);
                    Assert.IsTrue(importSource.Value<bool>("ok"), "准备源路径失败: " + (string)importSource["error"]);
                    double metersToModelUnits = importSource["data"].Value<double>("metersToModelUnits");

                    // 2. 导出
                    string exportPath = Path.Combine(tempDir, "exported-route." + format);
                    JObject exportResponse = await client.ExportRouteFileAsync(RouteName, format, exportPath).ConfigureAwait(false);
                    Assert.IsTrue(exportResponse.Value<bool>("ok"), "导出失败: " + (string)exportResponse["error"]);
                    Assert.IsTrue(File.Exists(exportPath), "导出文件不存在: " + exportPath);
                    Assert.IsTrue(new FileInfo(exportPath).Length > 0, "导出文件为空");

                    int sourcePointCount = (int)exportResponse["data"]["pointCount"];
                    double sourceLengthMeters = (double)exportResponse["data"]["totalLengthInMeters"];

                    // 3. 重新导入（overwrite 同名路径）
                    JObject reimportResponse = await client.ImportRouteFileAsync(exportPath, overwrite: true).ConfigureAwait(false);
                    Assert.IsTrue(reimportResponse.Value<bool>("ok"), "重新导入失败: " + (string)reimportResponse["error"]);

                    JObject reimported = (JObject)((JArray)reimportResponse["data"]["routes"])[0];

                    // 4. 回环一致性断言
                    Assert.AreEqual(RouteName, (string)reimported["name"], "回环后路径名不一致");
                    Assert.AreEqual("Ground", (string)reimported["pathType"], "回环后路径类型不一致");
                    Assert.AreEqual(sourcePointCount, (int)reimported["pointCount"], "回环后点数不一致");
                    Assert.AreEqual(
                        sourceLengthMeters,
                        (double)reimported["totalLengthInMeters"],
                        1e-2,
                        "回环后总长度不一致（源 " + sourceLengthMeters.ToString("F3") + "m）");

                    // 长度应等于模型单位直线距离换算（验证单位链完整；YUp 水平面为 XZ）
                    double expectedStraightMeters = Math.Sqrt(
                        (EndX - StartX) * (EndX - StartX) +
                        (EndZ - StartZ) * (EndZ - StartZ)) / metersToModelUnits;
                    Assert.AreEqual(
                        expectedStraightMeters,
                        (double)reimported["totalLengthInMeters"],
                        1e-2,
                        "回环后长度与起终点直线距离不一致（单位换算）");
                }
                finally
                {
                    SafeDelete(tempDir);
                }
            }
        }

        // 源路径起终点（模型单位，测试基准区域附近）
        private const double StartX = -204.608;
        private const double StartY = 14.833;
        private const double StartZ = 19.250;
        private const double EndX = -208.608;
        private const double EndY = 14.833;
        private const double EndZ = 18.250;

        private static string BuildSourceRouteJson()
        {
            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"":""roundtrip-{0}"",""name"":""{1}"",""description"":"""",""pathType"":""Ground"",""totalLength"":10.0,""objectLimits"":{{""maxLength"":0,""maxWidth"":0,""maxHeight"":0,""safetyMargin"":0}},""gridSize"":1.0,""liftHeight"":0.0,""created"":""2026-08-04T21:30:00"",""points"":[{{""id"":""rt-p1"",""name"":""start"",""type"":""StartPoint"",""index"":0,""x"":{2},""y"":{3},""z"":{4},""created"":""2026-08-04T21:30:00""}},{{""id"":""rt-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
            {
            }
        }
    }
}
