"""Renderer for markdown content."""

from __future__ import annotations

from rich.console import Console, RenderableType, ConsoleOptions, RenderResult
from rich.markdown import Markdown
from rich.segment import Segment
from rich.style import Style
from rich.theme import Theme as RichTheme

from clients.terminal.tui.themes import ThemeRegistry, get_active_theme

from .base import ContentRenderer


def _theme_aware_code_theme(theme_name: str) -> str:
    """Resolve the Pygments code style for a Navi theme name.

    The single source of truth is ``Theme.code_theme``; this is a thin
    resolver for callers that only hold the theme name (rich's ``Markdown``
    takes a style *string*, not a Theme). All syntax highlighting in the TUI
    flows through here so the whole UI shares one code colour scheme.
    """
    return ThemeRegistry.get(theme_name).code_theme


class ThemedMarkdownRenderable:
    """Wrap Markdown and render it with Navi theme colors applied."""

    def __init__(self, markdown: Markdown, theme_name: str) -> None:
        self._markdown = markdown
        self._theme_name = theme_name

    def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
        theme = get_active_theme()
        # Render at the *available* width (options.max_width), not the physical
        # console width. Textual passes a console whose .width is the terminal
        # width (e.g. 80), but the panel the markdown lives in is narrower —
        # options.max_width holds the real available columns (panel inner width
        # minus borders/padding). Using console.width here made rich wrap to the
        # terminal width while the visible area was narrower, so the right side
        # of every long line vanished off the panel's right edge. Fall back to
        # console.width only if max_width is unset.
        themed_console = Console(
            width=options.max_width or console.width,
            color_system=console.color_system,
            theme=RichTheme(theme.rich_theme_styles()),
            force_terminal=True,
        )
        link_color = Style.parse(theme.link.hex).color
        # Stream segments straight through instead of materializing them into a
        # list first — every paint (scroll, resize, reading-mode toggle) would
        # otherwise allocate the full segment list + walk it twice (once to
        # build, once to rewrite links). Inline the link rewrite in the loop.
        for segment in themed_console.render(self._markdown):
            style = segment.style
            if style and style.link and link_color is not None:
                yield Segment(
                    segment.text,
                    Style(color=link_color, underline=True, link=style.link),
                )
            else:
                yield segment


class MarkdownRenderer(ContentRenderer):
    """Render markdown text with syntax highlighting."""

    def accepts(self, msg: dict) -> bool:
        return msg.get("type") == "markdown"

    def render(self, msg: dict) -> RenderableType:
        theme = get_active_theme()
        text = msg.get("content", "")
        code_theme = _theme_aware_code_theme(theme.name)
        md = Markdown(
            text,
            code_theme=code_theme,
            inline_code_theme=code_theme,
        )
        return ThemedMarkdownRenderable(md, theme.name)
