"""PaginatedView — a discord.ui.View with Prev / Next buttons."""

from __future__ import annotations

from typing import Sequence

from discord import Embed, Interaction, InteractionMessage
from discord.ui import Button, View, button


class PaginatedView(View):
    """A View that pages through a sequence of Embeds with **Prev** / **Next** buttons.

    Parameters
    ----------
    pages : Sequence[Embed]
        The ordered list of embeds to paginate through.
        Any ``discord.Embed`` (including :class:`Page` subclasses) is accepted.
    timeout : float | None
        How long (seconds) the view stays active.  Defaults to ``600``.
    wrap : bool
        If ``True``, pressing *Next* on the last page goes to the first page
        (and vice-versa).  Defaults to ``False`` (buttons disable at boundaries).
    show_page_count : bool
        If ``True``, a ``Page X / Y`` indicator button is displayed between
        *Prev* and *Next*.  Defaults to ``True``.
    prev_label : str
        Label for the previous-page button.  Defaults to ``"Prev"``.
    next_label : str
        Label for the next-page button.  Defaults to ``"Next"``.

    Examples
    --------
    ::

        pages = [
            Page(title="Page 1", description="Hello"),
            Page(title="Page 2", description="World"),
        ]
        view = PaginatedView(pages)
        await interaction.response.send_message(embed=pages[0], view=view)
        view.message = await interaction.original_response()

    Or use the convenience :meth:`send` helper::

        view = PaginatedView(pages)
        await view.send(message)
    """

    def __init__(
        self,
        pages: Sequence[Embed],
        *,
        timeout: float | None = 600,
        wrap: bool = False,
        show_page_count: bool = True,
        prev_label: str = "Prev",
        next_label: str = "Next",
    ) -> None:
        super().__init__(timeout=timeout)
        if not pages:
            raise ValueError("pages must contain at least one Embed.")

        self.pages: list[Embed] = list(pages)
        self.current_page: int = 0
        self.wrap: bool = wrap
        self.show_page_count: bool = show_page_count

        # Update button labels
        self.prev_button.label = prev_label
        self.next_button.label = next_label

        # Message reference (set by send() or externally)
        self.message: InteractionMessage | None = None

    # -- helpers ---------------------------------------------------------------

    @property
    def page_count(self) -> int:
        """Total number of pages."""
        return len(self.pages)

    @property
    def current_embed(self) -> Embed:
        """The embed for the current page index."""
        return self.pages[self.current_page]

    def _update_buttons(self) -> None:
        """Enable / disable navigation buttons based on the current page."""
        if self.wrap:
            self.prev_button.disabled = False
            self.next_button.disabled = False
        else:
            self.prev_button.disabled = self.current_page == 0
            self.next_button.disabled = self.current_page >= self.page_count - 1

        if self.show_page_count:
            self.page_indicator.label = f"{self.current_page + 1} / {self.page_count}"

    # -- public API ------------------------------------------------------------

    async def send(self, message: InteractionMessage) -> None:
        """Edit *message* to display the first page with navigation buttons.

        Parameters
        ----------
        message : InteractionMessage
            A message obtained from ``await interaction.original_response()``.
        """
        self.message = message
        self.current_page = 0
        self._update_buttons()
        await self.message.edit(embed=self.current_embed, view=self)

    async def goto(self, page: int) -> None:
        """Jump directly to a specific page index and refresh the message.

        Parameters
        ----------
        page : int
            Zero-based page index.
        """
        self.current_page = max(0, min(page, self.page_count - 1))
        self._update_buttons()
        if self.message:
            await self.message.edit(embed=self.current_embed, view=self)

    # -- buttons ---------------------------------------------------------------

    @button(label="Prev", style=2)
    async def prev_button(self, interaction: Interaction, btn: Button) -> None:
        await interaction.response.defer()
        if self.wrap:
            self.current_page = (self.current_page - 1) % self.page_count
        else:
            self.current_page = max(0, self.current_page - 1)
        self._update_buttons()
        await self.message.edit(embed=self.current_embed, view=self)

    @button(label="\u00b7", style=2, disabled=True)
    async def page_indicator(self, interaction: Interaction, btn: Button) -> None:
        # This button is purely cosmetic — it shows "X / Y".
        await interaction.response.defer()

    @button(label="Next", style=2)
    async def next_button(self, interaction: Interaction, btn: Button) -> None:
        await interaction.response.defer()
        if self.wrap:
            self.current_page = (self.current_page + 1) % self.page_count
        else:
            self.current_page = min(self.page_count - 1, self.current_page + 1)
        self._update_buttons()
        await self.message.edit(embed=self.current_embed, view=self)

    # -- lifecycle -------------------------------------------------------------

    async def on_timeout(self) -> None:
        """Disable all buttons when the view times out."""
        for item in self.children:
            if isinstance(item, Button):
                item.disabled = True
        if self.message:
            try:
                await self.message.edit(view=self)
            except Exception:
                pass
