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

"""Script to run teleoperation for MindRobot with chassis (wheel) control.

Extends teleop_se3_agent.py with differential-drive keyboard control:
    ↑ / ↓       — chassis forward / backward
    ← / →       — chassis left turn / right turn  (in-place, skid-steer)
    W/S/A/D/Q/E — left arm IK: translate X/Y/Z
    Z/X T/G C/V — left arm IK: rotate roll/pitch/yaw
    K           — left gripper toggle open/close
    R           — reset environment
"""

import argparse
import torch

from isaaclab.app import AppLauncher

parser = argparse.ArgumentParser(description="MindRobot teleoperation with wheel control.")
parser.add_argument("--num_envs", type=int, default=1)
parser.add_argument("--task", type=str, default=None)
parser.add_argument("--sensitivity", type=float, default=1.0)
parser.add_argument("--wheel_speed", type=float, default=5.0,
                    help="Wheel velocity in rad/s (default: 5.0)")
AppLauncher.add_app_launcher_args(parser)
args_cli = parser.parse_args()

app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app

# ---------- Rest everything follows ----------

import logging
import gymnasium as gym

from isaaclab.devices import Se3Keyboard, Se3KeyboardCfg
from isaaclab.envs import ManagerBasedRLEnvCfg

import mindbot.tasks  # noqa: F401
from isaaclab_tasks.utils import parse_env_cfg

# mindrobot_keyboard.py lives in the same directory as this script.
# Python adds the script's own directory to sys.path, so a direct import works.
from mindrobot_keyboard import WheelKeyboard, MindRobotCombinedKeyboard  # noqa: E402

logger = logging.getLogger(__name__)


# ─────────────────────────────────────────────────────────────
# main
# ─────────────────────────────────────────────────────────────
def main() -> None:
    env_cfg = parse_env_cfg(args_cli.task, device=args_cli.device, num_envs=args_cli.num_envs)
    env_cfg.env_name = args_cli.task
    if not isinstance(env_cfg, ManagerBasedRLEnvCfg):
        raise ValueError(f"Unsupported env config type: {type(env_cfg).__name__}")
    env_cfg.terminations.time_out = None

    env = gym.make(args_cli.task, cfg=env_cfg).unwrapped

    should_reset = False

    def on_reset():
        nonlocal should_reset
        should_reset = True
        print("[teleop] Reset triggered.")

    # ── 机械臂 IK 控制器（Se3Keyboard，7 维输出）──
    arm_keyboard = Se3Keyboard(
        Se3KeyboardCfg(
            pos_sensitivity=0.05 * args_cli.sensitivity,
            rot_sensitivity=0.05 * args_cli.sensitivity,
            sim_device=args_cli.device,
        )
    )
    arm_keyboard.add_callback("R", on_reset)

    # ── 底盘轮速控制器（WheelKeyboard，4 维输出）──
    wheel_keyboard = WheelKeyboard(
        wheel_speed=args_cli.wheel_speed,
        sim_device=args_cli.device,
    )

    print(arm_keyboard)
    print(wheel_keyboard)
    print("\nAction layout: [arm_IK(6) | wheel_vel(4) | gripper(1)] = 11 dims")
    print("Press R to reset. Press Ctrl+C to exit.\n")

    env.reset()
    arm_keyboard.reset()
    wheel_keyboard.reset()

    while simulation_app.is_running():
        with torch.inference_mode():
            # ── 1. 获取机械臂 delta pose + gripper (7维) ──
            arm_cmd = arm_keyboard.advance()          # [dx,dy,dz,rx,ry,rz, gripper]
            arm_ik   = arm_cmd[:6]                    # (6,)
            gripper  = arm_cmd[6:7]                   # (1,)

            # ── 2. 获取底盘轮速 (4维) ──
            wheel_vel = wheel_keyboard.advance()      # [right_b, left_b, left_f, right_f]

            # ── 3. 拼接完整 action (11维) ──
            # 顺序与 MindRobotTeleopActionsCfg 中的声明顺序一致:
            #   arm_action(6) → wheel_action(4) → gripper_action(1)
            action = torch.cat([arm_ik, wheel_vel, gripper])  # (11,)
            actions = action.unsqueeze(0).repeat(env.num_envs, 1)

            env.step(actions)

            if should_reset:
                env.reset()
                arm_keyboard.reset()
                wheel_keyboard.reset()
                should_reset = False
                print("[teleop] Environment reset complete.")

    env.close()


if __name__ == "__main__":
    main()
    simulation_app.close()
