from __future__ import annotations

from typing import TYPE_CHECKING, cast

from rich.align import Align, AlignMethod

if TYPE_CHECKING:
    from textual.app import RenderResult

from textual.geometry import Size
from textual.renderables.digits import Digits as DigitsRenderable
from textual.selection import Selection
from textual.widget import Widget


class Digits(Widget):
    """A widget to display numerical values using a 3x3 grid of unicode characters."""

    DEFAULT_CSS = """
    Digits {
        width: 1fr;
        height: auto;
        text-align: left;        
        box-sizing: border-box;
    }
    """

    def __init__(
        self,
        value: str = "",
        *,
        name: str | None = None,
        id: str | None = None,
        classes: str | None = None,
        disabled: bool = False,
    ) -> None:
        """Initialize a Digits widget.

        Args:
            value: Value to display in widget.
            name: The name of the widget.
            id: The ID of the widget in the DOM.
            classes: The CSS classes of the widget.
            disabled: Whether the widget is disabled or not.

        """
        if not isinstance(value, str):
            raise TypeError("value must be a str")
        super().__init__(name=name, id=id, classes=classes, disabled=disabled)
        self._value = value

    @property
    def value(self) -> str:
        """The current value displayed in the Digits."""
        return self._value

    def get_selection(self, selection: Selection) -> str | None:
        return self._value

    def update(self, value: str) -> None:
        """Update the Digits with a new value.

        Args:
            value: New value to display.

        Raises:
            TypeError: If the value isn't a `str`.
        """
        if not isinstance(value, str):
            raise TypeError("value must be a str")
        layout_required = len(value) != len(self._value) or (
            DigitsRenderable.get_width(self._value) != DigitsRenderable.get_width(value)
        )
        self._value = value
        self.refresh(layout=layout_required)

    def render(self) -> RenderResult:
        """Render digits."""
        rich_style = self.rich_style
        if self.text_selection:
            rich_style = self.screen.get_component_rich_style(
                "screen--selection", partial=True
            )
        digits = DigitsRenderable(self._value, rich_style)
        text_align = self.styles.text_align
        align = "left" if text_align not in {"left", "center", "right"} else text_align
        return Align(digits, cast(AlignMethod, align), rich_style)

    def get_content_width(self, container: Size, viewport: Size) -> int:
        """Called by textual to get the width of the content area.

        Args:
            container: Size of the container (immediate parent) widget.
            viewport: Size of the viewport.

        Returns:
            The optimal width of the content.
        """
        return DigitsRenderable.get_width(self._value)

    def get_content_height(self, container: Size, viewport: Size, width: int) -> int:
        """Called by Textual to get the height of the content area.

        Args:
            container: Size of the container (immediate parent) widget.
            viewport: Size of the viewport.
            width: Width of renderable.

        Returns:
            The height of the content.
        """
        return 3  # Always 3 lines
