import carb

from typing import List, Dict
from .._omni_kit_usd_layers import LayerEventType


class LayerEventPayload:
    def __init__(self, event: carb.events.IEvent) -> None:
        # It is non-empty if event_type is INFO_CHANGED, for which key is the layer identifier,
        # and value is the set of strings that represent the info tokens.
        self.layer_info_data: Dict[str, List[str]] = {}

        # It's non-empty if event_type is DIRTY_STATE_CHANGED, OUTDATE_STATE_CHANGED
        # LOCK_STATE_CHANGED, MUTENESS_STATE_CHANGED, SPECS_LOCKING_CHANGED, or
        # LIVE_SESSION_STATE_CHANGED,
        # which will include all influenced layer identifiers or spec paths.
        self.identifiers_or_spec_paths: List[str] = []

        # It's non-empty if event_type is PRIM_SPECS_CHANGED or SPECS_LINKING_CHANGED. For which, the key is the layer identifier,
        # and value is the list of strings that represent spec paths.
        self.layer_spec_paths: Dict[str, List[str]] = {}

        # It's non-empty if event_type is LIVE_SESSION_USER_JOINED or LIVE_SESSION_USER_LEFT
        self.user_name = None

        # It's non-empty if event_type is LIVE_SESSION_USER_JOINED or LIVE_SESSION_USER_LEFT
        self.user_id = None

        # It's non-empty if event_type is LIVE_SESSION_MERGE_STARTED or LIVE_SESSION_MERGE_ENDED
        self.layer_identifier = None

        # It means if the merge of live session is successful or not.
        self.success = True

        self.event_type = LayerEventType(event.type)
        if event.type == int(LayerEventType.INFO_CHANGED):
            layer_identifier = event.payload["layer_identifier"]
            info_data = event.payload["val"]
            self.layer_info_data[layer_identifier] = list(info_data)
        elif (
            event.type == int(LayerEventType.DIRTY_STATE_CHANGED)
            or event.type == int(LayerEventType.OUTDATE_STATE_CHANGED)
            or event.type == int(LayerEventType.MUTENESS_STATE_CHANGED)
            or event.type == int(LayerEventType.LOCK_STATE_CHANGED)
            or event.type == int(LayerEventType.SPECS_LOCKING_CHANGED)
        ):
            self.identifiers_or_spec_paths = list(event.payload["val"])
        elif event.type == int(LayerEventType.PRIM_SPECS_CHANGED):
            layer_identifier = event.payload["layer_identifier"]
            prim_specs = event.payload["val"]
            self.layer_spec_paths[layer_identifier] = list(prim_specs)
        elif event.type == int(LayerEventType.SPECS_LINKING_CHANGED):
            for _, value in event.payload["val"].items():
                layer_identifier = value.get("key", "")
                spec_paths = value.get("value", [])
                if layer_identifier and spec_paths:
                    self.layer_spec_paths[layer_identifier] = spec_paths
        elif (
            event.type == int(LayerEventType.LIVE_SESSION_USER_JOINED)
            or event.type == int(LayerEventType.LIVE_SESSION_USER_LEFT)
        ):
            self.user_name = event.payload["user_name"]
            self.user_id = event.payload["user_id"]
        elif event.type == int(LayerEventType.LIVE_SESSION_STATE_CHANGED):
            layer_identifiers = list(event.payload["val"])
            if layer_identifiers:
                self.identifiers_or_spec_paths = layer_identifiers
        elif event.type == int(LayerEventType.LIVE_SESSION_LIST_CHANGED):
            layer_identifier = event.payload["val"]
            if layer_identifier:
                self.identifiers_or_spec_paths = [layer_identifier]
        elif (
            event.type == int(LayerEventType.LIVE_SESSION_MERGE_STARTED) or
            event.type == int(LayerEventType.LIVE_SESSION_MERGE_ENDED)
        ):
            self.layer_identifier = event.payload["layer_identifier"]
            self.success = event.payload["success"]


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


def post_notification(message: str, info=True):
    try:
        import omni.kit.notification_manager as nm
        if info:
            status = nm.NotificationStatus.INFO
        else:
            status = nm.NotificationStatus.WARNING
        nm.post_notification(message, status=status)
    except Exception:
        pass
