# SPDX-FileCopyrightText: Copyright (c) 2022-2025, The Isaac Lab Project Developers.
# SPDX-License-Identifier: BSD-3-Clause

"""Single-arm XR teleoperation agent."""

from __future__ import annotations

import torch

from .base_agent import BaseTeleopAgent
from .xr_controller import XrTeleopController
from .frame_utils import convert_action_world_to_root


class SingleArmXrAgent(BaseTeleopAgent):
    """Single-arm teleoperation: one XR controller -> one robot arm + gripper.

    Action: arm(7) | gripper(1) = 8D
    """

    def __init__(self, env, simulation_app, *,
                 arm: str = "left",
                 pos_sensitivity: float = 1.0,
                 rot_sensitivity: float = 0.3,
                 xr_client=None,
                 debug_viewports: bool = True):
        super().__init__(env, simulation_app, debug_viewports=debug_viewports)

        self.xr_client = xr_client
        self.teleop = XrTeleopController(
            arm=arm, pos_sensitivity=pos_sensitivity,
            rot_sensitivity=rot_sensitivity, xr_client=xr_client,
        )
        self.teleop.add_callback("RESET", self.request_reset)
        self._last_root = None

    def _ik_action_term_names(self) -> list[str]:
        return ["arm_action"]

    def on_reset(self):
        self.teleop.reset()
        self._last_root = None

    def assemble_action(self, obs) -> torch.Tensor:
        policy_obs = obs["policy"]
        eef_pos = policy_obs["eef_pos"][0].cpu().numpy()
        eef_quat = policy_obs["eef_quat"][0].cpu().numpy()

        action = self.teleop.advance(current_eef_pos=eef_pos, current_eef_quat=eef_quat)

        robot = self.env.unwrapped.scene["robot"]
        if self.teleop.grip_active or self._last_root is None:
            self._last_root = convert_action_world_to_root(action, robot)[:7].clone()

        # arm(7) | gripper(1)
        return torch.cat([self._last_root, action[7:8]])

    def cleanup(self):
        self.teleop.close()
        super().cleanup()
