"""Status layout renderer for the Kollabor CLI status area.

Renders the status area based on the configured layout, using
widgets from the registry.
"""

import logging
import re
from typing import List, Optional, Any

from core.ui.design_system import T, S, solid, solid_fg
from core.io.terminal_state import get_global_width

from .widget_registry import StatusWidgetRegistry, WidthType
from .layout_manager import StatusLayoutManager, RowConfig, WidgetConfig
from .core_widgets import WidgetContext

logger = logging.getLogger(__name__)


def _strip_ansi(text: str) -> str:
    """Remove ANSI escape codes from text."""
    return re.sub(r"\033\[[0-9;]*m", "", text)


def _bg_line(text: str, bg: tuple, width: int) -> str:
    """Apply background to entire line, preserving foreground colors.

    Args:
        text: Text that may contain ANSI foreground codes
        bg: RGB tuple for background
        width: Total width to pad to

    Returns:
        Text with background applied
    """
    r, g, b = bg
    visible_len = len(_strip_ansi(text))
    padding = max(0, width - visible_len)
    return f"\033[48;2;{r};{g};{b}m{text}{' ' * padding}\033[0m"


class StatusLayoutRenderer:
    """Renders the status area based on layout configuration.

    Uses the widget registry to render individual widgets and
    arranges them according to the layout configuration.
    """

    def __init__(
        self,
        widget_registry: StatusWidgetRegistry,
        layout_manager: StatusLayoutManager,
        terminal_width: int = 76,
    ):
        """Initialize the layout renderer.

        Args:
            widget_registry: Registry of available widgets
            layout_manager: Manager for layout configuration
            terminal_width: Terminal width for layout calculations
        """
        self._widget_registry = widget_registry
        self._layout_manager = layout_manager
        self._terminal_width = terminal_width
        self._context: Optional[WidgetContext] = None

        logger.info("StatusLayoutRenderer initialized")

    def set_terminal_width(self, width: int) -> None:
        """Update terminal width for layout calculations."""
        self._terminal_width = width

    def set_context(self, context: WidgetContext) -> None:
        """Set the widget context for rendering.

        Args:
            context: WidgetContext with services needed for rendering
        """
        self._context = context
        self._widget_registry.set_context(context)

    def render(self) -> List[str]:
        """Render the complete status area.

        Returns:
            List of rendered lines (including borders)
        """
        layout = self._layout_manager.get_layout()
        visible_rows = layout.get_visible_rows()

        if not visible_rows:
            return []

        # Constrain width
        width = get_global_width()

        lines = []

        # Top border
        top_border = solid_fg("\u2584" * width, T().dark[0])  # ▄
        lines.append(top_border)

        # Render each visible row
        for row in visible_rows:
            row_content = self._render_row(row, width)
            if row_content:  # Only add non-empty rows
                lines.append(row_content)

        # Bottom border
        bottom_border = solid_fg("\u2580" * width, T().dark[0])  # ▀
        lines.append(bottom_border)

        return lines

    def _render_row(self, row: RowConfig, total_width: int) -> str:
        """Render a single row of widgets.

        Args:
            row: Row configuration
            total_width: Total available width

        Returns:
            Rendered row string with gutter and background
        """
        if not row.widgets:
            return ""

        # Gutter takes 1 character
        gutter_width = 1
        content_width = total_width - gutter_width

        # Render all widgets and collect results
        rendered_widgets = []
        for widget_config in row.widgets:
            widget_text = self._render_widget(widget_config, content_width)
            if widget_text:  # Only include non-empty widgets
                rendered_widgets.append(widget_text)

        if not rendered_widgets:
            return ""

        # Join widgets with spacing
        content = "  ".join(rendered_widgets)

        # Truncate if too long
        visible_len = len(_strip_ansi(content))
        if visible_len > content_width - 1:  # -1 for leading space
            content = self._truncate_with_ansi(content, content_width - 2) + "\u2026"  # ...

        # Build line: gutter (grey) + space + content (dark bg)
        gutter = solid(" ", T().dark[0], T().text_dim, gutter_width)  # space with dark bg (no visible char)
        content_line = _bg_line(" " + content, T().dark[0], content_width)

        return gutter + content_line

    def _render_widget(self, widget_config: WidgetConfig, available_width: int) -> str:
        """Render a single widget.

        Args:
            widget_config: Widget configuration
            available_width: Available width for the widget

        Returns:
            Rendered widget string
        """
        widget = self._widget_registry.get(widget_config.id)
        if not widget:
            logger.warning(f"Widget '{widget_config.id}' not found in registry")
            return ""

        # Calculate widget width
        width = self._calculate_widget_width(widget_config, available_width)

        # Render widget
        try:
            return widget.render(width, self._context)
        except Exception as e:
            logger.error(f"Error rendering widget '{widget_config.id}': {e}")
            return f"[{widget_config.id}:err]"

    def _calculate_widget_width(self, widget_config: WidgetConfig, available_width: int) -> int:
        """Calculate actual widget width based on configuration.

        Args:
            widget_config: Widget configuration with width spec
            available_width: Total available width

        Returns:
            Calculated width in characters
        """
        width_spec = widget_config.width
        widget = self._widget_registry.get(widget_config.id)
        min_width = widget.min_width if widget else 5

        if width_spec.type == WidthType.AUTO:
            # Auto: widget determines its own width, but cap at available
            return available_width

        elif width_spec.type == WidthType.RELATIVE:
            # Relative: percentage of available width
            percent = width_spec.value or 25
            calculated = int(available_width * percent / 100)
            return max(min_width, calculated)

        elif width_spec.type == WidthType.FIXED:
            # Fixed: exact character count
            fixed = width_spec.value or 10
            return max(min_width, min(fixed, available_width))

        return available_width

    def _truncate_with_ansi(self, text: str, max_length: int) -> str:
        """Truncate text while preserving ANSI codes.

        Args:
            text: Text with possible ANSI codes
            max_length: Maximum visible length

        Returns:
            Truncated text
        """
        result = ""
        visible_count = 0
        i = 0

        while i < len(text) and visible_count < max_length:
            if text[i:i + 1] == "\033" and i + 1 < len(text) and text[i + 1] == "[":
                # Find end of ANSI sequence
                end = i + 2
                while end < len(text) and text[end] not in "mhlABCDEFGHJKSTfimpsuI":
                    end += 1
                if end < len(text):
                    end += 1
                result += text[i:end]
                i = end
            else:
                result += text[i]
                visible_count += 1
                i += 1

        return result

    def render_preview(self, row_id: Optional[int] = None) -> List[str]:
        """Render a preview of the status area or a single row.

        Used by the status setup UI to show real-time preview.

        Args:
            row_id: Optional specific row to preview (None = all)

        Returns:
            List of rendered preview lines
        """
        layout = self._layout_manager.get_layout()
        width = get_global_width()

        if row_id is not None:
            row = layout.get_row(row_id)
            if row:
                content = self._render_row(row, width)
                return [content] if content else []
            return []

        # Render all rows for full preview
        return self.render()

    def render_widget_preview(self, widget_id: str, width: int = 30) -> str:
        """Render a preview of a single widget.

        Used by the widget picker to show what a widget looks like.

        Args:
            widget_id: Widget to preview
            width: Preview width

        Returns:
            Rendered widget preview string
        """
        widget = self._widget_registry.get(widget_id)
        if not widget:
            return f"[{widget_id}: not found]"

        try:
            return widget.render(width, self._context)
        except Exception as e:
            logger.error(f"Error rendering widget preview '{widget_id}': {e}")
            return f"[{widget_id}: error]"
