"""
メッセージを表示するための Kivy 用ダイアログボックス

    Last modified: 2025/06/24

    Copyright (c) 2025 toshifumi tsutsui
    Released under the MIT license
    https://wpandora8.net/the_mit_license.html
"""

from typing import Callable, Literal

import kivy.resources
import my_dialogs.helper as helper
from kivy.core.window import Keyboard, Window
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import ObjectProperty, StringProperty
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.modalview import ModalView

kivy.resources.resource_add_path(helper.get_resource_path("my_dialogs/images"))

Builder.load_string("""
<MsgBoxLayout>:
    size_hint: 0.8, 0.8
    BoxLayout:
        orientation: 'vertical'
        BoxLayout:
            size_hint_y: 1.0-((button_close.height+dp(4))/(root.height*root.size_hint_y))
            orientation: 'horizontal'
            Image:
                id: image_icon
                size_hint_x: 0.2
                source: f"{root.icon}_128.png"
                fit_mode: 'contain'
            BoxLayout:
                size_hint_x: 0.1
            Label:
                size_hint_x: 0.7
                text_size: self.size
                valign: 'middle'
                text: root.message
                line_height: 1.5
        AnchorLayout:
            size_hint_y: (button_close.height+dp(4))/(root.height*root.size_hint_y)
            anchor_y: 'bottom'
            Button:
                id: button_close
                size_hint: 0.4, None
                height: dp(48)
                text: "閉じる"
                on_release: root.button_close_click()
""")


class MessageBox:
    """メッセージボックスを定義したクラス。"""

    def __init__(
        self,
        message: str = "",
        icon: Literal["information", "warning", "error"] = "information",
        callback: Callable | None = None,
        size_hint: tuple[float | None, float | None] = (0.8, 0.5),
        size: tuple[float, float] = (dp(640), dp(480)),
    ) -> None:
        """メッセージボックスのインスタンスを作成して返す。

        Args:
            message (str): 表示するメッセージ。
            icon (Literal[&#39;information&#39;, &#39;warning&#39;, &#39;error&#39;]): アイコンの種類。
            callback (Callable | None, optional): 「閉じる」ボタンがクリックされたときの処理。
            size_hint (tuple[float | None, float | None]): 親ウィンドウに対するダイアログボックスのサイズの比率。
            size (tuple[float, float]): ダイアログボックスのサイズ（size_hint にはそれぞれ None を指定）。
        """

        self._on_close_callback = callback
        self._view: ModalView = ModalView(
            size_hint=size_hint, size=size, auto_dismiss=False
        )
        self._view.add_widget(
            MsgBoxLayout(button_close_click=self._close, message=message, icon=icon)
        )

    def show(self) -> None:
        """MessageBox を表示する。"""

        self._view.open()

    def _close(self) -> None:
        """「閉じる」ボタンがクリックされたとき。"""

        self._view.dismiss()

        if self._on_close_callback is not None:
            self._on_close_callback()


class MsgBoxLayout(AnchorLayout):
    """メッセージボックスのレイアウト。"""

    button_close_click: Callable[[], None] = ObjectProperty(None)
    message: str = StringProperty("")
    icon: str = StringProperty("none")

    def __init__(self, **kwargs) -> None:
        super().__init__(**kwargs)

        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        self._keyboard.bind(on_key_down=self._on_keyboard_down)

    def _keyboard_closed(self):
        """キーボードが閉じられたときに呼び出されるコールバック。"""

        self._keyboard.unbind(on_key_down=self._on_keyboard_down)

    def _on_keyboard_down(
        self,
        keyboard: Keyboard,
        keycode: tuple[int, str],
        text: str,
        modifiers: list[str],
    ) -> None:
        """押下されたアクセスキーにより処理を行う。

        Args:
            keyboard (Keyboard): バインドされた Keyboard のインスタンス。
            keycode (tupl[int, str]): 押されたキーのキーコードと文字の tuple。
            text (str): 押されたキーのテキスト。
            modifiers (list[str]): 同時に押された補助キー名の list。
        """

        if keycode[1].lower() in ("spacebar", "enter", "escape"):
            self._keyboard.unbind(on_key_down=self._on_keyboard_down)
            self.button_close_click()
