"""
セット球情報画面を定義したクラス

    「ロト6 当せん数字予測アプリ」
    Copyright (c) 2025 toshifumi tsutsui
    Released under the MIT license
    https://wpandora8.net/the_mit_license.html
"""

from typing import override

import polars as pl
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen

from datagrid import DataGrid
from shared_vars import SharedVars
from views.datagrid_ball_sets_row import DataGridBallSetsHeader, DataGridBallSetsRow
from views.datagrid_recently_row import DataGridRecentlyHeader, DataGridRecentlyRow

Builder.load_string("""
<BallSetsScreen>:
    AnchorLayout:
        size_hint: 0.8, 0.9
        pos_hint: {'center_x': 0.5, 'center_y': 0.5}
        BoxLayout:
            orientation: 'horizontal'
            spacing: dp(50)
            BoxLayout:
                orientation: 'vertical'
                size_hint_x: 0.6
                Label:
                    text: '各セット球の選出回数'
                    halign: 'center'
                    valign: 'middle'
                    size_hint_y: 0.1
                AnchorLayout:
                    size_hint_y: 0.9
                    anchor_x: 'center'
                    anchor_y: 'top'
                    DataGrid:
                        id: datagrid_ball_sets
                        viewclass: 'DataGridBallSetsRow'
                        height: dp(330)
                        size_hint_y: None
                        bottom_padding: dp(0)

            BoxLayout:
                orientation: 'vertical'
                size_hint_x: 0.4
                Label:
                    text: '最近のセット球の選出状況'
                    halign: 'center'
                    valign: 'middle'
                    size_hint_y: 0.1
                DataGrid:
                    size_hint_y: 0.9
                    id: datagrid_recently
                    viewclass: 'DataGridRecentlyRow'
""")


class BallSetsScreen(Screen):
    """セット球情報画面を定義したクラス"""

    def __init__(self, shared_vars: SharedVars, **kwargs):
        """セット球情報画面のインスタンスを作成して返す。

        Args:
            shared_vars (SharedVars): アプリ内で共有する変数を管理するクラスのインスタンス。
        """

        super().__init__(**kwargs)

        self._shared_vars = shared_vars

        self._datagrid_ball_sets: DataGrid = self.ids.datagrid_ball_sets
        """セット球の選出状況のデータグリッド"""

        self._datagrid_recently: DataGrid = self.ids.datagrid_recently
        """最近のセット球の選出状況のデータグリッド"""

        self._datagrid_ball_sets.header_item = DataGridBallSetsHeader()
        self._datagrid_recently.header_item = DataGridRecentlyHeader()

    @override
    def on_pre_enter(self, *args):
        """画面が表示されるとき。"""

        df: pl.DataFrame = self._shared_vars.df

        if not df.is_empty():
            self._datagrid_ball_sets.data = self._get_ball_set_count_data(df)
            self._datagrid_ball_sets.scroll_to_top()

            recently_data: list[dict[str, int | str]] = self._get_recently_data(df)
            recently_data = self._detect_duplicates(recently_data)
            self._datagrid_recently.data = recently_data

    ###############################################################################
    # Controllers

    def _get_ball_set_count_data(self, df: pl.DataFrame) -> list[dict[str, int | str]]:
        """セット球の選出回数データを取得する。

        Args:
            df (pl.DataFrame): データフレーム。

        Returns:
            list[dict[str, int | str]]: セット球の選出回数データ
        """

        return (
            df.group_by("ball_set")
            .agg(pl.count("ball_set").alias("count"))
            .select(pl.all().sort_by("ball_set"))
            .with_columns((pl.col("count") / pl.sum("count")).alias("rate"))
            .to_dicts()
        )

    def _get_recently_data(self, df: pl.DataFrame) -> list[dict[str, int | str]]:
        """最近のセット球の選出状況データを取得する。

        Args:
            df (pl.DataFrame): データフレーム。

        Returns:
            list[dict[str, int | str]]: 最近のセット球選出状況データ
        """

        ball_sets: list[str] = (
            df.select(pl.all().sort_by("times", descending=True))
            .get_column("ball_set")
            .to_list()
        )
        unique_ball_sets: set[str] = set(ball_sets)

        for i in range(len(ball_sets)):
            if set(ball_sets[0 : i + 1]) == unique_ball_sets:
                return df.select("times", "ball_set").tail(i + 1).to_dicts()

        return df.select(["times", "ball_set"]).tail(10).to_dicts()

    def _detect_duplicates(
        self, source: list[dict[str, int | str]]
    ) -> list[dict[str, int | str]]:
        """重複を検出して、is_duplicates プロパティを追加する。

        Args:
            source (list[dict[str, int | str]]): 重複を検出するデータのリスト。

        Returns:
            list[dict[str, int | str]]: 重複を検出したデータのリスト。
        """

        for row in source:
            ball_set: str = str(row["ball_set"])
            count: int = len([r for r in source if r["ball_set"] == ball_set])
            row["is_duplicated"] = count > 1

        return source
