#!/usr/bin/env python3
"""
验证 teleop_xr_agent.py 中相对模式下动作拼接顺序的正确性。
无需 Isaac Sim / XR 设备，纯 CPU 运行。

运行方式：
    python scripts/debug_action_assembly.py
"""

import torch

# ============================================================
# 模拟 Action Manager 的切分逻辑
# ============================================================
# 来自 mindrobot_left_arm_ik_env_cfg.py 的 Action 配置：
#   arm_action  : DifferentialInverseKinematicsActionCfg，相对模式 6D，绝对模式 7D
#   wheel_action: JointVelocityActionCfg，4 个轮子，4D
#   gripper_action: BinaryJointPositionActionCfg，1D

def action_manager_split(action: torch.Tensor, arm_size: int):
    """模拟 Isaac Lab ManagerBasedRLEnv 的动作切分。"""
    assert action.shape[-1] == arm_size + 4 + 1, \
        f"期望总维度 {arm_size + 4 + 1}，实际 {action.shape[-1]}"
    arm    = action[..., :arm_size]
    wheel  = action[..., arm_size:arm_size + 4]
    gripper = action[..., arm_size + 4:]
    return arm, wheel, gripper


# ============================================================
# 复现 teleop_xr_agent.py:474 的拼接逻辑
# ============================================================

def current_assembly(action_np: torch.Tensor, wheel_np: torch.Tensor) -> torch.Tensor:
    """现有代码的拼接逻辑（逐字复制自 teleop_xr_agent.py:474）。"""
    return torch.cat([action_np[:7], wheel_np, action_np[7:]])


def fixed_assembly(action_np: torch.Tensor, wheel_np: torch.Tensor, is_abs_mode: bool) -> torch.Tensor:
    """修正后的拼接逻辑。"""
    arm_size = 7 if is_abs_mode else 6
    arm_action   = action_np[:arm_size]
    gripper_val  = action_np[arm_size:]   # 最后一个元素
    return torch.cat([arm_action, wheel_np, gripper_val])


# ============================================================
# 测试
# ============================================================

def run_test(mode: str):
    is_abs = (mode == "absolute")
    arm_size = 7 if is_abs else 6

    # 构造可辨识的测试值
    if is_abs:
        # 绝对模式：[x,y,z,qw,qx,qy,qz, gripper]
        fake_action = torch.tensor([0.1, 0.2, 0.3,   # pos
                                    1.0, 0.0, 0.0, 0.0,  # quat
                                    0.9])             # gripper (trigger=0.9)
    else:
        # 相对模式：[dx,dy,dz, drx,dry,drz, gripper]
        fake_action = torch.tensor([0.01, 0.02, 0.03,  # delta pos
                                    0.05, 0.06, 0.07,  # delta rot
                                    0.9])              # gripper (trigger=0.9)

    fake_wheel = torch.tensor([1.5, 1.5, 1.5, 1.5])  # 向前行驶

    print(f"\n{'='*60}")
    print(f"  测试模式: {mode.upper()}")
    print(f"{'='*60}")
    print(f"  原始 action_np  : {fake_action.tolist()}")
    print(f"  原始 wheel_np   : {fake_wheel.tolist()}")
    print(f"  期望 gripper 值 : {fake_action[-1].item()} (应为 0.9)")
    print(f"  期望 wheel  值  : {fake_wheel.tolist()} (应为 [1.5,1.5,1.5,1.5])")

    # ---- 现有代码 ----
    assembled_current = current_assembly(fake_action, fake_wheel)
    try:
        arm_c, wheel_c, grip_c = action_manager_split(assembled_current, arm_size)
        print(f"\n  [现有代码]")
        print(f"    拼接结果({assembled_current.shape[0]}D) : {assembled_current.tolist()}")
        print(f"    → arm     ({arm_c.shape[0]}D) : {arm_c.tolist()}")
        print(f"    → wheel   ({wheel_c.shape[0]}D) : {wheel_c.tolist()}")
        print(f"    → gripper ({grip_c.shape[0]}D) : {grip_c.tolist()}")
        arm_ok    = True
        wheel_ok  = torch.allclose(wheel_c, fake_wheel)
        grip_ok   = torch.allclose(grip_c, fake_action[-1:])
        print(f"    arm 正确? {'✅' if arm_ok else '❌'} | wheel 正确? {'✅' if wheel_ok else '❌  ← BUG'} | gripper 正确? {'✅' if grip_ok else '❌  ← BUG'}")
    except AssertionError as e:
        print(f"    [现有代码] 维度断言失败: {e}")

    # ---- 修正后代码 ----
    assembled_fixed = fixed_assembly(fake_action, fake_wheel, is_abs)
    try:
        arm_f, wheel_f, grip_f = action_manager_split(assembled_fixed, arm_size)
        print(f"\n  [修正后代码]")
        print(f"    拼接结果({assembled_fixed.shape[0]}D) : {assembled_fixed.tolist()}")
        print(f"    → arm     ({arm_f.shape[0]}D) : {arm_f.tolist()}")
        print(f"    → wheel   ({wheel_f.shape[0]}D) : {wheel_f.tolist()}")
        print(f"    → gripper ({grip_f.shape[0]}D) : {grip_f.tolist()}")
        arm_ok    = True
        wheel_ok  = torch.allclose(wheel_f, fake_wheel)
        grip_ok   = torch.allclose(grip_f, fake_action[-1:])
        print(f"    arm 正确? {'✅' if arm_ok else '❌'} | wheel 正确? {'✅' if wheel_ok else '❌'} | gripper 正确? {'✅' if grip_ok else '❌'}")
    except AssertionError as e:
        print(f"    [修正后代码] 维度断言失败: {e}")


if __name__ == "__main__":
    run_test("relative")
    run_test("absolute")
    print()
