from gi.repository import GLib, GObject, Gtk


@Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/revealer_notification.ui")
class RevealerNotification(Gtk.Revealer):
    __gtype_name__ = "RevealerNotification"

    _spinner = Gtk.Template.Child()
    _label = Gtk.Template.Child()

    def __init__(self):
        super().__init__()

        self.__callback = None
        self.__default_duration = self.get_transition_duration()

        self.connect("notify::child-revealed", self.__callback_wrapper)

    def show(
        self,
        text: str,
        show_spinner: bool = True,
        immediate: bool = False,
        callback=None,
    ) -> None:
        """Show the notification

        :param str text: The text to display
        :param bool show_spinner: Whether to show a spinner
        :param bool immediate: Whether to show immediately or with normal transition
        :param callback: Function to call when the notification is fully revealed. If the
            notification reveal is disrupted during normal operation the callback will still be
            called, however this excludes eg. the app shutting down.
        """
        self._label.set_text(text)
        self.set_transition_duration(0 if immediate else self.__default_duration)
        self.__ensure_prev_callback_called()
        if callback:
            self.__callback = callback
            # Handle case where child-revealed doesn't notify
            if immediate:
                GLib.idle_add(self.__run_and_clear_any_callback)
        self._spinner.set_visible(show_spinner)
        if show_spinner:
            self._spinner.start()
        self.set_reveal_child(True)

    def hide(self, immediate: bool = False) -> None:
        """Hide the notification.

        :param bool immediate: Whether to hide immediately or with normal transition
        """
        self.set_transition_duration(0 if immediate else self.__default_duration)
        self.set_reveal_child(False)
        self.__ensure_prev_callback_called()

    def __callback_wrapper(self, _obj: GObject.Object, _value: GObject.ParamSpec) -> None:
        if self.get_child_revealed():
            self.__run_and_clear_any_callback()
        else:
            if self._spinner.props.spinning:
                self._spinner.stop()

    def __run_and_clear_any_callback(self) -> None:
        if self.__callback is not None:
            callback = self.__callback
            self.__callback = None
            callback()

    def __ensure_prev_callback_called(self) -> None:
        if self.__callback is not None:
            self.__callback()
        self.__callback = None
