"""
メイン画面を定義したクラス。

    「ちょこっと時間計算」
    Copyright (c) 2025 toshifumi tsutsui
    Released under the MIT license
    https://wpandora8.net/the_mit_license.html
"""

from datetime import datetime, timedelta
from typing import Callable

from kivy.clock import Clock
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.screenmanager import Screen
from kivy.uix.textinput import TextInput
from kivy.uix.widget import Widget

Builder.load_string("""
<MainScreen>:
    BoxLayout:
        orientation: 'vertical'
        size: root.size
        BoxLayout:
            size_hint_y: 0.3
            orientation: 'horizontal'
            padding: sp(8)
            spacing: sp(4)
            NumericTextInput:
                id: base_year_textinput
                size_hint_x: 0.13
                on_text_validate: root._move_focus(self)
                on_focus: root._on_focus(self)
            Label:
                size_hint_x: 0.04
                text: '年'
                text_size: self.size
                halign: 'left'
                valign: 'middle'
            NumericTextInput:
                id: base_month_textinput
                size_hint_x: 0.1
                on_text_validate: root._move_focus(self)
                on_focus: root._on_focus(self)
            Label:
                size_hint_x: 0.04
                text: '月'
                text_size: self.size
                halign: 'left'
                valign: 'middle'
            NumericTextInput:
                id: base_day_textinput
                size_hint_x: 0.1
                on_text_validate: root._move_focus(self)
                on_focus: root._on_focus(self)
            Label:
                size_hint_x: 0.04
                text: '日'
                text_size: self.size
                halign: 'left'
                valign: 'middle'
            NumericTextInput:
                id: base_hour_textinput
                size_hint_x: 0.1
                on_text_validate: root._move_focus(self)
                on_focus: root._on_focus(self)
            Label:
                size_hint_x: 0.04
                text: '時'
                text_size: self.size
                halign: 'left'
                valign: 'middle'
            NumericTextInput:
                id: base_minute_textinput
                size_hint_x: 0.1
                on_text_validate: root._move_focus(self)
                on_focus: root._on_focus(self)
            Label:
                size_hint_x: 0.04
                text: '分'
                text_size: self.size
                halign: 'left'
                valign: 'middle'
            NumericTextInput:
                id: base_second_textinput
                size_hint_x: 0.1
                on_text_validate: root._move_focus(self)
                on_focus: root._on_focus(self)
            Label:
                size_hint_x: 0.04
                text: '秒'
                text_size: self.size
                halign: 'left'
                valign: 'middle'
            Button:
                id: now_button
                text: '現在'
                size_hint_x: 0.13
                on_press: root._set_current_datetime_to_base_inputs()
        BoxLayout:
            size_hint_y: 0.3
            orientation: 'horizontal'
            padding: sp(8)
            spacing: sp(4)
            Label:
                size_hint_x: 0.07
                text: 'の'
                text_size: self.size
                halign: 'center'
                valign: 'middle'
            NumericTextInput:
                id: offset_day_textinput
                size_hint_x: 0.15
                on_text_validate: root._move_focus(self)
                on_focus: root._on_focus(self)
            Label:
                size_hint_x: 0.04
                text: '日'
                text_size: self.size
                halign: 'left'
                valign: 'middle'
            NumericTextInput:
                id: offset_hour_textinput
                size_hint_x: 0.15
                on_text_validate: root._move_focus(self)
                on_focus: root._on_focus(self)
            Label:
                size_hint_x: 0.08
                text: '時間'
                text_size: self.size
                halign: 'left'
                valign: 'middle'
            NumericTextInput:
                id: offset_minute_textinput
                size_hint_x: 0.15
                on_text_validate: root._move_focus(self)
                on_focus: root._on_focus(self)
            Label:
                size_hint_x: 0.04
                text: '分'
                text_size: self.size
                halign: 'left'
                valign: 'middle'
            NumericTextInput:
                id: offset_second_textinput
                size_hint_x: 0.15
                on_text_validate: root._move_focus(self)
                on_focus: root._on_focus(self)
            Label:
                size_hint_x: 0.04
                text: '秒'
                text_size: self.size
                halign: 'left'
                valign: 'middle'
            Button:
                id: offset_direction_button
                text: '後'
                size_hint_x: 0.13
                on_press: root._on_offset_direction_button_press()
        BoxLayout:
            size_hint_y: 0.4
            orientation: 'horizontal'
            padding: sp(10)
            spacing: sp(6)
            Button:
                id: foreground_button
                size_hint_x: 0.19
                text: '最前面'
                on_press: root._on_foreground_button_press()
            Label:
                id: result_label
                size_hint_x: 0.58
                color: 0.0, 0.0, 0.0, 1.0
                text_size: self.size
                halign: 'center'
                valign: 'middle'
                canvas.before:
                    Color:
                        rgba: 1.0, 1.0, 1.0, 1.0
                    Rectangle:
                        pos: self.pos
                        size: self.size
            Button:
                id: clear_button
                size_hint_x: 0.13
                text: 'クリア'
                on_press: root._on_clear_button_press()
            ImageButton:
                size_hint_x: 0.1
                on_press: root._on_version_info_button_press()

<NumericTextInput@TextInput>:
    halign: 'center'
    padding: sp(6), sp(4)
    multiline: False
    write_tab: False
    text_validate_unfocus: True

<ImageButton@ButtonBehavior+Image>:
    source: 'image_64.png'
    fit_mode: 'contain'
""")


class MainScreen(Screen):
    """メイン画面を定義したクラス。"""

    def __init__(self, to_version_screen: Callable[[], None], **kwargs) -> None:
        """
        メイン画面のインスタンスを作成して返す。

        Args:
            to_version_screen (Callable[[], None]): バージョン情報画面に遷移するための関数。
        """
        super().__init__(**kwargs)

        self._base_year_textinput: TextInput = self.ids.base_year_textinput
        """基準日時の年を入力する TextInput ウィジェット"""
        self._base_month_textinput: TextInput = self.ids.base_month_textinput
        """基準日時の月を入力する TextInput ウィジェット"""
        self._base_day_textinput: TextInput = self.ids.base_day_textinput
        """基準日時の日を入力する TextInput ウィジェット"""
        self._base_hour_textinput: TextInput = self.ids.base_hour_textinput
        """基準日時の時を入力する TextInput ウィジェット"""
        self._base_minute_textinput: TextInput = self.ids.base_minute_textinput
        """基準日時の分を入力する TextInput ウィジェット"""
        self._base_second_textinput: TextInput = self.ids.base_second_textinput
        """基準日時の秒を入力する TextInput ウィジェット"""
        self._offset_day_textinput: TextInput = self.ids.offset_day_textinput
        """加減算する日数を入力する TextInput ウィジェット"""
        self._offset_hour_textinput: TextInput = self.ids.offset_hour_textinput
        """加減算する時間を入力する TextInput ウィジェット"""
        self._offset_minute_textinput: TextInput = self.ids.offset_minute_textinput
        """加減算する分を入力する TextInput ウィジェット"""
        self._offset_second_textinput: TextInput = self.ids.offset_second_textinput
        """加減算する秒を入力する TextInput ウィジェット"""
        self._offset_direction_button: Button = self.ids.offset_direction_button
        """加減算の方向を切り替える Button ウィジェット"""
        self._result_label: Label = self.ids.result_label
        """計算結果を表示する Label ウィジェット"""

        self._textinputs: list[TextInput] = self._get_textinput_list()
        """すべての TextInput ウィジェットを格納したリスト"""

        self._to_version_screen: Callable[[], None] = to_version_screen
        """バージョン情報画面に遷移するためのコールバック関数"""

        self._is_after: bool = self._offset_direction_button.text == "後"
        """加減算の方向が「後」なら True、「前」なら False"""

        Window.bind(mouse_pos=self._on_mouse_pos)

        self._set_current_datetime_to_base_inputs()

        if Window.always_on_top:
            self.ids.foreground_button.text = "✓最前面"
        else:
            self.ids.foreground_button.text = "最前面"

    def _get_textinput_list(self) -> list[TextInput]:
        """
        すべての TextInput ウィジェットをリストにまとめて返す。

        Returns:
            list[TextInput]: すべての TextInput ウィジェットを格納したリスト。
        """

        return [
            self._base_year_textinput,
            self._base_month_textinput,
            self._base_day_textinput,
            self._base_hour_textinput,
            self._base_minute_textinput,
            self._base_second_textinput,
            self._offset_day_textinput,
            self._offset_hour_textinput,
            self._offset_minute_textinput,
            self._offset_second_textinput,
        ]

    def _on_mouse_pos(self, instance: Widget, pos: tuple[float, float]) -> None:
        """
        マウスの位置が変化したときの処理。

        Args:
            instance (Widget): マウス位置を監視しているウィジェット。
            pos (tuple[float, float]): マウスの新しい位置。
        """

        if not self.get_root_window():
            return

        for ti in self._textinputs:
            if ti.collide_point(*pos):
                Window.set_system_cursor("ibeam")
                return

        Window.set_system_cursor("arrow")

    def _set_current_datetime_to_base_inputs(self) -> None:
        """現在日時を基準日時の入力欄に設定する。"""

        def move_focus(dt: float) -> None:
            self._offset_day_textinput.focus = True

        Clock.schedule_once(move_focus, 0.2)

        now: datetime = datetime.now()
        self._base_year_textinput.text = str(now.year)
        self._base_month_textinput.text = str(now.month)
        self._base_day_textinput.text = str(now.day)
        self._base_hour_textinput.text = str(now.hour)
        self._base_minute_textinput.text = str(now.minute)
        self._base_second_textinput.text = str(now.second)

        self._calculate_result_datetime()

    def _on_offset_direction_button_press(self) -> None:
        """加減算の方向ボタンがクリックされたときの処理。"""

        if self._is_after:
            self._is_after = False
            self._offset_direction_button.text = "前"
        else:
            self._is_after = True
            self._offset_direction_button.text = "後"

        self._calculate_result_datetime()

    def _move_focus(self, instance: TextInput) -> None:
        """
        TextInput で Enter キーが押されたら、フォーカスを次の TextInput に移動する。

        Args:
            instance (TextInput): Enter キーが押された TextInput インスタンス。
        """

        try:
            index: int = self._textinputs.index(instance)
            next_index: int = (index + 1) % len(self._textinputs)
            self._textinputs[next_index].focus = True

        except ValueError:
            pass

    def _on_focus(self, instance: TextInput) -> None:
        """
        TextInput のフォーカスの状態が変更されたときの処理。

        Args:
            instance (TextInput): フォーカスの状態が変更された TextInput インスタンス。
        """

        if instance.focus:
            instance.background_color = (1.0, 1.0, 0.7, 1.0)
            instance.select_all()
        else:
            instance.background_color = (1.0, 1.0, 1.0, 1.0)
            instance.cancel_selection()

            self._calculate_result_datetime()

    def _calculate_result_datetime(self) -> None:
        """計算結果の日時を取得して表示する。"""

        result_datetime: datetime | None = self._get_result_datetime()
        if result_datetime:
            self._result_label.text = (
                f"{result_datetime.year}年"
                f"{result_datetime.month}月"
                f"{result_datetime.day}日"
                f" {result_datetime.hour}時"
                f"{result_datetime.minute}分"
                f"{result_datetime.second}秒"
            )
        else:
            self._result_label.text = ""

    def _get_result_datetime(self) -> datetime | None:
        """
        入力欄の内容に基づいて計算結果の日時を取得して返す。

        Returns:
            datetime | None: 計算結果の日時の datetime インスタンス、無効な入力の場合は None。
        """

        base_datetime: datetime | None = self._get_datetime_from_base_inputs()
        offset_time: timedelta | None = self._get_timedelta_from_offset_inputs()

        if base_datetime is None or offset_time is None:
            return None

        if self._is_after:
            return base_datetime + offset_time
        else:
            return base_datetime - offset_time

    def _get_datetime_from_base_inputs(self) -> datetime | None:
        """
        基準日時の入力欄から datetime を取得して返す。

        Returns:
            datetime | None: 基準日時の datetime インスタンス、無効な入力の場合は None。
        """

        try:
            year: int = int(self._base_year_textinput.text or "0")
            month: int = int(self._base_month_textinput.text or "0")
            day: int = int(self._base_day_textinput.text or "0")
            hour: int = int(self._base_hour_textinput.text or "0")
            minute: int = int(self._base_minute_textinput.text or "0")
            second: int = int(self._base_second_textinput.text or "0")
            return datetime(year, month, day, hour, minute, second)

        except ValueError:
            return None

    def _get_timedelta_from_offset_inputs(self) -> timedelta | None:
        """
        加減算の入力欄から timedelta を取得して返す。

        Returns:
            timedelta | None: 加減算の timedelta インスタンス、または無効な入力の場合は None。
        """

        try:
            days: int = int(self._offset_day_textinput.text or "0")
            hours: int = int(self._offset_hour_textinput.text or "0")
            minutes: int = int(self._offset_minute_textinput.text or "0")
            seconds: int = int(self._offset_second_textinput.text or "0")
            return timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)

        except ValueError:
            return None

    def _on_foreground_button_press(self) -> None:
        """「最前面」ボタンがクリックされたときの処理。"""

        if Window.always_on_top:
            Window.always_on_top = False
            self.ids.foreground_button.text = "最前面"
        else:
            Window.always_on_top = True
            self.ids.foreground_button.text = "✓最前面"

    def _on_clear_button_press(self) -> None:
        """「クリア」ボタンがクリックされたときの処理。"""

        def move_focus(dt: float) -> None:
            self._base_year_textinput.focus = True

        Clock.schedule_once(move_focus, 0.2)

        for ti in self._textinputs:
            ti.text = ""

        self._result_label.text = ""

    def _on_version_info_button_press(self) -> None:
        """「バージョン情報」ボタンがクリックされたときの処理。"""

        self._to_version_screen()

    # def _focus_invalid_textinput(self, instance: TextInput) -> None:
    #     """
    #     入力がエラーになった TextInput にフォーカスを当てる。

    #     Args:
    #         instance (TextInput): フォーカスを当てる TextInput インスタンス。
    #     """

    #     instance.focus = True
    #     instance.background_color = (1.0, 0.7, 0.7, 1.0)

    #     if instance is not self.ids.color_code_textinput:
    #         instance.select_all()
