"""Actor selection overlay for the TUI first-run experience."""

from __future__ import annotations

import importlib
from typing import Any

_DEFAULT_ACTORS: list[str] = [
    "anthropic/claude-4-sonnet",
    "anthropic/claude-4-opus",
    "openai/gpt-4o",
    "openai/o3",
    "google/gemini-2",
]


def _load_static_base() -> type[Any]:
    try:
        return importlib.import_module("textual.widgets").Static
    except Exception:  # pragma: no cover - optional dependency

        class _FallbackStatic:
            def __init__(self, *args: object, **kwargs: object) -> None:
                self._text = ""

            def update(self, text: str) -> None:
                self._text = text

        return _FallbackStatic


_StaticBase = _load_static_base()


def render_actor_selection(
    actors: list[str],
    selected_index: int,
    search_query: str,
) -> str:
    """Render the actor selection overlay content.

    Parameters
    ----------
    actors:
        Ordered list of actor identifiers to display.
    selected_index:
        Zero-based index of the currently highlighted actor.
    search_query:
        Current search filter string (empty means no filter active).

    Returns
    -------
    str
        Rendered text content for the overlay widget.
    """
    lines: list[str] = [
        "Welcome to CleverAgents",
        "",
        "Select an actor to get started:",
        "",
    ]
    for idx, actor in enumerate(actors):
        prefix = "❯ " if idx == selected_index else "  "  # noqa: RUF001
        suffix = "  (recommended)" if idx == 0 else ""
        lines.append(f"  {prefix}{actor}{suffix}")
    lines.append(f"  / {search_query if search_query else 'to search...'}")
    lines.append("")
    lines.append("A default persona will be created with this actor.")
    lines.append("You can add more actors and personas later.")
    lines.append("")
    lines.append("─" * 50)
    lines.append("enter Select │ j/k Navigate │ / Search")
    return "\n".join(lines)


class ActorSelectionOverlay(_StaticBase):
    """Centered overlay that guides actor selection on first launch.

    The overlay is shown when no personas are configured.  The user
    navigates the actor list with ``j``/``k`` (or arrow keys), filters
    with ``/``, and confirms with ``enter``.  The selected actor name is
    stored in ``selected_actor`` after confirmation.
    """

    def __init__(self, *args: object, **kwargs: object) -> None:
        super().__init__(*args, **kwargs)
        self._actors: list[str] = list(_DEFAULT_ACTORS)
        self._filtered_actors: list[str] = list(_DEFAULT_ACTORS)
        self._selected_index: int = 0
        self._search_query: str = ""
        self._confirmed: bool = False
        self._selected_actor: str | None = None
        self._visible: bool = False

    # ------------------------------------------------------------------
    # Public read-only properties
    # ------------------------------------------------------------------

    @property
    def actors(self) -> list[str]:
        """Return the full (unfiltered) actor list."""
        return list(self._actors)

    @property
    def filtered_actors(self) -> list[str]:
        """Return the currently filtered actor list."""
        return list(self._filtered_actors)

    @property
    def selected_index(self) -> int:
        """Return the zero-based index of the highlighted actor."""
        return self._selected_index

    @property
    def search_query(self) -> str:
        """Return the active search filter string."""
        return self._search_query

    @property
    def confirmed(self) -> bool:
        """Return ``True`` if the user has confirmed a selection."""
        return self._confirmed

    @property
    def selected_actor(self) -> str | None:
        """Return the confirmed actor name, or ``None`` if not yet confirmed."""
        return self._selected_actor

    @property
    def visible(self) -> bool:
        """Return whether the overlay is currently visible."""
        return self._visible

    # ------------------------------------------------------------------
    # Lifecycle helpers
    # ------------------------------------------------------------------

    def show(self, actors: list[str] | None = None) -> None:
        """Display the overlay, optionally overriding the actor list."""
        if actors is not None:
            self._actors = list(actors)
        self._filtered_actors = list(self._actors)
        self._selected_index = 0
        self._search_query = ""
        self._confirmed = False
        self._selected_actor = None
        self._visible = True
        self._render()

    def hide(self) -> None:
        """Hide the overlay and clear its content."""
        self._visible = False
        self.update("")

    # ------------------------------------------------------------------
    # Navigation
    # ------------------------------------------------------------------

    def move_up(self) -> None:
        """Move the selection cursor up by one position (wraps)."""
        if not self._filtered_actors:
            return
        self._selected_index = (self._selected_index - 1) % len(self._filtered_actors)
        self._render()

    def move_down(self) -> None:
        """Move the selection cursor down by one position (wraps)."""
        if not self._filtered_actors:
            return
        self._selected_index = (self._selected_index + 1) % len(self._filtered_actors)
        self._render()

    # ------------------------------------------------------------------
    # Search / filter
    # ------------------------------------------------------------------

    def set_search(self, query: str) -> None:
        """Apply a search filter to the actor list.

        Parameters
        ----------
        query:
            Substring to match against actor names (case-insensitive).
            An empty string clears the filter.
        """
        self._search_query = query
        if query:
            self._filtered_actors = [
                actor for actor in self._actors if query.lower() in actor.lower()
            ]
        else:
            self._filtered_actors = list(self._actors)
        self._selected_index = 0
        self._render()

    # ------------------------------------------------------------------
    # Confirmation
    # ------------------------------------------------------------------

    def confirm(self) -> str | None:
        """Confirm the currently highlighted actor.

        Returns
        -------
        str | None
            The confirmed actor name, or ``None`` if the filtered list is
            empty.
        """
        if not self._filtered_actors:
            return None
        actor = self._filtered_actors[self._selected_index]
        self._selected_actor = actor
        self._confirmed = True
        self.hide()
        return actor

    # ------------------------------------------------------------------
    # Internal rendering
    # ------------------------------------------------------------------

    def _render(self) -> None:
        content = render_actor_selection(
            self._filtered_actors,
            self._selected_index,
            self._search_query,
        )
        self.update(content)
