#
#   Imandra Inc.
#
#   speclogician/presentation/renderers/state_diff.py
#

from __future__ import annotations

from rich.console import Group, RenderableType
from rich.rule import Rule
from rich.text import Text

from speclogician.presentation.ctx import RenderCtx
from speclogician.presentation.models.state_diff import StateDiffPM, DiffRowPM
from speclogician.state.diff import ComparisonOutcome


def _icon_style_label(oc: ComparisonOutcome) -> tuple[str, str, str]:
    """
    Returns: (icon, rich_style, human_label)
    """
    match oc:
        case ComparisonOutcome.IMPROVED:
            return ("⬆", "green", "improved")
        case ComparisonOutcome.DECLINED:
            return ("⬇", "red", "declined")
        case ComparisonOutcome.NO_CHANGE_GOOD:
            return ("🟢", "green", "no change (good)")
        case ComparisonOutcome.NO_CHANGE_BAD:
            return ("🔴", "red", "no change (bad)")
        case ComparisonOutcome.NO_CHANGE:
            return ("🟰", "yellow", "no change")
        case ComparisonOutcome.UNKNOWN:
            return ("🤷", "dim", "unknown")
        case _:
            # fallback for future enum additions
            return ("•", "dim", getattr(oc, "value", str(oc)))


def _render_row(r: DiffRowPM, *, label_width: int) -> RenderableType:
    icon, style, human = _icon_style_label(r.outcome)

    # Keep alignment stable for monospace-ish terminals
    before = str(r.before)
    after = str(r.after)

    # Example:
    # ⬆ base_status        UNKNOWN → VALID   (improved)
    txt = Text()
    txt.append(f"{icon} ", style=style)
    txt.append(f"{r.label:<{label_width}}", style="bold")
    txt.append(f" {before} → {after}")
    txt.append(f" ({human})", style="dim")
    return txt


def _render_section(title: str, rows: list[DiffRowPM], *, ctx: RenderCtx) -> RenderableType:
    if not rows:
        return Text("")

    # Compute a reasonable label alignment width for this section (cap to avoid huge padding)
    max_len = max((len(r.label) for r in rows), default=len("Metric"))
    label_width = min(max(max_len, 18), 34)

    parts: list[RenderableType] = []
    # Bracketed header style like your desired output
    parts.append(Text(f"[{title}]", style="bold"))

    for r in rows:
        parts.append(_render_row(r, label_width=label_width))

    return Group(*parts)


def render_state_diff(pm: StateDiffPM, *, ctx: RenderCtx) -> RenderableType:
    # Plain-text-ish layout, no panels/tables.
    # Desired style:
    # State diff
    # ──────────
    #
    # [Section]
    # ⬆ metric before → after (improved)

    if not pm.has_changes:
        return Group(
            Text("State diff", style="bold"),
            Rule(style="dim"),
            Text("No differences detected", style="italic dim"),
        )

    blocks: list[RenderableType] = [Text("State diff", style="bold"), Rule(style="dim")]

    first = True
    for sec in pm.sections:
        if sec.empty():
            continue
        if not first and not ctx.compact:
            blocks.append(Text(""))  # blank line between sections
        first = False
        blocks.append(_render_section(sec.title, sec.rows, ctx=ctx))

    return Group(*blocks)