__all__ = ["PresenceLayerEventType", "PresenceLayerEventPayload", "get_presence_layer_event_payload"]
import carb

from enum import IntEnum
from typing import Set, List


EVENT_PAYLOAD_KEY = "payload"


class PresenceLayerEventType(IntEnum):
    # Emitted when local user enters/quits follow mode to other peer users.
    # REMIND: this event only applies to local user. In order to get the following status of other peer user,
    # you need to listen for BOUND_CAMERA_CHANGED below and PresenceLayerAPI.is_in_following_mode to check
    # if peer user is following other users.
    LOCAL_FOLLOW_MODE_CHANGED = carb.events.type_from_string("omni.kit.collaboration.presence_layer@local_follow_mode")

    # Emitted when peer user switched its bound camera or the the user that is following switches the bound camera.
    BOUND_CAMERA_CHANGED = carb.events.type_from_string("omni.kit.collaboration.presence_layer@bound_camera")

    # Emitted when peer user switched its selections.
    SELECTIONS_CHANGED = carb.events.type_from_string("omni.kit.collaboration.presence_layer@selections")

    # Emitted when the bound camera if peer user is builtin camera, and its properties are changed.
    BOUND_CAMERA_PROPERTIES_CHANGED = carb.events.type_from_string(
        "omni.kit.collaboration.presence_layer@bound_camera_properties"
    )

    # Emitted when the bound camera of peer user is resynced. This is the same as prim resync of USD.
    BOUND_CAMERA_RESYNCED = carb.events.type_from_string(
        "omni.kit.collaboration.presence_layer@bound_camera_resynced"
    )


class PresenceLayerEventPayload:
    def __init__(self, event: carb.events.IEvent) -> None:
        carb_dict = carb.dictionary.get_dictionary()
        if event.type and event.type in iter(PresenceLayerEventType):
            self.event_type = PresenceLayerEventType(event.type)
            if self.event_type == PresenceLayerEventType.BOUND_CAMERA_PROPERTIES_CHANGED:
                self.__changed_users = carb_dict.get_dict_copy(event.payload)
            elif EVENT_PAYLOAD_KEY in event.payload:
                self.__changed_users = {}.fromkeys(event.payload[EVENT_PAYLOAD_KEY])
            else:
                self.__changed_users = {}
        else:
            self.event_type = None
            self.__changed_users = {}

    @property
    def changed_user_ids(self) -> List[str]:
        return self.__changed_users.keys()

    def get_changed_camera_properties(self, user_id: str) -> Set[str]:
        """Gets the changed properties of bound builtin camera if event_type is BOUND_CAMERA_PROPERTIES_CHANGED."""

        return self.__changed_users.get(user_id, set())

    def __str__(self):
        return f"Event Type: {str(self.event_type)}, Changes: {self.__changed_users}"


def get_presence_layer_event_payload(event: carb.events.IEvent) -> PresenceLayerEventPayload:
    try:
        return PresenceLayerEventPayload(event)
    except Exception as e:
        carb.log_error(f"Failed to convert event: {str(e)}")
        return None
