using System;
using Autodesk.Navisworks.Api;

namespace NavisworksTransport.Utils.CoordinateSystem
{
    /// <summary>
    /// 坐标系管理器 - 全局访问点和自动检测
    /// 简化版：基于 Document.UpVector 自动检测
    /// </summary>
    public class CoordinateSystemManager
    {
        #region 单例模式

        private static readonly Lazy<CoordinateSystemManager> _instance = 
            new Lazy<CoordinateSystemManager>(() => new CoordinateSystemManager());
        
        public static CoordinateSystemManager Instance => _instance.Value;

        #endregion

        #region 私有字段

        private ICoordinateSystem _current;
        private CoordinateSystemType _configuredType = CoordinateSystemType.AutoDetect;

        #endregion

        #region 公共属性

        /// <summary>
        /// 当前活动的坐标系
        /// </summary>
        public ICoordinateSystem Current => _current ?? (_current = new ZUpCoordinateSystem());

        /// <summary>
        /// 当前配置的坐标系类型
        /// </summary>
        public CoordinateSystemType ConfiguredType => _configuredType;

        /// <summary>
        /// 解析后的宿主坐标系类型。
        /// AutoDetect 模式下返回当前实际检测结果。
        /// </summary>
        public CoordinateSystemType ResolvedType => GetResolvedType();

        #endregion

        #region 构造函数

        private CoordinateSystemManager()
        {
            // 默认使用 Z-Up
            _current = new ZUpCoordinateSystem();
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 初始化坐标系
        /// 根据配置自动检测或强制指定；支持环境变量 TRANSPORTPLUGIN_TEST_COORD_SYSTEM 强制
        /// （F1 副实例：极小导出模型 AutoDetect 不稳定，注入主 NW 坐标系）
        /// </summary>
        /// <param name="configType">配置的类型</param>
        public void Initialize(CoordinateSystemType configType)
        {
            _configuredType = configType;

            // F1 副实例：环境变量强制坐标系优先（主 NW 注入，避免极小导出模型 AutoDetect 误判）
            if (TryApplyForcedCoordinateSystemFromEnvironment())
            {
                return;
            }

            switch (configType)
            {
                case CoordinateSystemType.AutoDetect:
                    _current = AutoDetectFromDocument();
                    break;
                case CoordinateSystemType.ZUp:
                    _current = new ZUpCoordinateSystem();
                    LogManager.Info("[坐标系] 强制使用 Z-Up 坐标系");
                    break;
                case CoordinateSystemType.YUp:
                    _current = new YUpCoordinateSystem();
                    LogManager.Info("[坐标系] 强制使用 Y-Up 坐标系");
                    break;
                default:
                    _current = new ZUpCoordinateSystem();
                    LogManager.Warning($"[坐标系] 未知配置类型 {configType}，使用默认 Z-Up");
                    break;
            }
        }

        /// <summary>
        /// 重新检测坐标系（用于文档切换后）
        /// </summary>
        public void ReDetect()
        {
            // F1 副实例：环境变量强制坐标系优先
            if (TryApplyForcedCoordinateSystemFromEnvironment())
            {
                return;
            }

            if (_configuredType == CoordinateSystemType.AutoDetect)
            {
                _current = AutoDetectFromDocument();
            }
        }

        /// <summary>
        /// 应用环境变量强制的坐标系（TRANSPORTPLUGIN_TEST_COORD_SYSTEM="YUp"/"ZUp"）。
        /// 返回是否已应用。
        /// </summary>
        private bool TryApplyForcedCoordinateSystemFromEnvironment()
        {
            string forced = Environment.GetEnvironmentVariable("TRANSPORTPLUGIN_TEST_COORD_SYSTEM");
            if (string.IsNullOrWhiteSpace(forced))
            {
                return false;
            }

            if (string.Equals(forced, "YUp", StringComparison.OrdinalIgnoreCase))
            {
                _current = new YUpCoordinateSystem();
                LogManager.Info("[坐标系] 环境变量强制使用 Y-Up 坐标系");
                return true;
            }

            if (string.Equals(forced, "ZUp", StringComparison.OrdinalIgnoreCase))
            {
                _current = new ZUpCoordinateSystem();
                LogManager.Info("[坐标系] 环境变量强制使用 Z-Up 坐标系");
                return true;
            }

            LogManager.Warning($"[坐标系] 无法识别的强制坐标系值: {forced}（仅支持 YUp/ZUp）");
            return false;
        }

        /// <summary>
        /// 手动设置坐标系（用于系统管理界面）
        /// </summary>
        /// <param name="type">坐标系类型</param>
        public void SetCoordinateSystem(CoordinateSystemType type)
        {
            _configuredType = type;

            switch (type)
            {
                case CoordinateSystemType.AutoDetect:
                    _current = AutoDetectFromDocument();
                    break;
                case CoordinateSystemType.ZUp:
                    _current = new ZUpCoordinateSystem();
                    LogManager.Info("[坐标系] 手动切换为 Z-Up 坐标系");
                    break;
                case CoordinateSystemType.YUp:
                    _current = new YUpCoordinateSystem();
                    LogManager.Info("[坐标系] 手动切换为 Y-Up 坐标系");
                    break;
            }
        }

        /// <summary>
        /// 获取当前坐标系的描述信息
        /// </summary>
        public string GetCurrentInfo()
        {
            return $"类型: {_current.Type}, 向上向量: ({_current.UpVector.X:F2}, {_current.UpVector.Y:F2}, {_current.UpVector.Z:F2})";
        }

        /// <summary>
        /// 获取当前宿主坐标到 Canonical Space 的统一适配器。
        /// </summary>
        public HostCoordinateAdapter CreateHostAdapter()
        {
            return new HostCoordinateAdapter(GetResolvedType());
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 基于 Document.UpVector 自动检测坐标系
        /// </summary>
        private ICoordinateSystem AutoDetectFromDocument()
        {
            try
            {
                var doc = Application.ActiveDocument;
                if (doc == null)
                {
                    LogManager.Debug("[坐标系检测] 无活动文档，使用默认 Z-Up");
                    return new ZUpCoordinateSystem();
                }

                // 检查文档是否已完全加载（通过检查文件名）
                if (string.IsNullOrEmpty(doc.FileName))
                {
                    LogManager.Debug("[坐标系检测] 文档尚未完全加载，使用默认 Z-Up");
                    return new ZUpCoordinateSystem();
                }

                // 安全获取 UpVector
                Vector3D upVector;
                try
                {
                    upVector = doc.UpVector;
                }
                catch
                {
                    LogManager.Debug("[坐标系检测] 无法获取 Document.UpVector，使用默认 Z-Up");
                    return new ZUpCoordinateSystem();
                }

                // 如果 UpVector 未定义（Zero），使用默认 Z-Up
                if (upVector.IsZero)
                {
                    LogManager.Warning("[坐标系检测] Document.UpVector 未定义，使用默认 Z-Up");
                    LogManager.Warning("[坐标系检测] 如需使用 Y-Up，请在系统管理中手动设置");
                    return new ZUpCoordinateSystem();
                }

                // 检测 Y-Up: UpVector 主要在 Y 方向
                if (Math.Abs(upVector.Y) > 0.9)
                {
                    LogManager.Info($"[坐标系检测] Document.UpVector=({upVector.X:F2}, {upVector.Y:F2}, {upVector.Z:F2}) 表明 Y-Up 坐标系");
                    return new YUpCoordinateSystem();
                }

                // 检测 Z-Up: UpVector 主要在 Z 方向
                if (Math.Abs(upVector.Z) > 0.9)
                {
                    LogManager.Info($"[坐标系检测] Document.UpVector=({upVector.X:F2}, {upVector.Y:F2}, {upVector.Z:F2}) 表明 Z-Up 坐标系");
                    return new ZUpCoordinateSystem();
                }

                // 未知情况
                LogManager.Warning($"[坐标系检测] Document.UpVector=({upVector.X:F2}, {upVector.Y:F2}, {upVector.Z:F2}) 非标准向量，使用默认 Z-Up");
                return new ZUpCoordinateSystem();
            }
            catch (Exception ex)
            {
                LogManager.Error($"[坐标系检测] 自动检测失败: {ex.Message}");
                return new ZUpCoordinateSystem();
            }
        }

        /// <summary>
        /// 获取当前解析后的宿主坐标系类型。
        /// </summary>
        public CoordinateSystemType GetResolvedType()
        {
            if (_current == null)
            {
                return CoordinateSystemType.ZUp;
            }

            switch (_current.Type)
            {
                case CoordinateSystemType.YUp:
                    return CoordinateSystemType.YUp;
                case CoordinateSystemType.ZUp:
                    return CoordinateSystemType.ZUp;
                default:
                    return CoordinateSystemType.ZUp;
            }
        }

        #endregion
    }
}
