"""
Components/Dialog
=================

.. seealso::

    `Material Design spec, Dialogs <https://m3.material.io/components/dialogs/overview>`_


.. rubric:: Dialogs provide important prompts in a user flow.

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-preview.png
    :align: center

- Use dialogs to make sure users act on information
- Two types: basic and full-screen (full-screen not provided in KivyMD)
- Should be dedicated to completing a single task
- Can also display information relevant to the task
- Commonly used to confirm high-risk actions like deleting progress

Anatomy
=======

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-anatomy.png
    :align: center

Example
=======

.. code-block:: python

    from kivy.lang import Builder
    from kivy.uix.widget import Widget

    from kivymd.app import MDApp
    from kivymd.uix.button import MDButton, MDButtonText
    from kivymd.uix.dialog import (
        MDDialog,
        MDDialogIcon,
        MDDialogHeadlineText,
        MDDialogSupportingText,
        MDDialogButtonContainer,
        MDDialogContentContainer,
    )
    from kivymd.uix.divider import MDDivider
    from kivymd.uix.list import (
        MDListItem,
        MDListItemLeadingIcon,
        MDListItemSupportingText,
    )

    KV = '''
    MDScreen:
        md_bg_color: self.theme_cls.backgroundColor

        MDButton:
            pos_hint: {'center_x': .5, 'center_y': .5}
            on_release: app.show_alert_dialog()

            MDButtonText:
                text: "Show dialog"
    '''


    class Example(MDApp):
        def build(self):
            return Builder.load_string(KV)

        def show_alert_dialog(self):
            MDDialog(
                # ----------------------------Icon-----------------------------
                MDDialogIcon(
                    icon="refresh",
                ),
                # -----------------------Headline text-------------------------
                MDDialogHeadlineText(
                    text="Reset settings?",
                ),
                # -----------------------Supporting text-----------------------
                MDDialogSupportingText(
                    text="This will reset your app preferences back to their "
                    "default settings. The following accounts will also "
                    "be signed out:",
                ),
                # -----------------------Custom content------------------------
                MDDialogContentContainer(
                    MDDivider(),
                    MDListItem(
                        MDListItemLeadingIcon(
                            icon="gmail",
                        ),
                        MDListItemSupportingText(
                            text="KivyMD-library@yandex.com",
                        ),
                        theme_bg_color="Custom",
                        md_bg_color=self.theme_cls.transparentColor,
                    ),
                    MDListItem(
                        MDListItemLeadingIcon(
                            icon="gmail",
                        ),
                        MDListItemSupportingText(
                            text="kivydevelopment@gmail.com",
                        ),
                        theme_bg_color="Custom",
                        md_bg_color=self.theme_cls.transparentColor,
                    ),
                    MDDivider(),
                    orientation="vertical",
                ),
                # ---------------------Button container------------------------
                MDDialogButtonContainer(
                    Widget(),
                    MDButton(
                        MDButtonText(text="Cancel"),
                        style="text",
                    ),
                    MDButton(
                        MDButtonText(text="Accept"),
                        style="text",
                    ),
                    spacing="8dp",
                ),
                # -------------------------------------------------------------
            ).open()


    Example().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-example.gif
    :align: center

.. warning:: Do not try to use the MDDialog widget in KV files.

API break
=========

1.2.0 version
-------------

.. code-block:: python

    from kivy.uix.widget import Widget

    from kivymd.app import MDApp
    from kivymd.uix.button import MDFlatButton
    from kivymd.uix.dialog import MDDialog


    class Example(MDApp):
        def build(self):
            return Widget()

        def on_start(self):
            MDDialog(
                title="Discard draft?",
                buttons=[
                    MDFlatButton(
                        text="CANCEL",
                        theme_text_color="Custom",
                        text_color=self.theme_cls.primary_color,
                    ),
                    MDFlatButton(
                        text="DISCARD",
                        theme_text_color="Custom",
                        text_color=self.theme_cls.primary_color,
                    ),
                ],
            ).open()


    Example().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-api-break-1-2-0.png
    :align: center

.. code-block:: python

    from kivy.uix.widget import Widget

    from kivymd.app import MDApp
    from kivymd.uix.button import MDFlatButton
    from kivymd.uix.dialog import MDDialog


    class Example(MDApp):
        def build(self):
            return Widget()

        def on_start(self):
            MDDialog(
                title="Discard draft?",
                text="This will reset your device to its default factory settings.",
                buttons=[
                    MDFlatButton(
                        text="CANCEL",
                        theme_text_color="Custom",
                        text_color=self.theme_cls.primary_color,
                    ),
                    MDFlatButton(
                        text="DISCARD",
                        theme_text_color="Custom",
                        text_color=self.theme_cls.primary_color,
                    ),
                ],
            ).open()


    Example().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/2-dialog-api-break-1-2-0.png
    :align: center

.. code-block:: python

    from kivy.lang import Builder
    from kivy.properties import StringProperty
    from kivy.uix.widget import Widget

    from kivymd import images_path
    from kivymd.app import MDApp
    from kivymd.uix.dialog import MDDialog
    from kivymd.uix.list import OneLineAvatarListItem

    KV = '''
    <Item>

        ImageLeftWidget:
            source: root.source
    '''


    class Item(OneLineAvatarListItem):
        divider = None
        source = StringProperty()


    class Example(MDApp):
        def build(self):
            Builder.load_string(KV)
            return Widget()

        def on_start(self):
            MDDialog(
                title="Set backup account",
                type="simple",
                items=[
                    Item(text="user01@gmail.com", source=f"{images_path}/logo/kivymd-icon-128.png"),
                    Item(text="user02@gmail.com", source="data/logo/kivy-icon-128.png"),
                ],
            ).open()


    Example().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/3-dialog-api-break-1-2-0.png
    :align: center

2.2.0 version
-------------

.. code-block:: python

    from kivy.uix.widget import Widget

    from kivymd.uix.widget import MDWidget
    from kivymd.app import MDApp
    from kivymd.uix.button import MDButton, MDButtonText
    from kivymd.uix.dialog import MDDialog, MDDialogHeadlineText, MDDialogButtonContainer


    class Example(MDApp):
        def build(self):
            return MDWidget(md_bg_color=self.theme_cls.backgroundColor)

        def on_start(self):
            MDDialog(
                MDDialogHeadlineText(
                    text="Discard draft?",
                    halign="left",
                ),
                MDDialogButtonContainer(
                    Widget(),
                    MDButton(
                        MDButtonText(text="Cancel"),
                        style="text",
                    ),
                    MDButton(
                        MDButtonText(text="Discard"),
                        style="text",
                    ),
                    spacing="8dp",
                ),
            ).open()


    Example().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-api-break-2-2-0.png
    :align: center

.. code-block:: python

    from kivy.uix.widget import Widget

    from kivymd.uix.widget import MDWidget
    from kivymd.app import MDApp
    from kivymd.uix.button import MDButton, MDButtonText
    from kivymd.uix.dialog import MDDialog, MDDialogHeadlineText, MDDialogButtonContainer


    class Example(MDApp):
        def build(self):
            return MDWidget(md_bg_color=self.theme_cls.backgroundColor)

        def on_start(self):
            MDDialog(
                MDDialogHeadlineText(
                    text="Discard draft?",
                    halign="left",
                ),
                MDDialogSupportingText(
                    text="This will reset your device to its default factory settings.",
                    halign="left",
                ),
                MDDialogButtonContainer(
                    Widget(),
                    MDButton(
                        MDButtonText(text="Cancel"),
                        style="text",
                    ),
                    MDButton(
                        MDButtonText(text="Discard"),
                        style="text",
                    ),
                    spacing="8dp",
                ),
            ).open()


    Example().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/2-dialog-api-break-2-2-0.png
    :align: center

.. code-block:: python

    from kivymd import images_path
    from kivymd.uix.widget import MDWidget
    from kivymd.app import MDApp
    from kivymd.uix.dialog import (
        MDDialog,
        MDDialogHeadlineText,
        MDDialogContentContainer,
    )
    from kivymd.uix.list import (
        MDListItem,
        MDListItemLeadingAvatar,
        MDListItemSupportingText,
    )


    class Example(MDApp):
        def build(self):
            return MDWidget(md_bg_color=self.theme_cls.backgroundColor)

        def on_start(self):
            MDDialog(
                MDDialogHeadlineText(
                    text="Set backup account",
                    halign="left",
                ),
                MDDialogContentContainer(
                    MDListItem(
                        MDListItemLeadingAvatar(
                            source=f"{images_path}/logo/kivymd-icon-128.png",
                        ),
                        MDListItemSupportingText(
                            text="user01@gmail.com",
                        ),
                        theme_bg_color="Custom",
                        md_bg_color=self.theme_cls.transparentColor,
                    ),
                    MDListItem(
                        MDListItemLeadingAvatar(
                            source="data/logo/kivy-icon-128.png",
                        ),
                        MDListItemSupportingText(
                            text="user01@gmail.com",
                        ),
                        theme_bg_color="Custom",
                        md_bg_color=self.theme_cls.transparentColor,
                    ),
                    orientation="vertical",
                ),
            ).open()


    Example().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/3-dialog-api-break-2-2-0.png
    :align: center

"""

__all__ = [
    "MDDialog",
    "MDDialogIcon",
    "MDDialogHeadlineText",
    "MDDialogSupportingText",
    "MDDialogContentContainer",
    "MDDialogButtonContainer",
]

import os

from kivy.core.window import Window
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import (
    VariableListProperty,
    NumericProperty,
    ColorProperty,
    ObjectProperty,
    BooleanProperty,
)
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget

from kivymd.uix.card import MDCard
from kivymd.uix.label import MDIcon, MDLabel
from kivymd import uix_path
from kivymd.material_resources import DEVICE_TYPE
from kivymd.uix.behaviors import MotionDialogBehavior, DeclarativeBehavior

with open(
    os.path.join(uix_path, "dialog", "dialog.kv"), encoding="utf-8"
) as kv_file:
    Builder.load_string(kv_file.read())


class MDDialog(MDCard, MotionDialogBehavior):
    """
    Dialog class.

    For more information, see in the
    :class:`~kivymd.uix.card.card.MDCard` and
    :class:`~kivymd.uix.behaviors.motion_behavior.MotionDialogBehavior`
    classes documentation.

    :Events:
        `on_pre_open`:
            Fired before the MDDialog is opened. When this event is fired
            MDDialog is not yet added to window.
        `on_open`:
            Fired when the MDDialog is opened.
        `on_pre_dismiss`:
            Fired before the MDDialog is closed.
        `on_dismiss`:
            Fired when the MDDialog is closed. If the callback returns True,
            the dismiss will be canceled.
    """

    width_offset = NumericProperty(dp(48))
    """
    Dialog offset from device width.

    :attr:`width_offset` is an :class:`~kivy.properties.NumericProperty`
    and defaults to `dp(48)`.
    """

    radius = VariableListProperty(dp(28), lenght=4)
    """
    Dialog corners rounding value.

    :attr:`radius` is an :class:`~kivy.properties.VariableListProperty`
    and defaults to `[dp(28), dp(28), dp(28), dp(28)]`.
    """

    scrim_color = ColorProperty([0, 0, 0, 0.5])
    """
    Color for scrim in (r, g, b, a) or string format.

    :attr:`scrim_color` is a :class:`~kivy.properties.ColorProperty`
    and defaults to `[0, 0, 0, 0.5]`.
    """

    auto_dismiss = BooleanProperty(True)
    """
    This property determines if the dialog is automatically
    dismissed when the user clicks outside it.

    ..versionadded:: 2.0.0

    :attr:`auto_dismiss` is a :class:`~kivy.properties.BooleanProperty` and
    defaults to True.
    """

    _scrim = ObjectProperty()  # kivymd.uix.dialog.dialog.MDDialogScrim object
    _is_open = False  # is the dialog currently open or closed.

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.register_event_type("on_open")
        self.register_event_type("on_pre_open")
        self.register_event_type("on_dismiss")
        self.register_event_type("on_pre_dismiss")
        self.opacity = 0
        Window.bind(on_resize=self.update_width)

    def update_width(self, *args) -> None:
        self.size_hint_max_x = max(
            self.width_offset,
            min(
                dp(560) if DEVICE_TYPE != "mobile" else dp(280),
                Window.width - self.width_offset,
            ),
        )

    def add_widget(self, widget, *args, **kwargs):
        if isinstance(widget, MDDialogIcon):
            self.ids.icon_container.add_widget(widget)
        elif isinstance(widget, MDDialogHeadlineText):
            self.ids.headline_container.add_widget(widget)
        elif isinstance(widget, MDDialogSupportingText):
            self.ids.supporting_text_container.add_widget(widget)
        elif isinstance(widget, MDDialogContentContainer):
            self.ids.content_container.add_widget(widget)
        elif isinstance(widget, MDDialogButtonContainer):
            self.ids.button_container.add_widget(widget)
        else:
            return super().add_widget(widget)

    def open(self) -> None:
        """Show the dialog."""

        if self._is_open:
            return

        self.dispatch("on_pre_open")
        self._is_open = True

        if not self._scrim:
            self._scrim = MDDialogScrim(color=self.scrim_color)

        Window.add_widget(self._scrim)
        Window.add_widget(self)
        super().on_open()
        self.dispatch("on_open")

    def on_pre_open(self, *args) -> None:
        """Fired when a dialog pre opened."""

    def on_open(self, *args) -> None:
        """Fired when a dialog opened."""

    def on_dismiss(self, *args) -> None:
        """Fired when a dialog dismiss."""

    def on_pre_dismiss(self, *args) -> None:
        """Fired when a dialog pre-dismiss."""

    def on_touch_down(self, touch):
        if not self.collide_point(*touch.pos) and self.auto_dismiss:
            self.dismiss()
            return True
        super().on_touch_down(touch)
        return True

    def dismiss(self, *args) -> None:
        """Closes the dialog."""

        self.dispatch("on_pre_dismiss")
        super().on_dismiss()
        self._is_open = False
        self.dispatch("on_dismiss")


class MDDialogIcon(MDIcon):
    """
    The class implements an icon.

    For more information, see in the
    :class:`~kivymd.uix.label.label.MDIcon` class documentation.
    """


class MDDialogHeadlineText(MDLabel):
    """
    The class implements the headline text.

    For more information, see in the
    :class:`~kivymd.uix.label.label.MDLabel` class documentation.
    """


class MDDialogSupportingText(MDLabel):
    """
    The class implements the supporting text.

    For more information, see in the
    :class:`~kivymd.uix.label.label.MDLabel` class documentation.
    """


class MDDialogContentContainer(DeclarativeBehavior, BoxLayout):
    """
    The class implements the container for custom widgets.

    For more information, see in the
    :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and
    :class:`~kivy.uix.boxlayout.BoxLayout` classes documentation.
    """


class MDDialogButtonContainer(DeclarativeBehavior, BoxLayout):
    """
    The class implements a container for placing dialog buttons.

    For more information, see in the
    :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and
    :class:`~kivy.uix.boxlayout.BoxLayout` classes documentation.
    """


class MDDialogScrim(Widget):
    color = ColorProperty(None)
    alpha = NumericProperty(0)
