using System;
using System.Collections.Generic;
using Autodesk.Navisworks.Api;

namespace NavisworksTransport.Utils
{
    /// <summary>
    /// 模型树遍历访问结果（回调决定本节点的深入/剪枝/命中行为）。
    /// </summary>
    public enum ModelItemWalkAction
    {
        /// <summary>剪掉整棵子树（不再访问任何后代）</summary>
        Prune,

        /// <summary>继续访问后代节点</summary>
        Continue,

        /// <summary>命中：停止深入本节点子树，并触发父级后序传播（postHitVisit）</summary>
        Hit
    }

    /// <summary>
    /// 模型树深度遍历通用工具。
    ///
    /// 内置语义：
    /// - IsHidden 剪枝：节点隐藏 → 整棵子树跳过（Navisworks 层级可见性规则：
    ///   父隐藏则所有子节点都不可见，无需深入）
    /// - 回调返回 Hit 时触发父级后序传播（postHitVisit）——用于收集
    ///   "命中对象的所有祖先"（共享祖先只被上传一次，避免 K×D 次枚举）
    ///
    /// 用途：剖面盒导出（SectionBoxExporter）、可见几何体收集
    /// （ModelItemAnalysisHelper）等模型树遍历统一复用。
    /// </summary>
    public static class ModelItemTreeWalker
    {
        /// <summary>
        /// 深度遍历模型树。
        /// </summary>
        /// <param name="item">当前节点（通常从 model.RootItem 开始）</param>
        /// <param name="visit">访问回调（决定 Prune/Continue/Hit）</param>
        /// <param name="postHitVisit">后序传播：子树有 Hit 时对祖先调用（用于收集祖先集合）</param>
        /// <param name="onHidden">隐藏节点通知（仅统计用，隐藏节点不会触发 visit）</param>
        /// <returns>本子树是否存在 Hit</returns>
        public static bool WalkVisible(
            ModelItem item,
            Func<ModelItem, ModelItemWalkAction> visit,
            Action<ModelItem> postHitVisit = null,
            Action<ModelItem> onHidden = null)
        {
            if (item == null)
            {
                return false;
            }

            // 关键剪枝：节点隐藏 → 整棵子树跳过（其所有子节点都不可见）
            if (item.IsHidden)
            {
                onHidden?.Invoke(item);
                return false;
            }

            ModelItemWalkAction action = visit(item);
            if (action == ModelItemWalkAction.Prune)
            {
                return false;
            }

            if (action == ModelItemWalkAction.Hit)
            {
                return true;
            }

            // Continue：深入子节点；任一子节点命中 → 本节点触发后序传播
            bool anyChildHit = false;
            foreach (var child in item.Children)
            {
                if (WalkVisible(child, visit, postHitVisit, onHidden))
                {
                    anyChildHit = true;
                }
            }

            if (anyChildHit)
            {
                postHitVisit?.Invoke(item);
            }

            return anyChildHit;
        }

        /// <summary>
        /// 遍历多个模型的根（Application.ActiveDocument.Models 场景）。
        /// 返回任意模型根命中时根节点本身也触发 postHitVisit（根是命中对象祖先之一）。
        /// </summary>
        public static bool WalkModels(
            IEnumerable<Model> models,
            Func<ModelItem, ModelItemWalkAction> visit,
            Action<ModelItem> postHitVisit = null,
            Action<ModelItem> onHidden = null)
        {
            bool anyHit = false;
            foreach (var model in models)
            {
                if (model?.RootItem == null)
                {
                    continue;
                }

                bool rootHit = WalkVisible(model.RootItem, visit, postHitVisit, onHidden);
                if (rootHit)
                {
                    postHitVisit?.Invoke(model.RootItem);
                    anyHit = true;
                }
            }

            return anyHit;
        }
    }
}
