from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QMenu, QStyle
from PyQt5.QtGui import QFont
from PyQt5.QtCore import Qt
from PyQt5.sip import delete
from panda3d.core import GeomNode, ModelRoot


class InterfaceManager:
    """界面管理器 - 处理树形控件和UI交互"""

    def __init__(self, world):
        """初始化界面管理器"""
        self.world = world
        self.treeWidget = None
        self._expanded_paths = set()

    def setTreeWidget(self, treeWidget):
        """设置树形控件引用并更新场景树"""
        self.treeWidget = treeWidget

        # 添加右键菜单
        # self.treeWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        # self.treeWidget.customContextMenuRequested.connect(self.showTreeContextMenu)

        # 更新场景树
        self.world.scene_manager.updateSceneTree()

    def onTreeWidgetClicked(self, index):
        """处理树形控件点击事件（包括空白区域）"""
        # 检查点击的是否是空白区域
        if not self.treeWidget.itemFromIndex(index):  # 点击的是空白区域
            self.world.selection.updateSelection(None)
            self.world.property_panel.clearPropertyPanel()
            print("点击树形控件空白区域，清除选中状态")

    def onTreeCurrentItemChanged(self, current, previous):
        """处理树形控件当前选中项改变事件"""
        # 当 current 为 None 时，表示点击了空白区域
        if current is None:
            self.world.selection.updateSelection(None)
            print("点击空白区域，清除选中状态")
        # 当 current 不为 None 时，表示选中了某个项目
        else:
            # 更新选择状态
            nodePath = current.data(0, Qt.UserRole)
            if nodePath:
                self.world.selected_np = nodePath
                self.world.selection.updateSelection(nodePath)
                self.world.property_panel.updatePropertyPanel(current)
                print(f"树形控件选中项改变: {current.text(0)}")

    def onTreeItemClicked(self, item, column):
        """处理树形控件项目点击事件"""
        #print(f"树形控件点击事件触发，item: {item}, column: {column}")

        # 检查是否点击了空白区域
        # 当点击空白区域时，item可能是一个空的QTreeWidgetItem对象
        if not item or (item.text(0) == "" and item.data(0, Qt.UserRole) is None):
            self.world.selection.updateSelection(None)
            print("点击空白区域，清除选中状态")
            return

        self.world.property_panel.updatePropertyPanel(item)

        # 获取节点对象
        nodePath = item.data(0, Qt.UserRole)
        if nodePath:
            # 更新选择状态
            self.world.selected_np = nodePath
            self.world.selection.updateSelection(nodePath)
            print(f"树形控件点击: {item.text(0)}")
        else:
            # 如果没有节点对象，清除选择
            self.world.selection.updateSelection(None)
            self.world.property_panel.clearPropertyPanel()
            print("点击了无数据项，清除选中状态")

    def isModelOrChild(self, item):
        """检查是否是模型节点或其子节点"""
        while item and item.parent():
            if item.parent().text(0) == "模型":
                return True
            item = item.parent()
        return False

    def deleteNode(self, nodePath, item):
        """删除节点"""
        try:
            # 如果是灯光节点，直接调用灯光删除方法
            if self.isLightNode(nodePath):
                self.deleteLightNode(nodePath, item)
                return

            item_data = item.data(0, Qt.UserRole + 1)
            if item_data == "terrain":
                if hasattr(self.world, 'terrain_manager') and self.world.terrain_manager.terrains:
                    terrain_to_remove = None
                    for terrain_info in self.world.terrain_manager.terrains:
                        if terrain_info['node'] == nodePath:
                            terrain_to_remove = terrain_info
                            break
                    if terrain_to_remove:
                        self.world.terrain_manager.deleteTerrain(terrain_to_remove)
                        print(f"成功删除地形节点：{nodePath.getName()}")
                        # self.updateSceneTree()
                        # self.world.property_panel.clearPropertyPanel()
                        # self.world.selection.updateSelection(None)
                        return

            # 先递归删除所有子节点中的灯光
            self._recursiveRemoveLights(nodePath)

            # 从场景中移除
            self.world.property_panel.removeActorForModel(nodePath)

            # 清除选择状态
            if hasattr(self.world, 'selection'):
                if self.world.selection.selectedNode == nodePath:
                    self.world.selection.clearSelectionBox()
                    self.world.selection.clearGizmo()
                    self.world.selection.selectedNode = None
                    self.world.selection.selectedObject = None

            # 强制删除节点及其所有子节点
            if not nodePath.isEmpty():
                # 先递归删除所有子节点
                children = list(nodePath.getChildren())
                for child in children:
                    try:
                        if not child.isEmpty():
                            child.removeNode()
                    except Exception as e:
                        print(f"删除子节点失败: {str(e)}")

                # 再删除节点本身
                nodePath.removeNode()

            if hasattr(self.world, 'selection'):
                self.world.selection.checkAndClearIfTargetDeleted()

            if hasattr(self.world, 'models') and nodePath in self.world.models:
                self.world.models.remove(nodePath)

            # 从树形控件中移除
            parentItem = item.parent()
            if parentItem:
                parentItem.removeChild(item)

            print(f"成功删除节点: {nodePath.getName()}")

            # 清空属性面板和选择框
            self.world.property_panel.clearPropertyPanel()
            self.world.selection.updateSelection(None)

        except Exception as e:
            print(f"删除节点失败: {str(e)}")
            import traceback
            traceback.print_exc()

    def _cleanupAllLightsInSubtree(self,parentNode):
        try:
            if parentNode.isEmpty():
                return
            #收集所有子节点
            all_nodes = []

            def collect_all_nodes(node):
                if not node.isEmpty():
                    all_nodes.append(node)
                    for child in node.getChildren():
                        collect_all_nodes(child)

            collect_all_nodes(parentNode)

            ligths_processed = 0
            for node in all_nodes:
                if self.isLightNode(node):
                    if hasattr(node,'getPythonTag'):
                        light_object = node.getPythonTag('rp_light_object')
                        if light_object and hasattr(self.world,'render_pipeline'):
                            try:
                                self.world.render_pipeline.remove_light(light_object)
                                print(f"✓ 从渲染管线移除灯光: {node.getName()}")
                            except Exception as e:
                                print(f"⚠ 从渲染管线移除灯光失败: {str(e)}")
                    #从灯光列表中移除
                    try:
                        if node in self.world.Spotlight:
                            self.world.Spotlight.remove(node)
                            print(f"从Spotlight列表移除{node.getName()}")
                        if node in self.world.Pointlight:
                            self.world.Pointlight.remove(node)
                            print(f"从pointlight列表移除{node.getName()}")
                    except Exception as e:
                        print(f"从灯列表移除失败{str(e)}")
                    ligths_processed += 1
            if ligths_processed>0:
                print(f"清理{ligths_processed}个灯光节点")
        except Exception as e:
            print(f"清理节点树中的灯光失败{str(e)}")


    def updateSceneTree(self):
        """更新场景树显示 - 实际实现"""
        if not self.treeWidget:
            return
        self._expanded_paths.clear()
        self._collect_expanded()

        print("\n=== 更新场景树 ===")
        self.treeWidget.clear()

        # 创建场景根节点
        sceneRoot = QTreeWidgetItem(self.treeWidget, ['场景'])
        sceneRoot.setData(0, Qt.UserRole, self.world.render)
        sceneRoot.setData(0, Qt.UserRole + 1, "SCENE_ROOT")
        font = QFont("Microsoft YaHei", 10, QFont.Light)  # 假设您希望字体大小为10
        sceneRoot.setFont(0, font)
        # 添加相机节点
        cameraItem = QTreeWidgetItem(sceneRoot, ['相机'])
        cameraItem.setData(0, Qt.UserRole, self.world.cam)
        cameraItem.setData(0, Qt.UserRole + 1, "CAMERA_NODE")
        print("添加相机节点")

        BLACK_LIST = {'','**','temp','collision'}

        from panda3d.core import CollisionNode
        def should_skip(node):
            name = node.getName()
            return name in BLACK_LIST or name.startswith('__') or isinstance(node.node(),CollisionNode) or isinstance(node.node(),ModelRoot) or name==""

        def addNodeToTree(node,parentItem,force = False):
            if node.isEmpty():
                return

            if not force and should_skip(node):
                return
            nodeItem = QTreeWidgetItem(parentItem,[node.getName()])
            nodeItem.setData(0,Qt.UserRole,node)

            for child in node.getChildren():
                addNodeToTree(child,nodeItem,force = False)

        for model in self.world.models:
            if not model.isEmpty():
                addNodeToTree(model, sceneRoot,force=True)

        # 添加所有GUI元素
        for gui in self.world.gui_elements:
            # 检查是否是有效的GUI节点（具有getTag方法的NodePath）
            if hasattr(gui, 'getTag') and hasattr(gui, 'getName'):
                gui_type = gui.getTag("gui_type") or "unknown"
                gui_text = gui.getTag("text") or gui.getTag("gui_text") or "GUI元素"
                item = QTreeWidgetItem(sceneRoot, [f"{gui_type}: {gui_text}"])
                item.setData(0, Qt.UserRole, gui)
            else:
                # 跳过非GUI节点（如QDockWidget等Qt对象）
                continue

            # 添加地板节点
        if hasattr(self.world, 'ground') and self.world.ground:
            groundItem = QTreeWidgetItem(sceneRoot, ['地板'])
            groundItem.setData(0, Qt.UserRole, self.world.ground)
            groundItem.setData(0,Qt.UserRole + 1, "SCENE_NODE")

        ground_nodes = [
            ('ground2','地板2'),
            ('ground3','地板3'),
            ('ground4','地板4'),
            ('ground5','地板5'),
            ('ground6','地板6')
        ]

        for attr_name,display_name in ground_nodes:
            if hasattr(self.world,attr_name):
                ground_node = getattr(self.world,attr_name)
                if ground_node:
                    extraGroundItem = QTreeWidgetItem(sceneRoot,[display_name])
                    extraGroundItem.setData(0,Qt.UserRole,ground_node)
                    extraGroundItem.setData(0,Qt.UserRole+1,"SCENE_NODE")


        #添加灯光节点
        for light in self.world.Spotlight:
            if light:
                addNodeToTree(light, sceneRoot, force=True)

        for light in self.world.Pointlight:
            if light:
                addNodeToTree(light, sceneRoot, force=True)

        # for light in self.world.Spotlight + self.world.Pointlight:
        #     if not light.isEmpty:
        #         print(f"33333333333333333333333333333{light}")
        #         addNodeToTree(light, sceneRoot, force=True)

        #添加 Cesium tilesets
        if hasattr(self.world,'scene_manager') and hasattr(self.world.scene_manager,'tilesets'):
            for i , tileset_info in enumerate(self.world.scene_manager.tilesets):
                tileset_node = tileset_info['node']
                if not tileset_node.isEmpty():
                    tileset_url = tileset_info['url']
                    tileset_item = QTreeWidgetItem(sceneRoot,[f"Cesium Tileset {i}"])
                    tileset_item.setData(0,Qt.UserRole,tileset_node)
                    addNodeToTree(tileset_node,tileset_item,force=True)
        #添加地形节点
        if hasattr(self.world,'terrain_manager') and self.world.terrain_manager.terrains:
            for terrain_info in self.world.terrain_manager.terrains:
                terrain_node = terrain_info['node']
                terrain_name = terrain_info.get('name','未知地形')
                terrain_item = QTreeWidgetItem(sceneRoot,[f"地形:{terrain_name}"])
                terrain_item.setData(0,Qt.UserRole,terrain_node)
                terrain_item.setData(0,Qt.UserRole+1,"terrain") # 标记为地形节点
                addNodeToTree(terrain_node,terrain_item,force=True)

        # 展开所有节点
        #self.treeWidget.expandAll()
        self._restore_expanded()
        print("=== 场景树更新完成 ===\n")

    def findTreeItem(self, node, parentItem):
        """在树形控件中查找指定的节点项"""
        for i in range(parentItem.childCount()):
            item = parentItem.child(i)
            itemNode = item.data(0, Qt.UserRole)
            if itemNode == node:
                return item
            # 递归查找子项
            if item.childCount() > 0:
                found = self.findTreeItem(node, item)
                if found:
                    return found
        return None

    def _collect_expanded(self,item=None,prefix=""):
        if item is None:
            root = self.treeWidget.invisibleRootItem()
            for i in range(root.childCount()):
                self._collect_expanded(root.child(i),prefix)
            return
        path = f"{prefix}/{item.text(0)}"
        if item.isExpanded():
            self._expanded_paths.add(path)

        for i in range(item.childCount()):
            self._collect_expanded(item.child(i),path)

    def _restore_expanded(self,item=None,prefix=""):
        if item is None:
            root = self.treeWidget.invisibleRootItem()
            for i in range(root.childCount()):
                self._restore_expanded(root.child(i),prefix)
            return
        path = f"{prefix}/{item.text(0)}"
        if path in self._expanded_paths:
            item.setExpanded(True)

        for i in range(item.childCount()):
            self._restore_expanded(item.child(i),path)


    def syncVisibilityDownward(self):
        from collections import deque

        if not self.world.models:
            return
        q = deque()

        for root in self.world.models:
            q.append(root)

        while q:
            node = q.popleft()

            visible = node.getPythonTag("visible")
            if visible is None:
                visible = True
            if not visible:
                stack = [node]
                while stack:
                    cur = stack.pop()
                    cur.hide()

                    for child in cur.getChildren():
                        stack.append(child)
                continue
            node.show()

            for child in node.getChildren():
                q.append(child)
