"""ThoughtBlockWidget — muted, expandable actor reasoning trace widget."""

from __future__ import annotations

import contextlib
import importlib
from typing import Any

from cleveragents.domain.models.thought.thought_block import ThoughtBlock


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

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

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

            def add_class(self, cls: str) -> None:
                self._classes.add(cls)

            def remove_class(self, cls: str) -> None:
                self._classes.discard(cls)

        return _FallbackStatic


_StaticBase = _load_static_base()

# CSS class applied to the widget for muted styling
_CSS_CLASS_MUTED = "thought-block"
_CSS_CLASS_EXPANDED = "thought-block--expanded"
_CSS_CLASS_COLLAPSED = "thought-block--collapsed"

# Indicator characters matching the spec
_INDICATOR_COLLAPSED = "▶"
_INDICATOR_EXPANDED = "▼"


class ThoughtBlockWidget(_StaticBase):
    """Widget that renders an actor thought block with muted styling.

    The widget wraps a :class:`~cleveragents.domain.models.thought.ThoughtBlock`
    domain model and provides:

    - Collapsed view showing at most ``max_lines`` lines with a truncation
      indicator when content exceeds that limit.
    - Expandable view showing the full content.
    - Muted styling via the ``thought-block`` CSS class.
    - Toggle via :meth:`toggle` (bound to ``space`` in the conversation
      stream) or :meth:`expand` / :meth:`collapse`.
    """

    DEFAULT_CSS = """
    ThoughtBlockWidget {
        background: $primary-muted 20%;
        color: $text-muted;
        border: solid $primary 30%;
        padding: 0 1;
        margin: 0 0 1 0;
    }
    ThoughtBlockWidget.thought-block--expanded {
        max-height: 100vh;
    }
    ThoughtBlockWidget.thought-block--collapsed {
        max-height: 10;
    }
    """

    def __init__(
        self,
        thought: ThoughtBlock,
        *args: object,
        **kwargs: object,
    ) -> None:
        super().__init__(*args, **kwargs)
        self._thought = thought
        self._text = ""
        self._classes: set[str] = {_CSS_CLASS_MUTED}
        self._refresh_display()

    # ------------------------------------------------------------------
    # Public API
    # ------------------------------------------------------------------

    @property
    def thought(self) -> ThoughtBlock:
        """Return the underlying domain model."""
        return self._thought

    @property
    def is_expanded(self) -> bool:
        """Return whether the widget is currently expanded."""
        return self._thought.expanded

    def toggle(self) -> None:
        """Toggle between expanded and collapsed states."""
        self._thought.toggle()
        self._refresh_display()

    def expand(self) -> None:
        """Expand the widget to show full content."""
        self._thought.expand()
        self._refresh_display()

    def collapse(self) -> None:
        """Collapse the widget to show only max_lines."""
        self._thought.collapse()
        self._refresh_display()

    # ------------------------------------------------------------------
    # Internal helpers
    # ------------------------------------------------------------------

    def _indicator(self) -> str:
        return _INDICATOR_EXPANDED if self._thought.expanded else _INDICATOR_COLLAPSED

    def _refresh_display(self) -> None:
        """Recompute the rendered text and update CSS classes."""
        rendered = self._thought.rendered_text()
        indicator = self._indicator()
        if rendered:
            self._text = f"{indicator} {rendered}"
        else:
            self._text = f"{indicator} (empty thought)"

        # Update CSS state classes
        if self._thought.expanded:
            self._classes.discard(_CSS_CLASS_COLLAPSED)
            self._classes.add(_CSS_CLASS_EXPANDED)
        else:
            self._classes.discard(_CSS_CLASS_EXPANDED)
            self._classes.add(_CSS_CLASS_COLLAPSED)

        with contextlib.suppress(Exception):  # pragma: no cover
            self.update(self._text)

    # ------------------------------------------------------------------
    # Textual event handlers (no-ops when Textual is unavailable)
    # ------------------------------------------------------------------

    def on_click(self) -> None:  # pragma: no cover
        """Toggle expand/collapse on mouse click."""
        self.toggle()

    def on_key(self, event: Any) -> None:  # pragma: no cover
        """Toggle on space key press."""
        try:
            if event.key == "space":
                self.toggle()
        except AttributeError:
            pass
