using System;
using Autodesk.Navisworks.Api;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NavisworksTransport.Utils;

namespace NavisworksTransport.UnitTests.Utils
{
    /// <summary>
    /// BoundingBoxGeometryUtils 的单元测试
    /// 重点验证旋转后包围盒中心偏移计算的数学正确性
    /// 使用大尺寸和夸张比例，确保结果清晰可见
    /// </summary>
    [TestClass]
    public class BoundingBoxGeometryUtilsTests
    {
        #region CalculateRotatedBoundingBoxCenterOffset Tests - 大尺寸非对称包围盒

        /// <summary>
        /// X方向超长的长方体（类似长沙发/长桌）绕Z轴旋转90度
        /// 尺寸: 10000 x 100 x 50
        /// 预期: X方向大偏移
        /// </summary>
        [TestMethod]
        public void CalculateRotatedBoundingBoxCenterOffset_LongX_Rotate90AroundZ_LargeXOffset()
        {
            // X方向从 -5000 到 +5000（总长10000）
            // Y方向从 -50 到 +50（总长100）
            // Z方向从 -25 到 +25（总长50）
            var bounds = new BoundingBox3D(
                new Point3D(-5000, -50, -25),
                new Point3D(5000, 50, 25));

            // 原中心: (0, 0, 0)
            // 8角点: (±5000, ±50, ±25)
            
            // 绕Z轴旋转90度 (x'=-y, y'=x):
            // (5000, 50) -> (-50, 5000)
            // (5000, -50) -> (50, 5000)
            // (-5000, 50) -> (-50, -5000)
            // (-5000, -50) -> (50, -5000)
            // 
            // 新X范围: [-50, 50]（来自原Y范围）
            // 新Y范围: [-5000, 5000]（来自原X范围）
            // 新中心: (0, 0, 0)
            // 偏移: (0, 0, 0) - 等等，这不应该是0
            
            // 啊不对，让我重新算：
            // 原中心是 (0, 0, 0)
            // 旋转后各角点分布在 [-50,50]x[-5000,5000]x[-25,25]
            // 新AABB中心仍然是 (0, 0, 0)
            // 所以偏移应该是 0？
            
            // 等等，问题在于原中心是 (0,0,0)，所以新中心也是 (0,0,0)
            // 我需要测试非对称的，即原中心不在原点的情况
            
            // 重新设计：让包围盒中心不在原点
            // Min=(-1000, -50, -25), Max=(9000, 50, 25)
            // 中心: (4000, 0, 0)
            bounds = new BoundingBox3D(
                new Point3D(-1000, -50, -25),
                new Point3D(9000, 50, 25));

            var rotation = new Rotation3D(new UnitVector3D(0, 0, 1), Math.PI / 2);

            var offset = BoundingBoxGeometryUtils.CalculateRotatedBoundingBoxCenterOffset(bounds, rotation);

            // 原中心: (4000, 0, 0)
            // 8角点相对中心: (-5000,±50,±25), (5000,±50,±25)
            // 
            // 旋转90度后:
            // (-5000, 50) -> (-50, -5000)
            // (-5000, -50) -> (50, -5000)
            // (5000, 50) -> (-50, 5000)
            // (5000, -50) -> (50, 5000)
            //
            // 新X范围: [-50, 50]
            // 新Y范围: [-5000, 5000]
            // 新中心: (0, 0, 0)
            // 偏移: (0-4000, 0-0, 0-0) = (-4000, 0, 0)

            Console.WriteLine($"LongX-Rotate90: offset=({offset.X:F1}, {offset.Y:F1}, {offset.Z:F1})");
            
            Assert.AreEqual(-4000, offset.X, 1, "X方向大偏移应为-4000");
            Assert.AreEqual(0, offset.Y, 1, "Y偏移应为0");
            Assert.AreEqual(0, offset.Z, 0.1, "Z偏移应为0");
        }

        /// <summary>
        /// Y方向超长的长方体绕X轴旋转90度
        /// 尺寸: 100 x 10000 x 50
        /// </summary>
        [TestMethod]
        public void CalculateRotatedBoundingBoxCenterOffset_LongY_Rotate90AroundX_LargeYOffset()
        {
            // Y方向从 -1000 到 +9000（总长10000，中心在4000）
            // X方向从 -50 到 +50（总长100）
            // Z方向从 -25 到 +25（总长50）
            var bounds = new BoundingBox3D(
                new Point3D(-50, -1000, -25),
                new Point3D(50, 9000, 25));

            // 绕X轴旋转90度 (y'=-z, z'=y)
            var rotation = new Rotation3D(new UnitVector3D(1, 0, 0), Math.PI / 2);

            var offset = BoundingBoxGeometryUtils.CalculateRotatedBoundingBoxCenterOffset(bounds, rotation);

            // 原中心: (0, 4000, 0)
            // 8角点相对中心: (±50, -5000, ±25), (±50, 5000, ±25)
            // 
            // 旋转90度后:
            // y' = -z, z' = y
            // (50, -5000, 25) -> (50, -25, -5000)
            // (50, -5000, -25) -> (50, 25, -5000)
            // (50, 5000, 25) -> (50, -25, 5000)
            // (50, 5000, -25) -> (50, 25, 5000)
            // (-50, -5000, 25) -> (-50, -25, -5000)
            // (-50, -5000, -25) -> (-50, 25, -5000)
            // (-50, 5000, 25) -> (-50, -25, 5000)
            // (-50, 5000, -25) -> (-50, 25, 5000)
            //
            // 新X范围: [-50, 50]
            // 新Y范围: [-25, 25]
            // 新Z范围: [-5000, 5000]
            // 新中心: (0, 0, 0)
            // 偏移: (0-0, 0-4000, 0-0) = (0, -4000, 0)

            Console.WriteLine($"LongY-Rotate90: offset=({offset.X:F1}, {offset.Y:F1}, {offset.Z:F1})");
            
            Assert.AreEqual(0, offset.X, 1, "X偏移应为0");
            Assert.AreEqual(-4000, offset.Y, 1, "Y方向大偏移应为-4000");
            Assert.AreEqual(0, offset.Z, 0.1, "Z偏移应为0");
        }

        /// <summary>
        /// Z方向超长的长方体绕Y轴旋转90度
        /// 尺寸: 100 x 100 x 10000
        /// </summary>
        [TestMethod]
        public void CalculateRotatedBoundingBoxCenterOffset_LongZ_Rotate90AroundY_LargeZOffset()
        {
            // Z方向从 -1000 到 +9000（总长10000，中心在4000）
            // X方向从 -50 到 +50（总长100）
            // Y方向从 -50 到 +50（总长100）
            var bounds = new BoundingBox3D(
                new Point3D(-50, -50, -1000),
                new Point3D(50, 50, 9000));

            // 绕Y轴旋转90度 (z'=x, x'=-z) - 等等，让我确认旋转矩阵
            // 绕Y轴旋转θ: x'=x*cosθ+z*sinθ, z'=-x*sinθ+z*cosθ
            // 90度时: x'=z, z'=-x
            var rotation = new Rotation3D(new UnitVector3D(0, 1, 0), Math.PI / 2);

            var offset = BoundingBoxGeometryUtils.CalculateRotatedBoundingBoxCenterOffset(bounds, rotation);

            // 原中心: (0, 0, 4000)
            // 8角点相对中心: (±50,±50,-5000), (±50,±50,5000)
            // 
            // 旋转90度后 (x'=z, z'=-x):
            // (50, 50, -5000) -> (-5000, 50, -50)
            // (50, 50, 5000) -> (5000, 50, -50)
            // (-50, 50, -5000) -> (-5000, 50, 50)
            // (-50, 50, 5000) -> (5000, 50, 50)
            // 以及Y=-50的四个点...
            //
            // 新X范围: [-5000, 5000]
            // 新Y范围: [-50, 50]
            // 新Z范围: [-50, 50]
            // 新中心: (0, 0, 0)
            // 偏移: (0-0, 0-0, 0-4000) = (0, 0, -4000)

            Console.WriteLine($"LongZ-Rotate90: offset=({offset.X:F1}, {offset.Y:F1}, {offset.Z:F1})");
            
            Assert.AreEqual(0, offset.X, 1, "X偏移应为0");
            Assert.AreEqual(0, offset.Y, 0.1, "Y偏移应为0");
            Assert.AreEqual(-4000, offset.Z, 1, "Z方向大偏移应为-4000");
        }

        /// <summary>
        /// 三轴都不同比例的长方体绕Z轴旋转45度
        /// 尺寸: 1000 x 200 x 100
        /// </summary>
        [TestMethod]
        public void CalculateRotatedBoundingBoxCenterOffset_AsymmetricXYZ_Rotate45AroundZ_MultipleOffsets()
        {
            // X: -500 ~ +500 (中心0，但非对称也可测)
            // Y: -100 ~ +100 (中心0)
            // Z: -50 ~ +50 (中心0)
            // 等等，中心0的话偏移还是0...
            
            // 改用非中心对称的
            // X: -100 ~ +900 (总长1000，中心400)
            // Y: -80 ~ +120 (总长200，中心20)
            // Z: -30 ~ +70 (总长100，中心20)
            var bounds = new BoundingBox3D(
                new Point3D(-100, -80, -30),
                new Point3D(900, 120, 70));

            // 绕Z轴旋转45度
            var rotation = new Rotation3D(new UnitVector3D(0, 0, 1), Math.PI / 4);

            var offset = BoundingBoxGeometryUtils.CalculateRotatedBoundingBoxCenterOffset(bounds, rotation);

            // 原中心: (400, 20, 20)
            // 
            // 8角点相对中心:
            // (-500,-100,-50), (500,-100,-50), (-500,100,-50), (500,100,-50)
            // (-500,-100,50), (500,-100,50), (-500,100,50), (500,100,50)
            //
            // 旋转45度后 (x'=(x-y)/√2, y'=(x+y)/√2):
            // (-500,-100) -> (-400/√2, -600/√2) ≈ (-283, -424)
            // (500,-100) -> (600/√2, 400/√2) ≈ (424, 283)
            // (-500,100) -> (-600/√2, -400/√2) ≈ (-424, -283)
            // (500,100) -> (400/√2, 600/√2) ≈ (283, 424)
            //
            // 新X范围: [-424, 424]
            // 新Y范围: [-424, 424]
            // 新中心: (0, 0, 20) - Z不变
            // 偏移: (0-400, 0-20, 20-20) = (-400, -20, 0)

            Console.WriteLine($"Asymmetric-Rotate45: offset=({offset.X:F1}, {offset.Y:F1}, {offset.Z:F1})");
            
            // 允许一定误差（因为手动计算是近似值）
            Assert.IsTrue(Math.Abs(offset.X - (-400)) < 50, $"X偏移应约-400，实际是{offset.X:F1}");
            Assert.IsTrue(Math.Abs(offset.Y - (-20)) < 50, $"Y偏移应约-20，实际是{offset.Y:F1}");
            Assert.AreEqual(0, offset.Z, 0.1, "Z偏移应为0");
        }

        /// <summary>
        /// 实际沙发案例放大版
        /// 模拟沙发: 长2000，宽100，高80，中心偏移
        /// </summary>
        [TestMethod]
        public void CalculateRotatedBoundingBoxCenterOffset_BigSofa_Rotate90AroundZ_RealisticCase()
        {
            // 沙发包围盒放大版
            // X: -200 ~ +1800 (总长2000，中心800)
            // Y: -50 ~ +50 (总长100，中心0)
            // Z: 0 ~ +80 (总高80，中心40)
            var bounds = new BoundingBox3D(
                new Point3D(-200, -50, 0),
                new Point3D(1800, 50, 80));

            var rotation = new Rotation3D(new UnitVector3D(0, 0, 1), Math.PI / 2);

            var offset = BoundingBoxGeometryUtils.CalculateRotatedBoundingBoxCenterOffset(bounds, rotation);

            // 原中心: (800, 0, 40)
            // 
            // 8角点相对中心:
            // (-1000,-50,-40), (1000,-50,-40), (-1000,50,-40), (1000,50,-40)
            // (-1000,-50,40), (1000,-50,40), (-1000,50,40), (1000,50,40)
            //
            // 旋转90度后 (x'=-y, y'=x):
            // (-1000,-50) -> (50, -1000)
            // (1000,-50) -> (50, 1000)
            // (-1000,50) -> (-50, -1000)
            // (1000,50) -> (-50, 1000)
            //
            // 新X范围: [-50, 50]
            // 新Y范围: [-1000, 1000]
            // 新中心: (0, 0, 40) - Z不变
            // 偏移: (0-800, 0-0, 40-40) = (-800, 0, 0)

            Console.WriteLine($"BigSofa-Rotate90: offset=({offset.X:F1}, {offset.Y:F1}, {offset.Z:F1})");
            
            Assert.AreEqual(-800, offset.X, 10, "X方向偏移应为-800");
            Assert.AreEqual(0, offset.Y, 10, "Y偏移应为0");
            Assert.AreEqual(0, offset.Z, 0.1, "Z偏移应为0");
        }

        /// <summary>
        /// X方向超长绕Z轴旋转45度 - 测试非90度旋转
        /// 尺寸: 10000 x 100 x 50
        /// </summary>
        [TestMethod]
        public void CalculateRotatedBoundingBoxCenterOffset_LongX_Rotate45AroundZ_DiagonalOffset()
        {
            // X方向从 -1000 到 +9000（总长10000，中心4000）
            // Y方向从 -50 到 +50（总长100）
            var bounds = new BoundingBox3D(
                new Point3D(-1000, -50, -25),
                new Point3D(9000, 50, 25));

            // 绕Z轴旋转45度
            var rotation = new Rotation3D(new UnitVector3D(0, 0, 1), Math.PI / 4);

            var offset = BoundingBoxGeometryUtils.CalculateRotatedBoundingBoxCenterOffset(bounds, rotation);

            // 原中心: (4000, 0, 0)
            // 8角点相对中心: (-5000,±50,±25), (5000,±50,±25)
            // 
            // 旋转45度后 (x'=(x-y)/√2, y'=(x+y)/√2):
            // (-5000, 50) -> (-5050/√2, -4950/√2) ≈ (-3571, -3500)
            // (-5000, -50) -> (-4950/√2, -5050/√2) ≈ (-3500, -3571)
            // (5000, 50) -> (4950/√2, 5050/√2) ≈ (3500, 3571)
            // (5000, -50) -> (5050/√2, 4950/√2) ≈ (3571, 3500)
            //
            // 新X范围: [-3571, 3571]
            // 新Y范围: [-3571, 3571]
            // 新中心: (0, 0, 0)
            // 偏移: (0-4000, 0-0, 0-0) = (-4000, 0, 0)

            Console.WriteLine($"LongX-Rotate45: offset=({offset.X:F1}, {offset.Y:F1}, {offset.Z:F1})");
            
            // X方向应该有较大负偏移（接近-4000）
            Assert.IsTrue(offset.X < -3500, $"45度旋转后X偏移应小于-3500，实际是{offset.X:F1}");
            Assert.IsTrue(offset.X > -4500, $"45度旋转后X偏移应大于-4500，实际是{offset.X:F1}");
            // Y方向偏移应该很小（因为原Y中心是0）
            Assert.IsTrue(Math.Abs(offset.Y) < 100, $"45度旋转后Y偏移应接近0，实际是{offset.Y:F1}");
            Assert.AreEqual(0, offset.Z, 0.1, "Z偏移应为0");
        }

        /// <summary>
        /// XY方向都非对称的长方体绕Z轴旋转45度 - 测试双向偏移
        /// 尺寸: 8000 x 4000 x 100
        /// </summary>
        [TestMethod]
        public void CalculateRotatedBoundingBoxCenterOffset_XYBothAsymmetric_Rotate45AroundZ_BothOffsets()
        {
            // X方向从 -3000 到 +5000（总长8000，中心2000）
            // Y方向从 -1000 到 +3000（总长4000，中心1000）
            var bounds = new BoundingBox3D(
                new Point3D(-3000, -1000, -50),
                new Point3D(5000, 3000, 50));

            // 绕Z轴旋转45度
            var rotation = new Rotation3D(new UnitVector3D(0, 0, 1), Math.PI / 4);

            var offset = BoundingBoxGeometryUtils.CalculateRotatedBoundingBoxCenterOffset(bounds, rotation);

            // 原中心: (2000, 1000, 0)
            // 8角点相对中心: (-5000,-2000,±50), (3000,-2000,±50), (-5000,2000,±50), (3000,2000,±50)
            // 
            // 旋转45度后:
            // (-5000, -2000) -> (-3000/√2, -7000/√2) ≈ (-2121, -4950)
            // (3000, -2000) -> (5000/√2, 1000/√2) ≈ (3536, 707)
            // (-5000, 2000) -> (-7000/√2, -3000/√2) ≈ (-4950, -2121)
            // (3000, 2000) -> (1000/√2, 5000/√2) ≈ (707, 3536)
            //
            // 新X范围: [-4950, 3536]
            // 新Y范围: [-4950, 3536]
            // 新中心: ((-4950+3536)/2, (-4950+3536)/2, 0) = (-707, -707, 0)
            // 偏移: (-707-2000, -707-1000, 0-0) = (-2707, -1707, 0)

            Console.WriteLine($"XY-Asymmetric-Rotate45: offset=({offset.X:F1}, {offset.Y:F1}, {offset.Z:F1})");
            
            // X方向应该有较大负偏移
            Assert.IsTrue(offset.X < -2000, $"45度旋转后X偏移应小于-2000，实际是{offset.X:F1}");
            Assert.IsTrue(offset.X > -3500, $"45度旋转后X偏移应大于-3500，实际是{offset.X:F1}");
            // Y方向也应该有负偏移，但比X小
            Assert.IsTrue(offset.Y < -1000, $"45度旋转后Y偏移应小于-1000，实际是{offset.Y:F1}");
            Assert.IsTrue(offset.Y > -2500, $"45度旋转后Y偏移应大于-2500，实际是{offset.Y:F1}");
            Assert.AreEqual(0, offset.Z, 0.1, "Z偏移应为0");
        }

        /// <summary>
        /// 零旋转验证 - 无论什么形状，不旋转偏移都应为0
        /// </summary>
        [TestMethod]
        public void CalculateRotatedBoundingBoxCenterOffset_NoRotation_ZeroOffset()
        {
            var bounds = new BoundingBox3D(
                new Point3D(-1000, -100, -50),
                new Point3D(9000, 100, 50));

            var rotation = Rotation3D.Identity;

            var offset = BoundingBoxGeometryUtils.CalculateRotatedBoundingBoxCenterOffset(bounds, rotation);

            Console.WriteLine($"No-Rotation: offset=({offset.X:F1}, {offset.Y:F1}, {offset.Z:F1})");
            
            Assert.AreEqual(0, offset.X, 1e-6, "无旋转时X偏移应为0");
            Assert.AreEqual(0, offset.Y, 1e-6, "无旋转时Y偏移应为0");
            Assert.AreEqual(0, offset.Z, 1e-6, "无旋转时Z偏移应为0");
        }

        /// <summary>
        /// 180度旋转验证 - 包围盒应该不变（只是翻转）
        /// </summary>
        [TestMethod]
        public void CalculateRotatedBoundingBoxCenterOffset_180DegreeRotation_ZeroOffset()
        {
            var bounds = new BoundingBox3D(
                new Point3D(-1000, -100, -50),
                new Point3D(9000, 100, 50));

            var rotation = new Rotation3D(new UnitVector3D(0, 0, 1), Math.PI);

            var offset = BoundingBoxGeometryUtils.CalculateRotatedBoundingBoxCenterOffset(bounds, rotation);

            Console.WriteLine($"180-Rotation: offset=({offset.X:F1}, {offset.Y:F1}, {offset.Z:F1})");
            
            Assert.AreEqual(0, offset.X, 1e-6, "180度旋转后X偏移应为0");
            Assert.AreEqual(0, offset.Y, 1e-6, "180度旋转后Y偏移应为0");
            Assert.AreEqual(0, offset.Z, 1e-6, "180度旋转后Z偏移应为0");
        }

        #endregion
    }
}
