import carb
import omni.usd
import omni.kit.usd.layers as layers
import omni.kit.collaboration.presence_layer as pl

from pxr import Usd, Sdf
from omni.kit.viewport.utility import get_active_viewport_camera_path, get_active_viewport_window


class LocalUserSharedData:

    def __init__(self, usd_context: omni.usd.UsdContext, user_name: str, user_id: str):
        self.usd_context = usd_context
        self.presence_layer = pl.get_presence_layer_interface(self.usd_context)
        self.user_name = user_name
        self.user_id = user_id

        self.__current_bound_camera_path = None

        self.__last_viewport_width = 0
        self.__last_viewport_height = 0
        self.__following_user_id = None

        self.update_viewport_bound_camera()

    def destroy(self):
        self.presence_layer = None
        self.usd_context = None
        self.__following_user_id = None

    @property
    def following_user_id(self):
        return self.__following_user_id

    @following_user_id.setter
    def following_user_id(self, value):
        self.__following_user_id = value

    @property
    def bound_camera_path(self) -> Sdf.Path:
        return self.__current_bound_camera_path

    def update_viewport_bound_camera(self, broadcast=True) -> bool:
        active_camera_path = get_active_viewport_camera_path()
        if active_camera_path and self.__current_bound_camera_path != active_camera_path:
            self.__set_bound_camera_path(active_camera_path, broadcast)
            return True

        return False

    def update_viewport_size(self) -> bool:
        viewport_window = get_active_viewport_window()
        if viewport_window:
            frame = viewport_window.frame
            if (
                self.__last_viewport_width != frame.computed_width
                or self.__last_viewport_height != frame.computed_height
            ):
                self.__last_viewport_width = frame.computed_width
                self.__last_viewport_height = frame.computed_height

                return True

        return False

    def broadcast_local_changes(self):
        if not self.__current_bound_camera_path or self.__following_user_id:
            return

        self.presence_layer.broadcast_local_bound_camera(self.__current_bound_camera_path)

    def __set_bound_camera_path(self, bound_camera_path, broadcast=True):
        self.__current_bound_camera_path = bound_camera_path
        # Clear bound camera as user it not bound to any cameras but following other users.
        if self.__following_user_id:
            camera_path = ""
        else:
            camera_path = bound_camera_path

        if broadcast:
            self.presence_layer.broadcast_local_bound_camera(camera_path)
