#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
选择框边界测试脚本

测试保存和加载场景后选择框是否正常显示
"""

import sys
import os
import tempfile
import shutil

# 添加项目路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from main import MyWorld
from PyQt5.QtWidgets import QApplication

def test_selection_bounds():
    """测试选择框边界问题"""
    
    print("=== 选择框边界测试 ===\n")
    
    # 创建应用程序
    app = QApplication.instance()
    if app is None:
        app = QApplication(sys.argv)
    
    # 创建世界
    world = MyWorld()
    
    return test_selection_bounds_with_world(world)

def test_selection_bounds_with_world(world):
    """使用提供的world实例测试选择框边界问题"""
    
    print("=== 选择框边界测试 ===\n")
    
    # 清理之前的测试数据
    world.models.clear()
    for child in world.render.getChildren():
        if child.getName() in ["test_cube", "fbx_model", "selectionBox", "gizmo"]:
            child.removeNode()
    
    print("1. 创建测试模型...")
    
    # 创建一个简单的测试立方体
    from panda3d.core import CardMaker
    cm = CardMaker("test_cube")
    cm.setFrame(-1, 1, -1, 1)
    
    # 创建立方体的6个面（使用ModelRoot确保保存/加载正常）
    from panda3d.core import ModelRoot
    model_root = ModelRoot("test_cube")
    cube = world.render.attachNewNode(model_root)
    
    # 前面
    front = cube.attachNewNode(cm.generate())
    front.setP(-90)
    front.setZ(1)
    front.setColor(1, 0, 0, 1)
    
    # 后面
    back = cube.attachNewNode(cm.generate())
    back.setP(-90)
    back.setZ(-1)
    back.setColor(0, 1, 0, 1)
    
    # 设置测试缩放（模拟FBX导入后的状态）
    cube.setScale(0.5, 0.5, 0.5)
    cube.setPos(2, 0, 1)
    
    # 设置碰撞检测
    world.scene_manager.setupCollision(cube)
    
    # 添加到模型列表
    world.models.append(cube)
    cube.setTag("file", "test_cube.fbx")
    cube.setTag("is_model_root", "1")
    
    print("✓ 测试模型创建完成")
    print(f"  位置: {cube.getPos()}")
    print(f"  缩放: {cube.getScale()}")
    print(f"  边界: {cube.getBounds().getMin()} 到 {cube.getBounds().getMax()}")
    
    print("\n2. 测试选择功能...")
    
    # 选择模型
    world.selection.updateSelection(cube)
    
    # 获取原始选择框信息
    original_bounds = cube.getBounds()
    original_pos = cube.getPos()
    original_scale = cube.getScale()
    
    print(f"  原始边界: {original_bounds.getMin()} 到 {original_bounds.getMax()}")
    print(f"  原始位置: {original_pos}")
    print(f"  原始缩放: {original_scale}")
    
    print("\n3. 保存场景...")
    
    # 创建临时文件
    temp_dir = tempfile.mkdtemp(prefix="bounds_test_")
    scene_file = os.path.join(temp_dir, "test_scene.bam")
    
    try:
        # 保存场景
        success = world.scene_manager.saveScene(scene_file)
        if success:
            print("✓ 场景保存成功")
        else:
            print("✗ 场景保存失败")
            return False
        
        print("\n4. 重新加载场景...")
        
        # 加载场景
        success = world.scene_manager.loadScene(scene_file)
        if success:
            print("✓ 场景加载成功")
        else:
            print("✗ 场景加载失败")
            return False
        
        print("\n5. 检查加载后的模型状态...")
        
        if not world.models:
            print("✗ 加载后没有找到模型")
            return False
        
        loaded_model = world.models[0]
        loaded_bounds = loaded_model.getBounds()
        loaded_pos = loaded_model.getPos()
        loaded_scale = loaded_model.getScale()
        
        print(f"  加载后边界: {loaded_bounds.getMin()} 到 {loaded_bounds.getMax()}")
        print(f"  加载后位置: {loaded_pos}")
        print(f"  加载后缩放: {loaded_scale}")
        
        print("\n6. 比较结果...")
        
        # 检查位置是否一致
        pos_diff = (loaded_pos - original_pos).length()
        scale_diff = (loaded_scale - original_scale).length()
        
        print(f"  位置差异: {pos_diff}")
        print(f"  缩放差异: {scale_diff}")
        
        # 检查边界大小
        original_size = (original_bounds.getMax() - original_bounds.getMin()).length()
        loaded_size = (loaded_bounds.getMax() - loaded_bounds.getMin()).length()
        size_diff = abs(loaded_size - original_size)
        
        print(f"  原始边界大小: {original_size:.3f}")
        print(f"  加载后边界大小: {loaded_size:.3f}")
        print(f"  边界大小差异: {size_diff:.3f}")
        
        print("\n7. 测试选择框...")
        
        # 选择加载后的模型
        world.selection.updateSelection(loaded_model)
        
        # 检查选择框是否创建成功
        if world.selection.selectionBox:
            print("✓ 选择框创建成功")
        else:
            print("✗ 选择框创建失败")
            return False
        
        print("\n=== 测试结果 ===")
        
        success = True
        
        if pos_diff < 0.01:
            print("✓ 位置信息正确恢复")
        else:
            print("✗ 位置信息恢复有误")
            success = False
        
        if scale_diff < 0.01:
            print("✓ 缩放信息正确恢复")
        else:
            print("✗ 缩放信息恢复有误")
            success = False
            
        if size_diff < 0.1:
            print("✓ 边界大小正常")
        else:
            print("✗ 边界大小异常")
            success = False
        
        if success:
            print("\n🎉 选择框边界测试通过！")
            print("保存和加载后选择框显示正常。")
        else:
            print("\n❌ 选择框边界测试失败。")
            print("需要进一步检查变换信息的保存和恢复。")
        
        return success
        
    except Exception as e:
        print(f"测试过程中出现错误: {str(e)}")
        import traceback
        traceback.print_exc()
        return False
        
    finally:
        # 清理临时文件
        try:
            shutil.rmtree(temp_dir)
            print(f"\n清理临时文件: {temp_dir}")
        except Exception as e:
            print(f"清理临时文件失败: {str(e)}")

def test_fbx_simulation(world=None):
    """模拟FBX模型的缩放标准化情况"""
    
    print("\n=== FBX缩放标准化测试 ===\n")
    
    # 重用现有的world实例，避免ShowBase冲突
    if world is None:
        # 创建应用程序
        app = QApplication.instance()
        if app is None:
            app = QApplication(sys.argv)
        
        # 创建世界
        world = MyWorld()
    else:
        # 清理之前的测试数据
        world.models.clear()
        for child in world.render.getChildren():
            if child.getName() in ["test_cube", "fbx_model", "selectionBox", "gizmo"]:
                child.removeNode()
    
    print("1. 创建模拟FBX模型（大缩放值）...")
    
    # 创建一个模拟FBX导入的模型结构
    from panda3d.core import CardMaker, ModelRoot
    
    # 创建根节点（使用ModelRoot确保保存/加载正常）
    model_root_node = ModelRoot("fbx_model")
    model_root = world.render.attachNewNode(model_root_node)
    
    # 创建子节点，模拟FBX的大缩放值
    child_node = model_root.attachNewNode("mesh_node")
    child_node.setScale(100, 100, 100)  # 模拟FBX的厘米到米转换问题
    
    # 创建几何体
    cm = CardMaker("geometry")
    cm.setFrame(-0.01, 0.01, -0.01, 0.01)  # 很小的几何体，配合大缩放
    geom = child_node.attachNewNode(cm.generate())
    geom.setColor(0, 0, 1, 1)
    
    # 应用标准化（模拟导入时的处理）
    print("2. 应用缩放标准化...")
    normalize_factor = 0.01  # 1/100
    child_node.setScale(child_node.getScale() * normalize_factor)
    child_node.setPos(child_node.getPos() * normalize_factor)
    
    print(f"  标准化后缩放: {child_node.getScale()}")
    print(f"  标准化后位置: {child_node.getPos()}")
    
    # 设置模型根的标准变换
    model_root.setPos(0, 5, 0)
    model_root.setScale(2, 2, 2)
    
    # 设置碰撞检测
    world.scene_manager.setupCollision(model_root)
    
    # 添加到模型列表
    world.models.append(model_root)
    model_root.setTag("file", "test_fbx.fbx")
    model_root.setTag("is_model_root", "1")
    model_root.setTag("scale_normalization_applied", "true")
    
    print(f"  模型根位置: {model_root.getPos()}")
    print(f"  模型根缩放: {model_root.getScale()}")
    print(f"  模型边界: {model_root.getBounds().getMin()} 到 {model_root.getBounds().getMax()}")
    
    # 继续使用与前面测试相同的流程
    print("\n3. 保存和加载测试...")
    
    # 创建临时文件
    temp_dir = tempfile.mkdtemp(prefix="fbx_bounds_test_")
    scene_file = os.path.join(temp_dir, "fbx_test_scene.bam")
    
    try:
        # 保存场景
        world.scene_manager.saveScene(scene_file)
        
        # 记录原始状态
        original_bounds = model_root.getBounds()
        original_pos = model_root.getPos()
        original_scale = model_root.getScale()
        
        # 重新加载
        world.scene_manager.loadScene(scene_file)
        
        # 检查结果
        if world.models:
            loaded_model = world.models[0]
            loaded_bounds = loaded_model.getBounds()
            loaded_pos = loaded_model.getPos()
            loaded_scale = loaded_model.getScale()
            
            print(f"  原始边界大小: {(original_bounds.getMax() - original_bounds.getMin()).length():.3f}")
            print(f"  加载后边界大小: {(loaded_bounds.getMax() - loaded_bounds.getMin()).length():.3f}")
            
            pos_diff = (loaded_pos - original_pos).length()
            scale_diff = (loaded_scale - original_scale).length()
            
            print(f"  位置差异: {pos_diff:.6f}")
            print(f"  缩放差异: {scale_diff:.6f}")
            
            if pos_diff < 0.01 and scale_diff < 0.01:
                print("✓ FBX模拟测试通过")
                return True
            else:
                print("✗ FBX模拟测试失败")
                return False
        else:
            print("✗ 加载后没有找到模型")
            return False
            
    finally:
        # 清理临时文件
        try:
            shutil.rmtree(temp_dir)
        except:
            pass

if __name__ == "__main__":
    print("选择框边界问题测试\n")
    
    # 创建应用程序
    app = QApplication.instance()
    if app is None:
        app = QApplication(sys.argv)
    
    # 创建世界（只创建一次）
    world = MyWorld()
    
    # 运行基础测试
    test1_result = test_selection_bounds_with_world(world)
    
    # 运行FBX模拟测试
    test2_result = test_fbx_simulation(world)
    
    print(f"\n=== 最终测试结果 ===")
    print(f"基础边界测试: {'通过' if test1_result else '失败'}")
    print(f"FBX模拟测试: {'通过' if test2_result else '失败'}")
    
    if test1_result and test2_result:
        print("\n🎉 所有测试通过！选择框边界问题已修复。")
    else:
        print("\n❌ 部分测试失败，需要进一步调试。") 