using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Core.Config;
using NavisworksTransport.Utils.CoordinateSystem;

namespace NavisworksTransport.Utils
{
    /// <summary>
    /// Navisworks 视角调整工具类
    /// 提供自动调整摄像机位置和视角的功能，用于碰撞报告截图
    /// </summary>
    public static class ViewpointHelper
    {
        public enum ViewpointStrategy
        {
            PathGroundSelection,
            PathHoistingSelection,
            PathRailSelection,
            ModelFocus,
            CollisionCloseUp
        }

        internal enum PathCameraHorizontalMode
        {
            Top,
            Side,
            Rear
        }

        internal struct PathViewpointProfile
        {
            public PathViewpointProfile(double cameraDistanceMeters, double elevationDegrees, PathCameraHorizontalMode horizontalMode)
            {
                CameraDistanceMeters = cameraDistanceMeters;
                ElevationDegrees = elevationDegrees;
                HorizontalMode = horizontalMode;
            }

            public double CameraDistanceMeters { get; }
            public double ElevationDegrees { get; }
            public PathCameraHorizontalMode HorizontalMode { get; }
        }

        internal struct FocusViewpointProfile
        {
            public FocusViewpointProfile(double viewAngleDegrees, double targetViewRatio)
            {
                ViewAngleDegrees = viewAngleDegrees;
                TargetViewRatio = targetViewRatio;
            }

            public double ViewAngleDegrees { get; }
            public double TargetViewRatio { get; }
        }

        /// <summary>
        /// 包围盒扩展系数（用于 ZoomBox 调整视野范围）
        /// </summary>
        private const double VIEW_BOUNDING_BOX_EXPANSION_FACTOR = 1.2;

        /// <summary>
        /// 默认视野扩展范围（米）- 用于调整视角时确保目标完全可见
        /// </summary>
        private const double DEFAULT_VIEW_EXPANSION_METERS = 10.0; 

        /// <summary>
        /// 智能调整视角：调整到路径中心，确保整个路径都在视野内
        /// </summary>
        /// <param name="path">路径对象</param>
        /// <param name="collisions">碰撞结果列表（用于日志记录，不影响视角调整）</param>
        public static void AdjustViewpointSmart(PathRoute path, List<CollisionResult> collisions)
        {
            // 调整视角到路径中心，确保整个路径都在视野内
            AdjustViewpointToPathCenter(path);
        }

        /// <summary>
        /// 按路径类型调整视角。
        /// Ground 使用俯视；
        /// Hoisting 使用后上方视角；
        /// Rail 使用侧面轻俯视角。
        /// </summary>
        public static void AdjustViewpointForPath(PathRoute path)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            switch (path.PathType)
            {
                case PathType.Hoisting:
                    AdjustDirectionalViewpointToPath(path, ResolvePathViewpointProfile(ViewpointStrategy.PathHoistingSelection));
                    return;
                case PathType.Rail:
                    AdjustDirectionalViewpointToPath(path, ResolvePathViewpointProfile(ViewpointStrategy.PathRailSelection));
                    return;
                case PathType.Ground:
                default:
                    AdjustViewpointToPathCenter(path);
                    return;
            }
        }

        /// <summary>
        /// 调整视角到路径中心，确保整个路径都在视野内
        /// </summary>
        /// <param name="path">路径对象</param>
        /// <exception cref="InvalidOperationException">没有活动的文档</exception>
        /// <exception cref="ArgumentException">路径为空或没有路径点</exception>
        /// <exception cref="InvalidOperationException">路径长度为0</exception>
        public static void AdjustViewpointToPathCenter(PathRoute path)
        {
            // 1. 计算路径起点和终点形成的包围盒（用于聚焦）
            Point3D startPoint = path.Points[0].Position;
            Point3D endPoint = path.Points[path.Points.Count - 1].Position;

            double minX = Math.Min(startPoint.X, endPoint.X);
            double minY = Math.Min(startPoint.Y, endPoint.Y);
            double minZ = Math.Min(startPoint.Z, endPoint.Z);
            double maxX = Math.Max(startPoint.X, endPoint.X);
            double maxY = Math.Max(startPoint.Y, endPoint.Y);
            double maxZ = Math.Max(startPoint.Z, endPoint.Z);
            BoundingBox3D startEndBoundingBox = new BoundingBox3D(
                new Point3D(minX, minY, minZ),
                new Point3D(maxX, maxY, maxZ)
            );

            // 2. 计算路径的包围盒（用于视野范围）
            BoundingBox3D pathBoundingBox = CalculatePathBoundingBox(path);

            // 3. 使用路径长度作为视野基准
            double baseDimension = path.TotalLength;

            // 4. 调整视角：聚焦起点终点中心，视野覆盖整个路径
            AdjustViewpointToBoundingBox(startEndBoundingBox, pathBoundingBox, baseDimension);
        }

        private static void AdjustDirectionalViewpointToPath(PathRoute path, PathViewpointProfile profile)
        {
            Document doc = Application.ActiveDocument;
            if (doc == null || doc.IsClear)
            {
                throw new InvalidOperationException("没有活动的文档");
            }

            if (path?.Points == null || path.Points.Count == 0)
            {
                throw new ArgumentException("路径为空或没有路径点", nameof(path));
            }

            Point3D startPoint = path.Points[0].Position;
            Point3D endPoint = path.Points[path.Points.Count - 1].Position;
            BoundingBox3D focusBoundingBox = ResolveDirectionalFocusBoundingBox(path);
            Point3D focusCenter = GetBoundingBoxCenter(focusBoundingBox);

            var adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
            Vector3 hostUp = ToVector3(adapter.HostUpVector);
            Vector3 rawPathDirection = new Vector3(
                (float)(endPoint.X - startPoint.X),
                (float)(endPoint.Y - startPoint.Y),
                (float)(endPoint.Z - startPoint.Z));
            Vector3 fallbackForward = ToVector3(ProjectVectorOntoPlane(doc.FrontRightTopViewVector, adapter.HostUpVector));
            Vector3 horizontalForward = ResolveHorizontalPathForward(rawPathDirection, hostUp, fallbackForward);
            Vector3 cameraOffsetDirection = ResolveCameraOffsetDirection(profile, hostUp, horizontalForward);
            double cameraDistance = UnitsConverter.ConvertFromMeters(profile.CameraDistanceMeters);
            Point3D cameraPosition = new Point3D(
                focusCenter.X + cameraOffsetDirection.X * (float)cameraDistance,
                focusCenter.Y + cameraOffsetDirection.Y * (float)cameraDistance,
                focusCenter.Z + cameraOffsetDirection.Z * (float)cameraDistance);

            ApplyViewpoint(
                cameraPosition,
                focusCenter,
                new Vector3D(hostUp.X, hostUp.Y, hostUp.Z),
                useAlignDirection: true);

            LogManager.Info(
                $"视角已调整完成: 类型={path.PathType}, 焦点=({focusCenter.X:F2},{focusCenter.Y:F2},{focusCenter.Z:F2}), " +
                $"相机=({cameraPosition.X:F2},{cameraPosition.Y:F2},{cameraPosition.Z:F2}), " +
                $"距离={UnitsConverter.ConvertToMeters(cameraDistance):F2}米, elevation={profile.ElevationDegrees:F1}°, 模式={profile.HorizontalMode}");
        }

        internal static BoundingBox3D ResolveDirectionalFocusBoundingBox(PathRoute path)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            if (path.Points == null || path.Points.Count == 0)
            {
                throw new ArgumentException("路径为空或没有路径点", nameof(path));
            }

            // 侧视路径应聚焦整条路径包络，而不是只看首尾点。
            // 对吊装路径尤其重要：首尾点常在地面，若只取首尾中心，高处主路径会被挤到画面上半部。
            return CalculatePathBoundingBox(path);
        }

        /// <summary>
        /// 调整视角到指定的包围盒（通用方法）
        /// 设置俯视位置，确保包围盒完整显示在视野中
        /// </summary>
        /// <param name="focusBoundingBox">聚焦包围盒（用于设置相机位置）</param>
        /// <param name="viewBoundingBox">视野包围盒（用于 ZoomBox 调整视野范围）</param>
        /// <param name="baseDimension">基准尺寸（米，用于计算相机距离）</param>
        /// <exception cref="InvalidOperationException">没有活动的文档</exception>
        private static void AdjustViewpointToBoundingBox(BoundingBox3D focusBoundingBox, BoundingBox3D viewBoundingBox, double baseDimension)
        {
            Document doc = Application.ActiveDocument;
            if (doc == null || doc.IsClear)
            {
                throw new InvalidOperationException("没有活动的文档");
            }

            var adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
            Vector3D hostUp = adapter.HostUpVector;
            Vector3D screenUp = adapter.FromCanonicalVector(new Vector3D(0, 1, 0));

            // 1. 计算聚焦包围盒中心（相机指向的位置）
            Point3D focusCenter = new Point3D(
                (focusBoundingBox.Min.X + focusBoundingBox.Max.X) / 2,
                (focusBoundingBox.Min.Y + focusBoundingBox.Max.Y) / 2,
                (focusBoundingBox.Min.Z + focusBoundingBox.Max.Z) / 2
            );

            // 2. 设置俯视位置（从上方往下看）
            // 将基准尺寸（米）转换为模型单位
            double baseDimensionInModelUnits = UnitsConverter.ConvertFromMeters(baseDimension);
            double cameraDistance = baseDimensionInModelUnits; // 相机距离设置为基准尺寸的1倍（可调整比例以获得更好视野）
            Point3D cameraPosition = new Point3D(
                focusCenter.X + hostUp.X * cameraDistance,
                focusCenter.Y + hostUp.Y * cameraDistance,
                focusCenter.Z + hostUp.Z * cameraDistance);

            // 将相机距离转换回米用于日志显示
            double cameraDistanceMeters = UnitsConverter.ConvertToMeters(cameraDistance);
            LogManager.Info($"相机设置: 位置=({cameraPosition.X:F2}, {cameraPosition.Y:F2}, {cameraPosition.Z:F2}), 焦点=({focusCenter.X:F2}, {focusCenter.Y:F2}, {focusCenter.Z:F2}), 相机距离={cameraDistanceMeters:F2}米");

            // 3. 计算扩展边距
            double boxWidth = viewBoundingBox.Max.X - viewBoundingBox.Min.X;
            double expansionFactor = VIEW_BOUNDING_BOX_EXPANSION_FACTOR + (DEFAULT_VIEW_EXPANSION_METERS / baseDimension);
            double expansionMargin = boxWidth * (expansionFactor - 1) / 2;

            // 4. 应用视角（使用通用方法，带 ZoomBox）
            ApplyViewpointWithZoomBox(cameraPosition, focusCenter, screenUp, viewBoundingBox, expansionMargin);

            LogManager.Info(
                $"视角已调整完成: 俯视图(已摆正), HostUp=({hostUp.X:F2},{hostUp.Y:F2},{hostUp.Z:F2}), " +
                $"ScreenUp=({screenUp.X:F2},{screenUp.Y:F2},{screenUp.Z:F2}), 基准尺寸={baseDimension:F2}米, " +
                $"相机距离={cameraDistanceMeters:F2}米, FOV=自动, 包围盒扩展系数={VIEW_BOUNDING_BOX_EXPANSION_FACTOR:F1}, 扩展边距={expansionMargin:F2}米");
        }

        /// <summary>
        /// 计算路径的包围盒
        /// </summary>
        /// <param name="path">路径对象</param>
        /// <returns>路径的包围盒</returns>
        /// <exception cref="ArgumentException">路径为空或没有路径点</exception>
        public static BoundingBox3D CalculatePathBoundingBox(PathRoute path)
        {
            if (path == null)
            {
                throw new ArgumentException("路径不能为空");
            }

            // 参考 BoundingBoxGeometryUtils.CalculateTotalBounds 的方式计算包围盒
            var firstPoint = path.Points[0].Position;
            double minX = firstPoint.X;
            double minY = firstPoint.Y;
            double minZ = firstPoint.Z;
            double maxX = firstPoint.X;
            double maxY = firstPoint.Y;
            double maxZ = firstPoint.Z;

            foreach (var point in path.Points.Skip(1))
            {
                var pos = point.Position;
                minX = Math.Min(minX, pos.X);
                minY = Math.Min(minY, pos.Y);
                minZ = Math.Min(minZ, pos.Z);
                maxX = Math.Max(maxX, pos.X);
                maxY = Math.Max(maxY, pos.Y);
                maxZ = Math.Max(maxZ, pos.Z);
            }

            var bounds = new BoundingBox3D(
                new Point3D(minX, minY, minZ),
                new Point3D(maxX, maxY, maxZ)
            );

            return bounds;
        }

        internal static PathViewpointProfile ResolvePathViewpointProfile(PathType pathType)
        {
            switch (pathType)
            {
                case PathType.Hoisting:
                    return ResolvePathViewpointProfile(ViewpointStrategy.PathHoistingSelection);
                case PathType.Rail:
                    return ResolvePathViewpointProfile(ViewpointStrategy.PathRailSelection);
                case PathType.Ground:
                default:
                    return ResolvePathViewpointProfile(ViewpointStrategy.PathGroundSelection);
            }
        }

        internal static PathViewpointProfile ResolvePathViewpointProfile(ViewpointStrategy strategy)
        {
            PathEditingConfig config = ConfigManager.Instance.Current?.PathEditing ?? new PathEditingConfig();
            switch (strategy)
            {
                case ViewpointStrategy.PathHoistingSelection:
                    return new PathViewpointProfile(
                        cameraDistanceMeters: config.HoistingViewDistanceMeters > 0 ? config.HoistingViewDistanceMeters : 6.0,
                        elevationDegrees: config.HoistingViewElevationDegrees > 0 ? config.HoistingViewElevationDegrees : 30.0,
                        horizontalMode: PathCameraHorizontalMode.Side);
                case ViewpointStrategy.PathRailSelection:
                    return new PathViewpointProfile(
                        cameraDistanceMeters: config.RailViewDistanceMeters > 0 ? config.RailViewDistanceMeters : 6.0,
                        elevationDegrees: config.RailViewElevationDegrees > 0 ? config.RailViewElevationDegrees : 30.0,
                        horizontalMode: PathCameraHorizontalMode.Side);
                case ViewpointStrategy.PathGroundSelection:
                default:
                    return new PathViewpointProfile(
                        cameraDistanceMeters: 12.0,
                        elevationDegrees: 90.0,
                        horizontalMode: PathCameraHorizontalMode.Top);
            }
        }

        internal static FocusViewpointProfile ResolveFocusViewpointProfile(ViewpointStrategy strategy)
        {
            switch (strategy)
            {
                case ViewpointStrategy.CollisionCloseUp:
                    return new FocusViewpointProfile(viewAngleDegrees: 60.0, targetViewRatio: 0.25);
                case ViewpointStrategy.ModelFocus:
                default:
                    return new FocusViewpointProfile(viewAngleDegrees: 60.0, targetViewRatio: 0.25);
            }
        }

        internal static Vector3 ResolveHorizontalPathForward(Vector3 rawPathDirection, Vector3 hostUp, Vector3 fallbackForward)
        {
            Vector3 projected = ProjectOntoPlane(rawPathDirection, hostUp);
            if (projected.LengthSquared() > 1e-8f)
            {
                return Vector3.Normalize(projected);
            }

            Vector3 fallbackProjected = ProjectOntoPlane(fallbackForward, hostUp);
            if (fallbackProjected.LengthSquared() > 1e-8f)
            {
                return Vector3.Normalize(fallbackProjected);
            }

            Vector3 canonicalFallback = Math.Abs(Vector3.Dot(Vector3.UnitX, hostUp)) > 0.9f
                ? Vector3.UnitY
                : Vector3.UnitX;
            return Vector3.Normalize(ProjectOntoPlane(canonicalFallback, hostUp));
        }

        internal static Vector3 ResolveCameraOffsetDirection(PathViewpointProfile profile, Vector3 hostUp, Vector3 horizontalForward)
        {
            float elevationRadians = (float)(profile.ElevationDegrees * Math.PI / 180.0);
            float horizontalWeight = (float)Math.Cos(elevationRadians);
            float verticalWeight = (float)Math.Sin(elevationRadians);

            Vector3 horizontalDirection;
            switch (profile.HorizontalMode)
            {
                case PathCameraHorizontalMode.Rear:
                    horizontalDirection = -horizontalForward;
                    break;
                case PathCameraHorizontalMode.Side:
                    horizontalDirection = Vector3.Cross(hostUp, horizontalForward);
                    if (horizontalDirection.LengthSquared() <= 1e-8f)
                    {
                        horizontalDirection = -horizontalForward;
                    }
                    break;
                default:
                    horizontalDirection = hostUp;
                    break;
            }

            Vector3 offset = horizontalDirection * horizontalWeight + hostUp * verticalWeight;
            return Vector3.Normalize(offset);
        }

        private static BoundingBox3D CreateBoundingBoxFromPoints(Point3D pointA, Point3D pointB)
        {
            return new BoundingBox3D(
                new Point3D(
                    Math.Min(pointA.X, pointB.X),
                    Math.Min(pointA.Y, pointB.Y),
                    Math.Min(pointA.Z, pointB.Z)),
                new Point3D(
                    Math.Max(pointA.X, pointB.X),
                    Math.Max(pointA.Y, pointB.Y),
                    Math.Max(pointA.Z, pointB.Z)));
        }

        private static Point3D GetBoundingBoxCenter(BoundingBox3D boundingBox)
        {
            return new Point3D(
                (boundingBox.Min.X + boundingBox.Max.X) / 2.0,
                (boundingBox.Min.Y + boundingBox.Max.Y) / 2.0,
                (boundingBox.Min.Z + boundingBox.Max.Z) / 2.0);
        }

        private static double GetMaxDimension(BoundingBox3D boundingBox)
        {
            return Math.Max(
                boundingBox.Max.X - boundingBox.Min.X,
                Math.Max(
                    boundingBox.Max.Y - boundingBox.Min.Y,
                    boundingBox.Max.Z - boundingBox.Min.Z));
        }

        private static Vector3D ProjectVectorOntoPlane(Vector3D vector, Vector3D planeNormal)
        {
            double dot = vector.X * planeNormal.X + vector.Y * planeNormal.Y + vector.Z * planeNormal.Z;
            return new Vector3D(
                vector.X - planeNormal.X * dot,
                vector.Y - planeNormal.Y * dot,
                vector.Z - planeNormal.Z * dot);
        }

        private static Vector3 ProjectOntoPlane(Vector3 vector, Vector3 planeNormal)
        {
            float dot = Vector3.Dot(vector, planeNormal);
            return vector - planeNormal * dot;
        }

        private static Vector3 ToVector3(Vector3D vector)
        {
            return new Vector3((float)vector.X, (float)vector.Y, (float)vector.Z);
        }

        /// <summary>
        /// 计算所有碰撞位置的总包围盒
        /// </summary>
        /// <param name="collisions">碰撞结果列表</param>
        /// <returns>所有碰撞位置的总包围盒</returns>
        /// <exception cref="ArgumentException">碰撞列表为空或没有有效的碰撞位置信息</exception>
        public static BoundingBox3D CalculateCollisionsBoundingBox(List<CollisionResult> collisions)
        {
            if (collisions == null || collisions.Count == 0)
            {
                throw new ArgumentException("碰撞列表为空");
            }

            // 获取所有碰撞的中心点
            var collisionCenters = collisions
                .Where(c => c.Center != null)
                .Select(c => c.Center)
                .ToList();

            if (collisionCenters.Count == 0)
            {
                throw new ArgumentException("没有有效的碰撞位置信息");
            }

            // 创建初始包围盒
            BoundingBox3D bounds = new BoundingBox3D(
                collisionCenters[0],
                collisionCenters[0]
            );

            // 扩展包围盒以包含所有碰撞位置
            foreach (var center in collisionCenters)
            {
                bounds.Extend(center);
            }

            return bounds;
        }

        /// <summary>
        /// 保存当前视角
        /// </summary>
        /// <returns>当前视角的副本</returns>
        /// <exception cref="InvalidOperationException">没有活动的文档</exception>
        public static Viewpoint SaveCurrentViewpoint()
        {
            try
            {
                Document doc = Application.ActiveDocument;
                if (doc == null || doc.IsClear)
                {
                    throw new InvalidOperationException("没有活动的文档");
                }

                Viewpoint currentViewpoint = doc.CurrentViewpoint.Value;
                return currentViewpoint.CreateCopy();
            }
            catch (Exception ex)
            {
                LogManager.Error($"保存当前视角失败: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 恢复视角
        /// </summary>
        /// <param name="savedViewpoint">要恢复的视角</param>
        /// <exception cref="InvalidOperationException">没有活动的文档</exception>
        /// <exception cref="ArgumentNullException">视角不能为空</exception>
        public static void RestoreViewpoint(Viewpoint savedViewpoint)
        {
            if (savedViewpoint == null)
            {
                throw new ArgumentNullException(nameof(savedViewpoint));
            }

            try
            {
                Document doc = Application.ActiveDocument;
                if (doc == null || doc.IsClear)
                {
                    throw new InvalidOperationException("没有活动的文档");
                }

                doc.CurrentViewpoint.CopyFrom(savedViewpoint);
                LogManager.Info("视角已恢复");
            }
            catch (Exception ex)
            {
                LogManager.Error($"恢复视角失败: {ex.Message}");
                throw;
            }
        }

        #region 通用视角设置方法

        /// <summary>
        /// 应用视角设置（核心通用方法）
        /// </summary>
        /// <param name="cameraPosition">相机位置</param>
        /// <param name="targetPoint">目标点（相机看向的位置）</param>
        /// <param name="upVector">相机上方向</param>
        /// <param name="useAlignDirection">是否使用 AlignDirection/AlignUp（true）还是直接设置 Rotation（false）</param>
        private static void ApplyViewpoint(Point3D cameraPosition, Point3D targetPoint, Vector3D upVector, bool useAlignDirection = true)
        {
            Document doc = Application.ActiveDocument;
            if (doc == null || doc.IsClear)
            {
                throw new InvalidOperationException("没有活动的文档");
            }

            Viewpoint newViewpoint = doc.CurrentViewpoint.Value.CreateCopy();
            newViewpoint.Position = cameraPosition;

            if (useAlignDirection)
            {
                // 方法1：使用 AlignDirection + AlignUp（推荐用于聚焦对象）
                Vector3D lookDirection = new Vector3D(
                    targetPoint.X - cameraPosition.X,
                    targetPoint.Y - cameraPosition.Y,
                    targetPoint.Z - cameraPosition.Z
                );
                lookDirection.Normalize();
                newViewpoint.AlignDirection(lookDirection);
                newViewpoint.AlignUp(upVector);
            }
            else
            {
                // 方法2：直接设置 Rotation 和 WorldUpVector（用于标准俯视图等）
                newViewpoint.Rotation = new Rotation3D();
                newViewpoint.WorldUpVector = new UnitVector3D(upVector.X, upVector.Y, upVector.Z);
            }

            doc.CurrentViewpoint.CopyFrom(newViewpoint);
        }

        /// <summary>
        /// 应用视角并缩放视野（使用 ZoomBox）
        /// </summary>
        /// <param name="cameraPosition">相机位置</param>
        /// <param name="targetPoint">目标点</param>
        /// <param name="upVector">相机上方向</param>
        /// <param name="viewBoundingBox">视野包围盒（用于 ZoomBox）</param>
        /// <param name="expansionMargin">包围盒扩展边距</param>
        private static void ApplyViewpointWithZoomBox(Point3D cameraPosition, Point3D targetPoint, Vector3D upVector, BoundingBox3D viewBoundingBox, double expansionMargin = 0)
        {
            Document doc = Application.ActiveDocument;
            if (doc == null || doc.IsClear)
            {
                throw new InvalidOperationException("没有活动的文档");
            }

            Viewpoint newViewpoint = doc.CurrentViewpoint.Value.CreateCopy();
            newViewpoint.Position = cameraPosition;

            // 使用 AlignDirection + AlignUp
            Vector3D lookDirection = new Vector3D(
                targetPoint.X - cameraPosition.X,
                targetPoint.Y - cameraPosition.Y,
                targetPoint.Z - cameraPosition.Z
            );
            lookDirection.Normalize();
            newViewpoint.AlignDirection(lookDirection);
            newViewpoint.AlignUp(upVector);

            // 使用 ZoomBox 调整视野
            BoundingBox3D expandedBox = expansionMargin > 0 
                ? BoundingBoxGeometryUtils.ExpandBoundingBox(viewBoundingBox, expansionMargin)
                : viewBoundingBox;
            newViewpoint.ZoomBox(expandedBox);

            doc.CurrentViewpoint.CopyFrom(newViewpoint);
        }

        #endregion

        #region 模型元素聚焦方法

        /// <summary>
        /// 聚焦到指定模型元素
        /// 相机会 positioned 在元素斜上方，使元素占据视图约1/4宽度
        /// </summary>
        /// <param name="modelItem">要聚焦的模型元素</param>
        /// <param name="viewAngleDegrees">视角角度（度，推荐45度斜上方）</param>
        /// <param name="targetViewRatio">目标占据视图比例（1/4 = 0.25）</param>
        public static void FocusOnModelItem(ModelItem modelItem, double viewAngleDegrees, double targetViewRatio)
        {
            if (modelItem == null)
            {
                throw new ArgumentNullException(nameof(modelItem));
            }

            Document doc = Application.ActiveDocument;
            if (doc == null || doc.IsClear)
            {
                throw new InvalidOperationException("没有活动的文档");
            }

            try
            {
                // 1. 获取模型元素的包围盒
                BoundingBox3D boundingBox = modelItem.BoundingBox();
                if (boundingBox == null || boundingBox.Size == new Vector3D(0, 0, 0))
                {
                    LogManager.Warning($"模型元素 {modelItem.DisplayName} 没有有效的包围盒，使用默认视角");
                    return;
                }

                // 2. 计算包围盒中心和尺寸
                Point3D center = new Point3D(
                    (boundingBox.Min.X + boundingBox.Max.X) / 2,
                    (boundingBox.Min.Y + boundingBox.Max.Y) / 2,
                    (boundingBox.Min.Z + boundingBox.Max.Z) / 2
                );

                double maxDimension = Math.Max(
                    boundingBox.Max.X - boundingBox.Min.X,
                    Math.Max(boundingBox.Max.Y - boundingBox.Min.Y, boundingBox.Max.Z - boundingBox.Min.Z)
                );

                LogManager.Debug($"聚焦到模型元素: {modelItem.DisplayName}, 最大边: {maxDimension:F2}");

                // 3. 计算相机位置（使用模型标准视角方向）
                Point3D cameraPosition = CalculateCameraPosition(center, maxDimension, viewAngleDegrees, targetViewRatio);

                // 4. 应用视角（使用通用方法）
                Vector3D upVector = doc.FrontRightTopViewUpVector;
                ApplyViewpoint(cameraPosition, center, upVector, useAlignDirection: true);

                LogManager.Debug($"视角已调整: 标准前右上视角, 目标占据视图{targetViewRatio:P0}");
            }
            catch (Exception ex)
            {
                LogManager.Error($"聚焦到模型元素失败: {ex.Message}", ex);
                throw;
            }
        }

        public static void FocusOnModelItem(ModelItem modelItem, ViewpointStrategy strategy)
        {
            FocusViewpointProfile profile = ResolveFocusViewpointProfile(strategy);
            FocusOnModelItem(modelItem, profile.ViewAngleDegrees, profile.TargetViewRatio);
        }

        public static void FocusOnModelItems(IEnumerable<ModelItem> modelItems, ViewpointStrategy strategy)
        {
            if (modelItems == null)
            {
                throw new ArgumentNullException(nameof(modelItems));
            }

            List<ModelItem> items = modelItems.Where(item => item != null).ToList();
            if (items.Count == 0)
            {
                throw new ArgumentException("至少需要一个模型元素", nameof(modelItems));
            }

            BoundingBox3D combinedBounds = items[0].BoundingBox();
            for (int i = 1; i < items.Count; i++)
            {
                BoundingBox3D itemBounds = items[i].BoundingBox();
                combinedBounds.Extend(itemBounds.Min);
                combinedBounds.Extend(itemBounds.Max);
            }

            Point3D center = new Point3D(
                (combinedBounds.Min.X + combinedBounds.Max.X) / 2.0,
                (combinedBounds.Min.Y + combinedBounds.Max.Y) / 2.0,
                (combinedBounds.Min.Z + combinedBounds.Max.Z) / 2.0);
            double targetSize = GetMaxDimension(combinedBounds);

            FocusOnPosition(center, targetSize, strategy);
        }

        /// <summary>
        /// 聚焦到多个模型元素（如碰撞中的两个对象）
        /// </summary>
        /// <param name="item1">第一个模型元素（运动物体）</param>
        /// <param name="item2">第二个模型元素（被撞对象）</param>
        /// <param name="viewAngleDegrees">视角角度（度，推荐45度斜上方）</param>
        /// <param name="targetViewRatio">目标占据视图比例（1/4 = 0.25）</param>
        public static void FocusOnCollision(ModelItem item1, ModelItem item2, double viewAngleDegrees, double targetViewRatio)
        {
            if (item1 == null && item2 == null)
            {
                throw new ArgumentException("至少需要一个模型元素");
            }

            try
            {
                // 计算两个元素的联合包围盒
                BoundingBox3D combinedBounds = null;
                
                if (item1 != null)
                {
                    combinedBounds = item1.BoundingBox();
                }
                
                if (item2 != null)
                {
                    if (combinedBounds == null)
                    {
                        combinedBounds = item2.BoundingBox();
                    }
                    else
                    {
                        BoundingBox3D item2Box = item2.BoundingBox();
                        combinedBounds.Extend(item2Box.Min);
                        combinedBounds.Extend(item2Box.Max);
                    }
                }

                if (combinedBounds == null || combinedBounds.Size == new Vector3D(0, 0, 0))
                {
                    LogManager.Warning("碰撞对象没有有效的包围盒");
                    return;
                }

                // 使用联合包围盒的中心点和尺寸
                Point3D center = new Point3D(
                    (combinedBounds.Min.X + combinedBounds.Max.X) / 2,
                    (combinedBounds.Min.Y + combinedBounds.Max.Y) / 2,
                    (combinedBounds.Min.Z + combinedBounds.Max.Z) / 2
                );

                double maxDimension = Math.Max(
                    combinedBounds.Max.X - combinedBounds.Min.X,
                    Math.Max(combinedBounds.Max.Y - combinedBounds.Min.Y, combinedBounds.Max.Z - combinedBounds.Min.Z)
                );

                FocusOnPosition(center, maxDimension, viewAngleDegrees, targetViewRatio);

                LogManager.Info($"已聚焦到碰撞位置: {item1?.DisplayName} ↔ {item2?.DisplayName}");
            }
            catch (Exception ex)
            {
                LogManager.Error($"聚焦到碰撞位置失败: {ex.Message}", ex);
                throw;
            }
        }

        public static void FocusOnCollision(ModelItem item1, ModelItem item2, ViewpointStrategy strategy)
        {
            FocusViewpointProfile profile = ResolveFocusViewpointProfile(strategy);
            FocusOnCollision(item1, item2, profile.ViewAngleDegrees, profile.TargetViewRatio);
        }

        /// <summary>
        /// 聚焦到指定位置和尺寸
        /// </summary>
        /// <param name="center">目标中心点</param>
        /// <param name="targetSize">目标尺寸（最大边）</param>
        /// <param name="viewAngleDegrees">视角角度</param>
        /// <param name="targetViewRatio">目标占据视图比例（1/4 = 0.25）</param>
        public static void FocusOnPosition(Point3D center, double targetSize, double viewAngleDegrees, double targetViewRatio)
        {
            Document doc = Application.ActiveDocument;
            if (doc == null || doc.IsClear)
            {
                throw new InvalidOperationException("没有活动的文档");
            }

            try
            {
                // 计算相机位置（使用模型标准视角方向）
                Point3D cameraPosition = CalculateCameraPosition(center, targetSize, viewAngleDegrees, targetViewRatio);

                // 应用视角（使用通用方法）
                Vector3D upVector = doc.FrontRightTopViewUpVector;
                ApplyViewpoint(cameraPosition, center, upVector, useAlignDirection: true);
            }
            catch (Exception ex)
            {
                LogManager.Error($"聚焦到位置失败: {ex.Message}", ex);
                throw;
            }
        }

        public static void FocusOnPosition(Point3D center, double targetSize, ViewpointStrategy strategy)
        {
            FocusViewpointProfile profile = ResolveFocusViewpointProfile(strategy);
            FocusOnPosition(center, targetSize, profile.ViewAngleDegrees, profile.TargetViewRatio);
        }

        /// <summary>
        /// 计算相机位置（使用模型标准前右上视角）
        /// 基于 Navisworks 的标准 FrontRightTopViewVector 确定相机方向
        /// </summary>
        private static Point3D CalculateCameraPosition(Point3D center, double targetSize, double viewAngleDegrees, double targetViewRatio)
        {
            // 计算相机距离（标准透视投影公式）
            // 公式：distance = (targetSize / 2) / tan(FOV / 2) / targetViewRatio
            double fovRadians = viewAngleDegrees * Math.PI / 180.0;
            double cameraDistance = (targetSize / 2.0) / Math.Tan(fovRadians / 2.0) / targetViewRatio;

            // 调试日志：打印计算参数
            LogManager.Debug($"[ViewpointHelper] FOV={viewAngleDegrees:F2}°, targetSize={targetSize:F2}, ratio={targetViewRatio:F2}, " +
                           $"distance={cameraDistance:F2}, center=({center.X:F2},{center.Y:F2},{center.Z:F2})");

            // 获取模型的标准前右上视角向量
            Vector3D viewDirection = Application.ActiveDocument.FrontRightTopViewVector;
            viewDirection.Normalize();
            
            // 沿标准视角方向偏移相机位置
            return new Point3D(
                center.X - viewDirection.X * cameraDistance,
                center.Y - viewDirection.Y * cameraDistance,
                center.Z - viewDirection.Z * cameraDistance
            );
        }

        #endregion
    }
}
