import discord

# from typing import List
# from typing import Optional
# from typing import Iterable
# import traceback
from dataclasses import dataclass

MAX_SELECT_PER_PAGE = 2
MAX_OPTIONS_PER_SELECT = 25
ITEMS_PER_PAGE = MAX_SELECT_PER_PAGE * MAX_OPTIONS_PER_SELECT


@dataclass
class SelectItem:
    label: str
    value: str
    description: str | None = None


class GenericSelect(discord.ui.Select):
    def __init__(
        self,
        items: list[SelectItem],
        selected_values: set[str],
        placeholder: str = "選択してください",
    ):
        options = [
            discord.SelectOption(
                label=item.label,
                value=item.value,
                description=item.description,
                default=item.value in selected_values,
            )
            for item in items
        ]

        super().__init__(
            placeholder=placeholder,
            min_values=0,
            max_values=len(options),
            options=options,
        )

    async def callback(self, interaction: discord.Interaction):
        view: GenericSelectView = self.view  # type: ignore

        # このSelect内のvalueを一旦削除
        for opt in self.options:
            view.selected_values.discard(opt.value)

        # 新規選択分を追加
        for v in self.values:
            view.selected_values.add(v)

        await interaction.response.defer()


class PrevButton(discord.ui.Button):
    def __init__(self):
        super().__init__(label="前へ", style=discord.ButtonStyle.secondary)

    async def callback(self, interaction: discord.Interaction):
        view: GenericSelectView = self.view  # type: ignore
        if view.page > 0:
            view.page -= 1
            view._refresh_items()
        await interaction.response.edit_message(view=view)


class NextButton(discord.ui.Button):
    def __init__(self):
        super().__init__(label="次へ", style=discord.ButtonStyle.secondary)

    async def callback(self, interaction: discord.Interaction):
        view: GenericSelectView = self.view  # type: ignore
        max_page = (len(view.items) - 1) // ITEMS_PER_PAGE
        if view.page < max_page:
            view.page += 1
            view._refresh_items()
        await interaction.response.edit_message(view=view)


class GenericSelectView(discord.ui.View):
    def __init__(
        self,
        interaction: discord.Interaction,
        items: list[SelectItem],
        default_values: set[str] | None = None,
        extra_items: list[discord.ui.Item] | None = None,
    ):
        super().__init__(timeout=None)

        self.interaction = interaction
        self.items = items
        self.page = 0
        self.selected_values: set[str] = default_values or set()
        self.extra_items = extra_items or []

        self._refresh_items()

    def _refresh_items(self):
        self.clear_items()

        start = self.page * ITEMS_PER_PAGE
        end = start + ITEMS_PER_PAGE
        page_items = self.items[start:end]

        for i in range(0, len(page_items), MAX_OPTIONS_PER_SELECT):
            self.add_item(
                GenericSelect(
                    items=page_items[i : i + MAX_OPTIONS_PER_SELECT],
                    selected_values=self.selected_values,
                )
            )

        self.add_item(PrevButton())
        self.add_item(NextButton())

        for item in self.extra_items:
            self.add_item(item)
