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

from __future__ import annotations

from rich import box
from rich.panel import Panel
from rich.console import Group
from rich.rule import Rule
from rich.table import Table
from rich.text import Text
from rich.syntax import Syntax

from speclogician.presentation.ctx import RenderCtx
from speclogician.presentation.models.trace import TestTracePM, LogTracePM
from speclogician.presentation.renderers import iml_validity_icon_style_label


def _validity_text(iml_valid: str | None) -> Text:
    icon, style, label = iml_validity_icon_style_label(iml_valid)
    return Text(f"{icon} {label}", style=f"bold {style}")


def _kv_table(ctx: RenderCtx) -> Table:
    b = box.MINIMAL if getattr(ctx, "compact", False) else box.SIMPLE
    t = Table(show_header=False, box=b, show_edge=False, pad_edge=False, expand=True)
    t.add_column(style="italic dim", no_wrap=True)
    t.add_column()
    return t


def _code_block(title: str, code: str, *, lang: str) -> Group:
    # No panel: just a rule + syntax
    return Group(
        Rule(f"[bold]{title}[/bold]"),
        Syntax(code or "", lang, word_wrap=True),
    )


def render_test_trace(pm: TestTracePM, *, ctx: RenderCtx):
    core = pm.core

    t = _kv_table(ctx)

    if getattr(ctx, "show_ids", False):
        t.add_row("art_id", Text(core.art_id, style="dim"))

    t.add_row("name", Text(pm.name or "-", style="bold"))
    if pm.filepath:
        t.add_row("filepath", Text(pm.filepath))
    if pm.language:
        t.add_row("language", Text(pm.language))

    t.add_row("iml_valid", _validity_text(core.iml_validity.iml_valid))
    if core.iml_validity.err:
        t.add_row("iml_error", Text(core.iml_validity.err, style="red"))

    if core.time:
        t.add_row("time", Text(core.time, style="dim"))

    blocks: list[object] = [t]

    if getattr(ctx, "show_code", True):
        blocks.append(_code_block("given : state", core.given, lang="ocaml"))
        if core.when:
            blocks.append(_code_block("when : action", core.when, lang="ocaml"))
        if core.then:
            blocks.append(_code_block("then : state", core.then, lang="ocaml"))

        if pm.contents:
            blocks.append(
                _code_block(
                    "original test contents",
                    pm.contents,
                    lang=(pm.language or "text"),
                )
            )

    return Panel(
        Group(*blocks),
        title="[bold]Test trace[/bold]",
        border_style="cyan",
    )


def render_log_trace(pm: LogTracePM, *, ctx: RenderCtx):
    core = pm.core

    t = _kv_table(ctx)

    if getattr(ctx, "show_ids", False):
        t.add_row("art_id", Text(core.art_id, style="dim"))

    t.add_row("filename", Text(pm.filename or "-", style="bold"))

    t.add_row("iml_valid", _validity_text(core.iml_validity.iml_valid))
    if core.iml_validity.err:
        t.add_row("iml_error", Text(core.iml_validity.err, style="red"))

    if core.time:
        t.add_row("time", Text(core.time, style="dim"))

    blocks: list[object] = [t]

    if getattr(ctx, "show_code", True):
        blocks.append(_code_block("given : state", core.given, lang="ocaml"))
        if core.when:
            blocks.append(_code_block("when : action", core.when, lang="ocaml"))
        if core.then:
            blocks.append(_code_block("then : state", core.then, lang="ocaml"))

        if pm.contents:
            blocks.append(_code_block("log contents", pm.contents, lang="text"))

    return Panel(
        Group(*blocks),
        title="[bold]Log trace[/bold]",
        border_style="cyan",
    )