"""
Components/ScreenManager
========================

.. versionadded:: 1.0.0

:class:`~kivy.uix.screenmanager.ScreenManager` class equivalent.
If you want to use Hero animations you need to use
:class:`~kivymd.uix.screenmanager.MDScreenManager` not
:class:`~kivy.uix.screenmanager.ScreenManager` class.

Transition
----------

:class:`~kivymd.uix.screenmanager.MDScreenManager` class supports the following
transitions:

- :class:`~kivymd.uix.transition.MDFadeSlideTransition`
- :class:`~kivymd.uix.transition.MDSlideTransition`
- :class:`~kivymd.uix.transition.MDSwapTransition`

You need to use the :class:`~kivymd.uix.screenmanager.MDScreenManager` class
when you want to use hero animations on your screens. If you don't need hero
animation use the :class:`~kivy.uix.screenmanager.ScreenManager` class.
"""

from kivy import Logger
from kivy.clock import Clock
from kivy.properties import ListProperty, StringProperty
from kivy.uix.screenmanager import ScreenManager

from kivymd.theming import ThemableBehavior
from kivymd.uix import MDAdaptiveWidget
from kivymd.uix.behaviors import DeclarativeBehavior, BackgroundColorBehavior
from kivymd.uix.hero import MDHeroFrom


class MDScreenManager(
    DeclarativeBehavior,
    ThemableBehavior,
    BackgroundColorBehavior,
    ScreenManager,
    MDAdaptiveWidget,
):
    """
    Screen manager. This is the main class that will control your
    :class:`~kivymd.uix.screen.MDScreen` stack and memory.

    For more information, see in the
    :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and
    :class:`~kivymd.theming.ThemableBehavior` and
    :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and
    :class:`~kivy.uix.screenmanager.ScreenManager` and
    :class:`~kivymd.uix.MDAdaptiveWidget`
    classes documentation.
    """

    current_hero = StringProperty(None, deprecated=True)
    """
    The name of the current tag for the :class:`~kivymd.uix.hero.MDHeroFrom`
    and :class:`~kivymd.uix.hero.MDHeroTo` objects that will be animated when
    animating the transition between screens.

    .. deprecated:: 1.1.0
        Use :attr:`current_heroes` attribute instead.

    See the `Hero <https://kivymd.readthedocs.io/en/latest/components/hero/>`_
    module documentation for more information about creating and using Hero
    animations.

    :attr:`current_hero` is an :class:`~kivy.properties.StringProperty`
    and defaults to `None`.
    """

    current_heroes = ListProperty()
    """
    A list of names (tags) of heroes that need to be animated when moving
    to the next screen.

    .. versionadded:: 1.1.0

    :attr:`current_heroes` is an :class:`~kivy.properties.ListProperty`
    and defaults to `[]`.
    """

    # Collection of `MDHeroFrom` objects on all screens of the current
    # screen manager.
    _heroes_data = ListProperty()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        Clock.schedule_once(self.check_transition)

    def check_transition(self, *args) -> None:
        """Sets the default type transition."""

        from kivymd.uix.transition.transition import MDTransitionBase

        if not issubclass(self.transition.__class__, MDTransitionBase):
            from kivymd.uix.transition import MDSlideTransition

            self.transition = MDSlideTransition()

    def get_hero_from_widget(self) -> list:
        """
        Get a list of :class:`~kivymd.uix.hero.MDHeroFrom` objects according
        to the tag names specified in the :attr:`~current_heroes` list.
        """

        hero_from_widget = []

        for name_hero in self.current_heroes:
            for hero_widget in self._heroes_data:
                if isinstance(hero_widget, MDHeroFrom) or issubclass(
                    hero_widget.__class__, MDHeroFrom
                ):
                    if hero_widget.tag == name_hero:
                        hero_from_widget.append(hero_widget)

        return hero_from_widget

    def on_current_hero(self, instance, value: str) -> None:
        """
        Fired when the value of the :attr:`current_hero` attribute changes.
        """

        Logger.warning(
            "KivyMD: "
            "`kivymd/uix/screenmanager.MDScreenManager.current_hero` "
            "attribute is deprecated. "
            "Use `kivymd/uix/screenmanager.MDScreenManager.current_heroes` "
            "attribute instead."
        )
        if value:
            self.current_heroes = [value]
        else:
            self.current_heroes = []

    def add_widget(self, widget, *args, **kwargs):
        super().add_widget(widget, *args, **kwargs)
        Clock.schedule_once(lambda x: self._create_heroes_data(widget))

    # TODO: Add a method to delete an object from the arrt:`_heroes_data`
    #  collection when deleting an object using the `remove_widget` method.

    def _create_heroes_data(self, widget):
        def find_hero_widget(child_widget):
            widget_hero = None

            for w in child_widget.children:
                if isinstance(w, MDHeroFrom) or issubclass(
                    w.__class__, MDHeroFrom
                ):
                    self._heroes_data.append(w)
                find_hero_widget(w)

            return widget_hero

        for child in widget.children:
            if isinstance(child, MDHeroFrom) or issubclass(
                child.__class__, MDHeroFrom
            ):
                self._heroes_data.append(child)
            else:
                find_hero_widget(child)
