from typing import Optional, Callable

import omni.ui as ui


class OptionItem(ui.AbstractItem):
    """
    Represent an item for OptionsMenu.

    Args:
        name (str): Item name.

    Keyword args:
        text (str): Item text to show in menu item. Default None means using name.
        default (bool): Default item value. Default False.
        on_value_changed_fn (Callable[[bool], None]): Callback when item value changed.
    """
    def __init__(self, name: Optional[str], text: Optional[str] = None, default: bool = False, on_value_changed_fn: Callable[[bool], None] = None):
        self.name = name
        self.text = text or name
        self.default = default
        self.model = ui.SimpleBoolModel(default)
        if on_value_changed_fn:
            self.__on_value_changed_fn = on_value_changed_fn

            def __on_value_changed(model: ui.SimpleBoolModel):
                self.__on_value_changed_fn(model.as_bool)
            
            self.__sub = self.model.subscribe_value_changed_fn(__on_value_changed)

        super().__init__()

    def destroy(self):
        self.__sub = None

    @property
    def value(self) -> bool:
        """
        Item current value.
        """
        return self.model.as_bool
    
    @value.setter
    def value(self, new_value: bool) -> None:
        self.model.set_value(new_value)

    @property
    def dirty(self) -> bool:
        """
        Flag of item value changed.
        """
        return self.model.as_bool != self.default

    def reset(self) -> None:
        """
        Reset item value to default.
        """
        self.model.set_value(self.default)


class OptionSeparator(OptionItem):
    """
    A simple option item represents a separator in menu item.
    """
    def __init__(self):
        super().__init__(None)