# SPDX-License-Identifier: MIT

from __future__ import annotations

from typing import TYPE_CHECKING, Any, ClassVar, List, Tuple, Union, cast

from ..components import Section as SectionComponent
from ..enums import ComponentType
from ..utils import copy_doc
from .item import UIComponent, ensure_ui_component
from .text_display import TextDisplay

if TYPE_CHECKING:
    from typing_extensions import Self

    from .button import Button
    from .thumbnail import Thumbnail

    SectionAccessoryUIComponent = Union[Thumbnail, Button[Any]]

__all__ = ("Section",)


class Section(UIComponent):
    """Represents a UI section.

    This allows displaying an accessory (thumbnail or button) next to a block of text.

    .. versionadded:: 2.11

    Parameters
    ----------
    *components: Union[:class:`str`, :class:`~.ui.TextDisplay`]
        The text items in this section (up to 3).
    accessory: Union[:class:`~.ui.Thumbnail`, :class:`~.ui.Button`]
        The accessory component displayed next to the section text.
    id: :class:`int`
        The numeric identifier for the component. Must be unique within the message.
        If set to ``0`` (the default) when sending a component, the API will assign
        sequential identifiers to the components in the message.

    Attributes
    ----------
    children: List[:class:`~.ui.TextDisplay`]
        The list of text items in this section.
    accessory: Union[:class:`~.ui.Thumbnail`, :class:`~.ui.Button`]
        The accessory component displayed next to the section text.
    """

    __repr_attributes__: ClassVar[Tuple[str, ...]] = (
        "children",
        "accessory",
    )

    def __init__(
        self,
        *components: Union[str, TextDisplay],
        accessory: SectionAccessoryUIComponent,
        id: int = 0,
    ) -> None:
        self._id: int = id
        # this list can be modified without any runtime checks later on,
        # just assume the user knows what they're doing at that point
        self.children: List[TextDisplay] = [
            TextDisplay(c) if isinstance(c, str) else ensure_ui_component(c, "components")
            for c in components
        ]
        self.accessory: SectionAccessoryUIComponent = ensure_ui_component(accessory, "accessory")

    # these are reimplemented here to store the value in a separate attribute,
    # since `Section` lazily constructs `_underlying`, unlike most components
    @property
    @copy_doc(UIComponent.id)
    def id(self) -> int:
        return self._id

    @id.setter
    def id(self, value: int) -> None:
        self._id = value

    @property
    def _underlying(self) -> SectionComponent:
        return SectionComponent._raw_construct(
            type=ComponentType.section,
            id=self._id,
            children=[comp._underlying for comp in self.children],
            accessory=self.accessory._underlying,
        )

    @classmethod
    def from_component(cls, section: SectionComponent) -> Self:
        from .action_row import _to_ui_component

        return cls(
            *cast(
                "List[TextDisplay]",
                [_to_ui_component(c) for c in section.children],
            ),
            accessory=cast("SectionAccessoryUIComponent", _to_ui_component(section.accessory)),
            id=section.id,
        )
