"""
二次元形式のデータを表示するための 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 Any

from datagrid.header_item import HeaderItem
from datagrid.row_item import RowItem
from datagrid.selectable_recycle_box_layout import SelectableRecycleBoxLayout
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import (
    ListProperty,
    NumericProperty,
    ObjectProperty,
    StringProperty,
)
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview import RecycleView

Builder.load_string("""
<DataGrid>:
    _recycle_view: recycle_view
    _box_layout: box_layout
    _header_anchor: header_anchor
    selected_row: box_layout.selected_row

    orientation: 'vertical'

    AnchorLayout:
        id: header_anchor
        height: 0
        size_hint_y: None
    AnchorLayout:
        RecycleView:
            id: recycle_view
            size_hint_y: 1.0
            scroll_type: ['bars', 'content']
            bar_width: dp(16)
            scroll_wheel_distance: dp(50)
            canvas.before:
                Color:
                    rgba: (64/255, 64/255, 64/255, 1.0)
                Rectangle:
                    pos: self.pos
                    size: self.size
            SelectableRecycleBoxLayout:
                id: box_layout
                orientation: 'vertical'
                default_size: 0, root.row_height
                default_size_hint: 1.0, None
                height: self.minimum_height
                size_hint_y: None
                padding: 0, 0, 0, root.bottom_padding
""")


class DataGrid(BoxLayout):
    """二次元形式のデータを表示するための Kivy 用自作ウィジェットを定義したクラス"""

    selected_row: RowItem = ObjectProperty(None)
    """選択された行アイテム"""

    viewclass: str = StringProperty("")
    """レコード行のレイアウトを定義したクラス名"""

    data: list[dict[str, Any]] = ListProperty([])
    """表示するデータのリスト"""

    header_item: HeaderItem = ObjectProperty(None)
    """ヘッダー行のレイアウトを定義したクラス"""

    header_height: float = NumericProperty(dp(30))
    """ヘッダー行の高さ"""

    row_height: float = NumericProperty(dp(30))
    """レコード行の高さ"""

    bottom_padding: float = NumericProperty(dp(30))
    """データグリッドの下部のパディング"""

    _recycle_view: RecycleView = ObjectProperty(None)
    """RecycleView のインスタンス"""

    _header_anchor: AnchorLayout = ObjectProperty(None)
    """動的にヘッダーを挿入するためのアンカー"""

    _box_layout: SelectableRecycleBoxLayout = ObjectProperty(None)
    """選択可能な RecycleBoxLayout のインスタンス"""

    def __init__(self, **kwargs):
        """二次元形式のデータを表示するための Kivy 用自作ウィジェットのインスタンスを作成して返す。

        Args:
            **kwargs: キーワード引数。
        """

        super().__init__(**kwargs)

        self.bind(viewclass=self._set_viewclass)  # type: ignore
        self.bind(data=self._set_data)  # type: ignore
        self.bind(header_item=self._set_header)  # type: ignore
        self.bind(header_height=self._set_header)  # type: ignore
        self.bind(row_height=self._set_row_height)  # type: ignore
        self.bind(bottom_padding=self._set_bottom_padding)  # type: ignore

    def _set_viewclass(self, instance, value) -> None:
        """表示するアイテムのクラスを設定する。"""

        self._recycle_view.viewclass = self.viewclass

    def _set_header(self, instance, value) -> None:
        """ヘッダーを挿入する。"""

        if self.header_item:
            self._header_anchor.height = self.header_height
            self._header_anchor.size_hint_y = None
            self._header_anchor.clear_widgets()
            self._header_anchor.add_widget(self.header_item)
        else:
            self._header_anchor.height = 0
            self._header_anchor.size_hint_y = None
            self._header_anchor.clear_widgets()

    def _set_data(self, instance, value) -> None:
        """表示するデータを設定する。"""

        self._recycle_view.data = self.data

    def _set_row_height(self, instance, value: float) -> None:
        """レコード行の高さを設定する。

        Args:
            value (float): レコード行の高さ。
        """

        self._box_layout.default_size = (0, value)
        self._box_layout.default_size_hint = (1.0, None)
        self._box_layout.height = self._box_layout.minimum_height

    def _set_bottom_padding(self, instance, value: float) -> None:
        """レコード行の下部のパディングを設定する。

        Args:
            value (float): 下部のパディングの値。
        """

        self._box_layout.padding = (0, 0, 0, value)

    def scroll_to_bottom(self) -> None:
        """データグリッドを一番下までスクロールする。"""

        self._recycle_view.scroll_y = 0.0

    def scroll_to_top(self) -> None:
        """データグリッドを一番上までスクロールする。"""

        self._recycle_view.scroll_y = 1.0
