"""Message display widget for rendering chat message history."""

from typing import TYPE_CHECKING, Callable

from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import VerticalScroll
from textual.widget import Widget
from textual.widgets import Static

from cli.tui.chat.messages import CopyToClipboardRequested
from cli.tui.chat.renderers.markdown import MarkdownRenderer
from cli.tui.chat.renderers.plain import PlainTextRenderer
from cli.tui.chat.store import ChatStore
from cli.tui.chat.types import (
    ChatPhase,
    ChatState,
    MessageRenderer,
    RenderMode,
    extract_message_text,
)
from cli.tui.chat.widgets.welcome_screen import WelcomeScreen

if TYPE_CHECKING:
    from cli.tui.app import AlloyRuntimeApp


class MessageDisplay(Widget):
    """Widget for displaying chat message history.

    Features:
        - Renders message history with timestamps
        - Shows optimistic pending user messages while a response is in flight
        - Auto-scrolls to bottom on new content (unless user scrolls up)
        - Supports copying last response
        - Pluggable renderer for different output formats

    Posts Messages:
        - CopyToClipboardRequested: When user triggers copy action

    Auto-scroll behavior:
        - New renders scroll to bottom while auto-scroll is enabled
        - Pressing G re-enables auto-scroll and jumps to the end
    """

    app: "AlloyRuntimeApp"

    BINDINGS = [
        Binding("ctrl+y", "copy_last", "Copy Last", show=False),
        Binding("ctrl+shift+y", "copy_all", "Copy All", show=False),
        Binding("g", "scroll_top", "Top", show=False),
        Binding("G", "scroll_bottom", "Bottom", show=False),
    ]

    def __init__(
        self,
        store: ChatStore,
        renderer: MessageRenderer | None = None,
    ) -> None:
        """Initialize the message display.

        Args:
            store: ChatStore instance for state management.
            renderer: Optional renderer for message formatting. Defaults to MarkdownRenderer.
        """
        super().__init__()
        self._store = store
        self._custom_renderer: MessageRenderer | None = renderer
        self._markdown_renderer = MarkdownRenderer()
        self._plain_renderer = PlainTextRenderer()
        self._unsubscribe: Callable[[], None] | None = None
        # Auto-scroll is enabled by default.
        self._auto_scroll_enabled = True
        # Track whether welcome screen is currently shown
        self._welcome_screen_visible = False

    def _get_renderer(self, state: ChatState) -> MessageRenderer:
        """Get the appropriate renderer based on state."""
        if self._custom_renderer:
            return self._custom_renderer
        if state.render_mode == RenderMode.PLAIN:
            return self._plain_renderer
        return self._markdown_renderer

    def compose(self) -> ComposeResult:
        """Compose the message display layout."""
        with VerticalScroll(id="message-scroll"):
            # Start with welcome screen visible, messages hidden
            yield WelcomeScreen(id="welcome-screen")
            messages_widget = Static("", id="messages")
            messages_widget.display = False
            yield messages_widget
        self._welcome_screen_visible = True

    def on_mount(self) -> None:
        """Subscribe to store on mount."""
        self._unsubscribe = self._store.subscribe(self._on_state_change)

    def on_unmount(self) -> None:
        """Unsubscribe from store on unmount."""
        if self._unsubscribe:
            self._unsubscribe()

    def _on_state_change(self, state: ChatState) -> None:
        """React to store state changes."""
        self._render_messages(state)

    def _is_at_bottom(self) -> bool:
        """Check if scroll is at or near the bottom."""
        scroll = self.query_one("#message-scroll", VerticalScroll)
        return scroll.max_scroll_y <= 0 or scroll.scroll_y >= scroll.max_scroll_y - 50

    def _render_messages(self, state: ChatState) -> None:
        """Render messages to the display using the configured renderer."""
        messages_widget = self.query_one("#messages", Static)
        messages = state.messages
        pending_user_message = state.pending_user_message
        is_generating = state.phase == ChatPhase.SENDING

        self._auto_scroll_enabled = self._is_at_bottom()

        # Get assistant name from session context
        assistant_name = "Assistant"
        if state.session:
            assistant_name = state.session.display_name

        # Check if we have anything to show
        has_content = messages or pending_user_message

        # Determine if welcome screen should be visible
        should_show_welcome = state.session is None and not has_content

        # Switch between welcome screen and messages display
        if should_show_welcome != self._welcome_screen_visible:
            self._toggle_welcome_screen(should_show_welcome)

        if should_show_welcome:
            # Welcome screen handles its own content
            return

        if not has_content:
            # Session exists but no messages yet
            messages_widget.update(
                "[dim]No messages yet. Type below and press Ctrl+D to send.[/]"
            )
            return

        # Delegate rendering to the appropriate renderer based on state
        renderer = self._get_renderer(state)
        rendered_content = renderer.render(
            messages,
            pending_user_message=pending_user_message,
            assistant_name=assistant_name,
            is_generating=is_generating,
            thinking_collapsed=state.thinking_collapsed,
        )
        messages_widget.update(rendered_content)

        # Auto-scroll if enabled
        if self._auto_scroll_enabled:
            self._scroll_to_bottom()

    def _scroll_to_bottom(self) -> None:
        """Scroll the message view to the bottom."""
        scroll = self.query_one("#message-scroll", VerticalScroll)
        scroll.scroll_end(animate=False)

    def _toggle_welcome_screen(self, show_welcome: bool) -> None:
        """Toggle between welcome screen and messages display.

        Args:
            show_welcome: If True, show welcome screen; if False, show messages.
        """
        try:
            welcome_screen = self.query_one("#welcome-screen", WelcomeScreen)
            messages_widget = self.query_one("#messages", Static)

            welcome_screen.display = show_welcome
            messages_widget.display = not show_welcome
            self._welcome_screen_visible = show_welcome

            # Refresh welcome screen data when showing it
            if show_welcome:
                welcome_screen.refresh_data()
        except Exception:
            # Widgets may not be mounted yet during initial compose
            pass

    def action_copy_last(self) -> None:
        """Copy the last assistant response to clipboard."""
        messages = self._store.state.messages

        if not messages:
            self.app.notify("No messages to copy", severity="warning")
            return

        # Find last assistant message
        for msg in reversed(messages):
            if msg.role == "assistant":
                text = extract_message_text(msg)
                if text:
                    self.post_message(CopyToClipboardRequested(text, "Last response"))
                    return

        self.app.notify("No assistant message to copy", severity="warning")

    def action_copy_all(self) -> None:
        """Copy all messages to clipboard as plain text."""
        messages = self._store.state.messages

        if not messages:
            self.app.notify("No messages to copy", severity="warning")
            return

        # Build plain text version of all messages
        lines: list[str] = []
        for msg in messages:
            role = msg.role.capitalize()
            text = extract_message_text(msg)
            if text:
                lines.append(f"{role}:\n{text}\n")

        if lines:
            full_text = "\n".join(lines)
            self.post_message(CopyToClipboardRequested(full_text, "All messages"))
        else:
            self.app.notify("No message content to copy", severity="warning")

    def action_scroll_top(self) -> None:
        """Scroll to the top of messages."""
        scroll = self.query_one("#message-scroll", VerticalScroll)
        scroll.scroll_home(animate=False)

    def action_scroll_bottom(self) -> None:
        """Scroll to the bottom of messages and resume auto-scroll."""
        self._auto_scroll_enabled = True
        self._scroll_to_bottom()

    def show_welcome(self) -> None:
        """Show the welcome screen."""
        self._toggle_welcome_screen(show_welcome=True)
