"""StreamingPanel - Real-time output display for Claude Code execution.

Contract: CNT-T5-UI-001
Traceability: UX-001, UI-002

Responsibility: Display streaming output from Claude Code in a visually
appealing panel that updates in real-time.
"""

from collections import deque
from collections.abc import Callable, Generator, Iterator
from contextlib import contextmanager

from rich.console import Console
from rich.live import Live
from rich.panel import Panel
from rich.text import Text

from laida_cli.ui.theme import LAIDA_THEME, Styles


class StreamingPanel:
    """Real-time streaming output panel.

    Displays Claude Code output as it arrives, maintaining a rolling
    buffer of recent lines for clean display.

    Usage:
        panel = StreamingPanel(console)
        output = panel.stream(line_iterator, title="Executing...")
    """

    DEFAULT_MAX_LINES = 20

    def __init__(
        self,
        console: Console | None = None,
        max_lines: int = DEFAULT_MAX_LINES,
    ) -> None:
        """Initialize streaming panel.

        Args:
            console: Rich console for output (creates themed console if None)
            max_lines: Maximum lines to display in the rolling buffer
        """
        self._console = console or Console(theme=LAIDA_THEME)
        self._max_lines = max_lines

    def stream(
        self,
        lines: Iterator[str],
        title: str = "Claude Code Output",
    ) -> str:
        """Stream lines to the panel and return complete output.

        Displays each line as it arrives using Rich Live, then
        returns the complete accumulated output.

        Args:
            lines: Iterator yielding output lines
            title: Panel title to display

        Returns:
            Complete output as a single string
        """
        buffer: deque[str] = deque(maxlen=self._max_lines)
        complete_output: list[str] = []

        with Live(
            self._render_panel(buffer, title, is_running=True),
            console=self._console,
            refresh_per_second=10,
            transient=True,
        ) as live:
            for line in lines:
                complete_output.append(line)
                # Strip trailing newline for display, keep content
                display_line = line.rstrip("\n")
                if display_line:  # Skip empty lines in display
                    buffer.append(display_line)
                live.update(self._render_panel(buffer, title, is_running=True))

        # Show final static panel
        self._console.print(
            self._render_panel(buffer, title, is_running=False)
        )

        return "".join(complete_output)

    @contextmanager
    def live_output(
        self,
        title: str = "Claude Code Output",
    ) -> Generator[Callable[[str], None], None, None]:
        """Context manager for callback-based streaming.

        Provides a callback function that updates the live display
        when invoked with new output lines.

        Usage:
            with panel.live_output("Executing...") as on_output:
                result = service.execute_streaming(
                    on_output=on_output,
                    ...
                )

        Args:
            title: Panel title to display

        Yields:
            Callback function to invoke with each output line
        """
        buffer: deque[str] = deque(maxlen=self._max_lines)

        with Live(
            self._render_panel(buffer, title, is_running=True),
            console=self._console,
            refresh_per_second=10,
            transient=True,
        ) as live:

            def handle_output(line: str) -> None:
                display_line = line.rstrip("\n")
                if display_line:
                    buffer.append(display_line)
                live.update(self._render_panel(buffer, title, is_running=True))

            yield handle_output

        # Show final static panel
        self._console.print(
            self._render_panel(buffer, title, is_running=False)
        )

    def _render_panel(
        self,
        buffer: deque[str],
        title: str,
        is_running: bool,
    ) -> Panel:
        """Render the output panel.

        Args:
            buffer: Lines to display
            title: Panel title
            is_running: Whether execution is still running

        Returns:
            Configured Rich Panel
        """
        if not buffer:
            content = Text("Waiting for output...", style=Styles.HINT)
        else:
            content = Text()
            for i, line in enumerate(buffer):
                if i > 0:
                    content.append("\n")
                content.append(line, style=Styles.AGENT)

        if is_running:
            status = f"[{Styles.PROGRESS}]Running...[/{Styles.PROGRESS}]"
        else:
            status = f"[{Styles.SUCCESS}]Complete[/{Styles.SUCCESS}]"
        subtitle = f"{status}  [{Styles.MUTED}]{len(buffer)} lines[/{Styles.MUTED}]"

        return Panel(
            content,
            title=f"[{Styles.PANEL_TITLE}]{title}[/{Styles.PANEL_TITLE}]",
            subtitle=subtitle,
            border_style=Styles.PANEL_BORDER,
            padding=(0, 1),
        )
