"""
VR Effects Manager - 为VR场景中的模型自动应用RenderPipeline Effects

主要功能:
1. 扫描VR场景中的所有模型节点
2. 自动应用RenderPipeline的默认effect配置
3. 设置正确的shader tags以确保模型能正确渲染到GBuffer
4. 支持批量应用和单个模型应用
"""

from panda3d.core import NodePath, GeomNode


class VREffectsManager:
    """VR场景的RenderPipeline Effects管理器"""

    def __init__(self, pipeline):
        """
        初始化VR Effects Manager

        Args:
            pipeline: RenderPipeline实例
        """
        self.pipeline = pipeline
        self.applied_models = set()  # 记录已应用effects的模型

        # 默认的effect配置
        self.default_effect_config = {
            "normal_mapping": True,        # 法线贴图
            "render_gbuffer": True,        # 渲染到GBuffer
            "alpha_testing": False,        # Alpha测试
            "parallax_mapping": False,     # 视差贴图(性能考虑,VR中默认关闭)
            "render_shadow": True,         # 投射阴影
            "render_envmap": True,         # 环境映射
        }

    def apply_effects_to_scene(self, scene_root):
        """
        为场景根节点下的所有模型应用effects

        Args:
            scene_root: 场景根节点(通常是render或其子节点)

        Returns:
            int: 应用effects的模型数量
        """
        if not self.pipeline:
            print("⚠️ RenderPipeline未初始化,无法应用effects")
            return 0

        print("🎨 开始为VR场景应用RenderPipeline Effects...")
        count = 0

        # 递归遍历所有子节点
        for node in scene_root.findAllMatches("**/+GeomNode"):
            if self._should_apply_effect(node):
                if self.apply_effect_to_model(node):
                    count += 1

        print(f"✅ 为 {count} 个模型应用了RenderPipeline Effects")
        return count

    def apply_effect_to_model(self, model_node, effect_config=None):
        """
        为单个模型节点应用RenderPipeline effect

        Args:
            model_node: 模型的NodePath
            effect_config: 自定义effect配置(可选,默认使用default_effect_config)

        Returns:
            bool: 是否成功应用
        """
        if not isinstance(model_node, NodePath):
            print(f"⚠️ 无效的模型节点: {model_node}")
            return False

        # 使用提供的配置或默认配置
        config = effect_config or self.default_effect_config

        try:
            # 应用RenderPipeline effect
            self.pipeline.set_effect(
                model_node,
                "effects/default.yaml",
                config,
                sort=50  # 默认排序值
            )

            # 设置RenderPipeline shader tag
            # 这个tag告诉RenderPipeline这个模型需要通过GBuffer渲染
            model_node.setTag("RenderPipeline", "1")

            # 递归设置所有子节点的tag
            for child in model_node.findAllMatches("**/+GeomNode"):
                child.setTag("RenderPipeline", "1")

            # 记录已应用的模型
            model_id = id(model_node.node())
            self.applied_models.add(model_id)

            return True

        except Exception as e:
            print(f"❌ 应用effect失败: {model_node.getName()} - {e}")
            return False

    def apply_effect_to_model_simple(self, model_node):
        """
        为模型应用简化版effect(只设置tags,不调用set_effect)

        适用于某些特殊情况,例如:
        - 模型已经有自定义shader
        - 只需要确保模型能渲染到GBuffer
        - 避免覆盖现有的shader配置

        Args:
            model_node: 模型的NodePath

        Returns:
            bool: 是否成功
        """
        try:
            model_node.setTag("RenderPipeline", "1")

            # 递归设置所有子节点
            for child in model_node.findAllMatches("**/+GeomNode"):
                child.setTag("RenderPipeline", "1")

            return True

        except Exception as e:
            print(f"❌ 设置tags失败: {model_node.getName()} - {e}")
            return False

    def _should_apply_effect(self, node):
        """
        判断是否应该为节点应用effect

        Args:
            node: 待检查的节点

        Returns:
            bool: 是否应该应用effect
        """
        # 跳过已应用的模型
        model_id = id(node.node())
        if model_id in self.applied_models:
            return False

        # 跳过没有几何数据的节点
        if not node.node().getNumGeoms() > 0:
            return False

        # 跳过特殊标记的节点(例如:UI元素、调试几何体等)
        # 检查节点是否有"skip_pipeline"标签
        if node.hasTag("skip_pipeline"):
            return False

        # 跳过隐藏的节点
        if node.isHidden():
            return False

        return True

    def apply_effects_to_new_models(self, model_list):
        """
        为新添加的模型列表批量应用effects

        Args:
            model_list: 模型NodePath列表

        Returns:
            int: 成功应用effects的模型数量
        """
        count = 0
        for model in model_list:
            if self.apply_effect_to_model(model):
                count += 1

        print(f"✅ 为 {count}/{len(model_list)} 个新模型应用了effects")
        return count

    def update_effect_config(self, new_config):
        """
        更新默认effect配置

        Args:
            new_config: 新的配置字典(会合并到现有配置)
        """
        self.default_effect_config.update(new_config)
        print(f"✓ 更新effect配置: {new_config}")

    def get_applied_models_count(self):
        """获取已应用effects的模型数量"""
        return len(self.applied_models)

    def clear_applied_models_cache(self):
        """清空已应用模型的缓存(用于场景重置等情况)"""
        self.applied_models.clear()
        print("✓ 已清空effects应用缓存")


def setup_vr_model_effects(world, vr_root=None):
    """
    便捷函数:为VR场景设置RenderPipeline Effects

    Args:
        world: CoreWorld实例(需要有render_pipeline属性)
        vr_root: VR场景根节点(可选,默认使用world.render)

    Returns:
        VREffectsManager实例,或None(如果失败)
    """
    if not hasattr(world, 'render_pipeline') or not world.render_pipeline:
        print("⚠️ RenderPipeline未初始化")
        return None

    # 创建Effects Manager
    effects_mgr = VREffectsManager(world.render_pipeline)

    # 应用effects到场景
    scene_root = vr_root or world.render
    effects_mgr.apply_effects_to_scene(scene_root)

    return effects_mgr
