# Copyright (c) 2025, Yutang Li, SIAT (yt.li2@siat.ac.cn)
# SPDX-License-Identifier: BSD-3-Clause

"""Coordinate frame utilities for XR teleoperation."""

import numpy as np
import torch
from scipy.spatial.transform import Rotation as R


def quat_wxyz_to_rotation(quat_wxyz: np.ndarray) -> R:
    """Convert Isaac-style wxyz quaternion to scipy Rotation."""
    return R.from_quat([quat_wxyz[1], quat_wxyz[2], quat_wxyz[3], quat_wxyz[0]])


def rotation_to_quat_wxyz(rot: R) -> np.ndarray:
    """Convert scipy Rotation to Isaac-style wxyz quaternion."""
    q = rot.as_quat()
    return np.array([q[3], q[0], q[1], q[2]])


def world_pose_to_root_frame(
    pos_w: np.ndarray,
    quat_wxyz: np.ndarray,
    root_pos_w: np.ndarray,
    root_quat_wxyz: np.ndarray,
) -> tuple[np.ndarray, np.ndarray]:
    """Express a world-frame pose in the robot root frame."""
    root_rot = quat_wxyz_to_rotation(root_quat_wxyz)
    pose_rot = quat_wxyz_to_rotation(quat_wxyz)
    pos_root = root_rot.inv().apply(pos_w - root_pos_w)
    quat_root = rotation_to_quat_wxyz(root_rot.inv() * pose_rot)
    return pos_root, quat_root


def convert_action_world_to_root(action_tensor: torch.Tensor, robot) -> torch.Tensor:
    """Convert absolute IK action from world frame to robot root frame.

    Args:
        action_tensor: 8D tensor [x, y, z, qw, qx, qy, qz, gripper] in world frame.
        robot: Isaac Lab Articulation object (env.unwrapped.scene["robot"]).

    Returns:
        8D tensor with pos/quat converted to robot root frame.
    """
    root_pos_w = robot.data.root_pos_w[0].detach().cpu().numpy()
    root_quat_w = robot.data.root_quat_w[0].detach().cpu().numpy()
    pos_root, quat_root = world_pose_to_root_frame(
        action_tensor[:3].numpy(), action_tensor[3:7].numpy(),
        root_pos_w, root_quat_w,
    )
    out = action_tensor.clone()
    out[:3] = torch.tensor(pos_root, dtype=torch.float32)
    out[3:7] = torch.tensor(quat_root, dtype=torch.float32)
    return out
