"""Inline slash-command hints shown above the input box.

A non-interactive ``Static`` that renders the commands matching the current
input while the user is typing a ``/``-command. It is purely visual — it never
takes focus. Keyboard navigation (``Up``/``Down`` to move the highlight,
``Enter`` to run the highlighted command, ``Tab`` to complete its name) is
handled by ``_PromptInput`` via a reference to this widget.

Visibility rule: hints appear only while the input starts with ``/`` and
contains no whitespace yet (i.e. the command name is still being typed). The
moment a space appears the command name is complete and the hints hide.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from rich.text import Text
from textual.widgets import Static

if TYPE_CHECKING:
    from clients.terminal.tui.commands.base import BaseCommand

# Cap the list so a one-character prefix does not push the whole input frame up
# by half a screen.
_MAX_HINTS = 8


class CommandHints(Static):
    """Render matching slash commands for the current input, with a highlight."""

    DEFAULT_CSS = """
    CommandHints {
        display: none;
        height: auto;
        max-height: 10;
        width: 100%;
        padding: 0 1;
        background: $tui-surface;
        color: $tui-text;
        border-top: solid $tui-border;
    }
    """

    def __init__(self) -> None:
        super().__init__("")
        self._matches: list[BaseCommand] = []
        self._highlighted = 0

    def update_for(self, text: str) -> None:
        """Recompute hints for ``text`` and show/hide the widget."""
        # Show only while typing the command name: starts with '/' and no space.
        if not text.startswith("/") or any(ch.isspace() for ch in text):
            self._matches = []
            self._highlighted = 0
            self.display = False
            return

        from clients.terminal.tui.commands.registry import get_registry

        self._matches = get_registry().match(text[1:])
        if not self._matches:
            self._highlighted = 0
            self.display = False
            return
        # Keep the highlight valid when the match set shrinks; reset to top when
        # the command name changed (highlight 0 is the exact-name-first match).
        if self._highlighted >= len(self._matches):
            self._highlighted = 0
        self.update(self._build_content())
        self.display = True

    def visible(self) -> bool:
        """True when the hint list is currently shown with at least one match."""
        return bool(self.display) and bool(self._matches)

    def current_match(self) -> BaseCommand | None:
        """The highlighted match — what ``Enter``/``Tab`` act on."""
        if not self._matches:
            return None
        return self._matches[self._highlighted]

    def move_highlight(self, delta: int) -> bool:
        """Move the highlight by ``delta`` (wraps around). Returns True if moved."""
        if len(self._matches) <= 1:
            return False
        self._highlighted = (self._highlighted + delta) % len(self._matches)
        self.update(self._build_content())
        return True

    def _build_content(self) -> Text:
        lines: list[Text] = []
        for index, cmd in enumerate(self._matches[:_MAX_HINTS]):
            meta = cmd.meta
            aliases = f" ({', '.join(meta.aliases)})" if meta.aliases else ""
            keybind = f"  [{meta.keybind}]" if meta.keybind else ""
            line = Text.assemble(
                Text(f"/{meta.name}{aliases}", style="bold"),
                Text(keybind, style="dim"),
                Text(f"  — {meta.description}", style="dim"),
            )
            if index == self._highlighted:
                line.stylize("reverse")
            lines.append(line)
        return Text("\n").join(lines)