"""Visual primitives for the darwin.agenticcloud CLI.

Brand colors (referenced semantically, not decoratively):
- bright green #00ff01 ▸ verified, success, ready
- amber #fdb515       ▸ alpha, warning, pending
- dim gray            ▸ secondary metadata
- black background    ▸ surface

Rich does not let us pick exact hex on every terminal, but it gracefully
degrades. We use bright green for the brand accents and yellow for amber.
"""

from __future__ import annotations

import hashlib
import time
from dataclasses import dataclass
from datetime import UTC, datetime

from rich.console import Console, Group
from rich.live import Live
from rich.panel import Panel
from rich.text import Text

# -------------------------------------------------------------------
# Brand
# -------------------------------------------------------------------

BRAND_GREEN = "#00ff01"
BRAND_AMBER = "#fdb515"
BRAND_DIM = "#6a6a6a"

# Block-letter banner — produced by `figlet -f ANSI Shadow DARWIN`,
# stored as a literal so we have zero runtime dependency on figlet.
BANNER = r"""██████╗  █████╗ ██████╗ ██╗    ██╗██╗███╗   ██╗
██╔══██╗██╔══██╗██╔══██╗██║    ██║██║████╗  ██║
██║  ██║███████║██████╔╝██║ █╗ ██║██║██╔██╗ ██║
██║  ██║██╔══██║██╔══██╗██║███╗██║██║██║╚██╗██║
██████╔╝██║  ██║██║  ██║╚███╔███╔╝██║██║ ╚████║
╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝ ╚══╝╚══╝ ╚═╝╚═╝  ╚═══╝"""


# -------------------------------------------------------------------
# Banner
# -------------------------------------------------------------------


def render_banner(
    version: str,
    schema: str,
    signer_key_id: str | None = None,
    substrate_id: str = "local-docker-v0",
) -> Group:
    """Branded ASCII banner with version / schema / signer footer."""
    parts: list = [Text(BANNER, style=f"bold {BRAND_GREEN}")]
    parts.append(Text(""))

    tagline = Text()
    tagline.append("  verifiable compute for AI agents", style=BRAND_DIM)
    tagline.append("               ")
    tagline.append(f"v{version}", style=f"bold {BRAND_AMBER}")
    parts.append(tagline)

    schema_line = Text()
    schema_line.append("  schema  ", style=BRAND_DIM)
    schema_line.append(schema, style=BRAND_AMBER)
    parts.append(schema_line)

    if signer_key_id:
        signer_line = Text()
        signer_line.append("  signer  ", style=BRAND_DIM)
        signer_line.append(signer_key_id, style=BRAND_GREEN)
        signer_line.append("  ·  ", style=BRAND_DIM)
        signer_line.append("substrate  ", style=BRAND_DIM)
        signer_line.append(substrate_id, style=BRAND_GREEN)
        parts.append(signer_line)

    return Group(*parts)


def print_banner(
    console: Console,
    version: str,
    schema: str,
    signer_key_id: str | None = None,
    substrate_id: str = "local-docker-v0",
) -> None:
    """Convenience: print the banner with appropriate vertical spacing."""
    console.print()
    console.print(render_banner(version, schema, signer_key_id, substrate_id))
    console.print()


# -------------------------------------------------------------------
# First-run welcome
# -------------------------------------------------------------------


def render_welcome(
    version: str,
    demo_url: str = "https://darwin-agentic-cloud.fly.dev/demo",
    repo_url: str = "https://github.com/vje013/darwin-agentic-cloud",
    docs_url: str = "https://darwin-agentic-cloud.fly.dev/docs",
) -> Group:
    """First-run welcome: ASCII banner + tagline + 3 commands + links.

    Visually distinct from `render_banner()` (which prints version/signer
    metadata for repeat users). Designed to orient a new user in their
    first 30 seconds with the tool.
    """
    parts: list = []

    parts.append(Text(BANNER, style=f"bold {BRAND_GREEN}"))
    parts.append(Text(""))

    motto = Text()
    motto.append("  ")
    motto.append("✦", style=f"bold {BRAND_AMBER}")
    motto.append("  SECURITAS · STABILITAS · SIGNUM  ", style=BRAND_GREEN)
    motto.append("✦", style=f"bold {BRAND_AMBER}")
    parts.append(motto)
    parts.append(Text(""))

    parts.append(Text("  Verifiable and free compute for AI agents.", style=f"bold {BRAND_GREEN}"))
    parts.append(
        Text("  Cryptographically signed execution attestations.", style=f"bold {BRAND_GREEN}")
    )
    parts.append(Text("  MCP-native.", style=f"bold {BRAND_GREEN}"))
    parts.append(Text(""))

    parts.append(Text("  " + "─" * 59, style=BRAND_DIM))
    parts.append(Text(""))

    parts.append(Text("  Try it in 3 commands:", style=f"bold {BRAND_GREEN}"))
    parts.append(Text(""))

    cmd1 = Text("    1.  ", style=f"bold {BRAND_GREEN}")
    cmd1.append("darwin list", style=f"bold {BRAND_GREEN}")
    parts.append(cmd1)
    parts.append(
        Text("        See which compute substrates are available right now.", style=BRAND_GREEN)
    )
    parts.append(Text(""))

    cmd2 = Text("    2.  ", style=f"bold {BRAND_GREEN}")
    cmd2.append("echo 'print(\"hello\")' > hello.py", style=BRAND_GREEN)
    parts.append(cmd2)
    parts.append(Text("        darwin run hello.py --save att.json", style=f"bold {BRAND_GREEN}"))
    parts.append(Text("        Execute a workload, get a signed attestation.", style=BRAND_GREEN))
    parts.append(Text(""))

    cmd3 = Text("    3.  ", style=f"bold {BRAND_GREEN}")
    cmd3.append("darwin verify att.json", style=f"bold {BRAND_GREEN}")
    parts.append(cmd3)
    parts.append(
        Text("        Cryptographically verify the attestation against", style=BRAND_GREEN)
    )
    parts.append(Text("        the public keylist.", style=BRAND_GREEN))
    parts.append(Text(""))

    parts.append(Text("  " + "─" * 59, style=BRAND_DIM))
    parts.append(Text(""))

    link_demo = Text("  Live demo:  ", style=BRAND_GREEN)
    link_demo.append(demo_url, style=f"underline {BRAND_GREEN}")
    parts.append(link_demo)

    link_repo = Text("  GitHub:     ", style=BRAND_GREEN)
    link_repo.append(repo_url, style=f"underline {BRAND_GREEN}")
    parts.append(link_repo)

    link_docs = Text("  Docs:       ", style=BRAND_GREEN)
    link_docs.append(docs_url, style=f"underline {BRAND_GREEN}")
    parts.append(link_docs)

    parts.append(Text(""))

    parts.append(Text("  This message shown once per install.", style=BRAND_DIM))
    parts.append(Text("  Run `darwin welcome` to see it again.", style=BRAND_DIM))

    return Group(*parts)


def print_welcome(console: Console, version: str) -> None:
    """Convenience: print the welcome with appropriate vertical spacing."""
    console.print()
    console.print(render_welcome(version=version))
    console.print()


# -------------------------------------------------------------------
# Matrix boot sequence
# -------------------------------------------------------------------


@dataclass(frozen=True)
class BootStep:
    label: str
    delay: float = 0.08  # seconds before next step appears


def matrix_boot(
    console: Console,
    steps: list[BootStep],
    suppress_tty_check: bool = False,
) -> None:
    """Stream lines of the form `> {label} ......... ok` one at a time.

    If not running in a TTY (CI, logs, redirected stdout), we skip the
    animation and just print each line instantly. The Karpathy/Matrix
    aesthetic should not break grep'ing logs.
    """
    is_tty = suppress_tty_check or (console.is_terminal and not console.is_jupyter)
    width = max(len(s.label) for s in steps)

    for step in steps:
        # `> step .......... ok`
        dots = "." * max(3, 56 - width - len(step.label))
        line = Text()
        line.append("> ", style=BRAND_DIM)
        line.append(step.label, style="white")
        line.append(f" {dots} ", style=BRAND_DIM)
        line.append("ok", style=f"bold {BRAND_GREEN}")
        console.print(line)
        if is_tty:
            time.sleep(step.delay)


# -------------------------------------------------------------------
# Single-line progressive ticker
# -------------------------------------------------------------------


class StepLine:
    """One line that updates in-place, then renders final state.

    Usage:
        with StepLine(console, "darwin.agenticcloud · running workload") as step:
            step.tick("budget")
            ...do work...
            step.tick("sandbox")
            ...
        # When the context exits, last state stays printed.
    """

    def __init__(self, console: Console, header: str) -> None:
        self.console = console
        self.header = header
        self.ticks: list[str] = []
        self._live: Live | None = None
        self._is_tty = console.is_terminal and not console.is_jupyter

    def __enter__(self) -> StepLine:
        if self._is_tty:
            self._live = Live(
                self._render(),
                console=self.console,
                refresh_per_second=12,
                transient=False,
            )
            self._live.__enter__()
        else:
            self.console.print(self._header_text())
        return self

    def __exit__(self, exc_type, exc, tb) -> None:
        if self._live is not None:
            self._live.update(self._render())
            self._live.__exit__(exc_type, exc, tb)

    def tick(self, label: str) -> None:
        """Add a tick and re-render."""
        self.ticks.append(label)
        if self._live is not None:
            self._live.update(self._render())
        else:
            # non-TTY: each tick on its own line
            self.console.print(self._tick_text(label, finished=True))

    def _header_text(self) -> Text:
        t = Text()
        t.append("▶ ", style=f"bold {BRAND_GREEN}")
        t.append(self.header)
        return t

    def _tick_text(self, label: str, finished: bool) -> Text:
        t = Text()
        t.append("  ╴ ", style=BRAND_DIM)
        t.append(label)
        t.append(" ", style=BRAND_DIM)
        t.append("✓", style=f"bold {BRAND_GREEN}")
        return t

    def _render(self) -> Group:
        if not self.ticks:
            return Group(self._header_text())
        body = Text()
        for i, label in enumerate(self.ticks):
            if i > 0:
                body.append("  ", style=BRAND_DIM)
            body.append("╴ ", style=BRAND_DIM)
            body.append(label)
            body.append(" ", style=BRAND_DIM)
            body.append("✓", style=f"bold {BRAND_GREEN}")
        return Group(self._header_text(), Text("  ").append_text(body))


# -------------------------------------------------------------------
# Attestation panel
# -------------------------------------------------------------------


def render_attestation_panel(
    workload_hash: str,
    output_hash: str,
    substrate: str,
    signer_key_id: str,
    cost_usd: float,
    cost_cap_usd: float,
    verified: bool = True,
    schema_short: str = "v0.1",
    *,
    attestation_id: str | None = None,
    issued_at: float | None = None,
    public_key_b64: str | None = None,
    schema_full: str = "darwin.cloud/agenticcloud/attestation/v0.1",
    version: str = "0.1.0",
) -> Panel:
    """Branded panel showing the signed attestation contents.

    The optional keyword-only params (attestation_id, issued_at, public_key_b64,
    schema_full, version) make the panel a credible "receipt" — they're the
    fields a verifier would actually inspect.
    """
    body = Text()

    # Identity block
    if attestation_id:
        body.append("id           ", style=BRAND_DIM)
        body.append(_short_id(attestation_id), style="white")
        body.append("\n")
    if issued_at is not None:
        body.append("issued       ", style=BRAND_DIM)
        body.append(_fmt_timestamp(issued_at), style="white")
        body.append("\n")
    if attestation_id or issued_at is not None:
        body.append("\n")

    # Execution block
    body.append("workload     ", style=BRAND_DIM)
    body.append(_short_hash(workload_hash), style="white")
    body.append("\n")
    body.append("output       ", style=BRAND_DIM)
    body.append(_short_hash(output_hash), style="white")
    body.append("\n")
    body.append("substrate    ", style=BRAND_DIM)
    body.append(substrate, style=BRAND_AMBER)
    body.append("\n")
    body.append("\n")

    # Cryptography block
    body.append("signer       ", style=BRAND_DIM)
    body.append(signer_key_id, style=BRAND_GREEN)
    body.append("\n")
    if public_key_b64:
        body.append("fingerprint  ", style=BRAND_DIM)
        body.append(_fmt_fingerprint(public_key_b64), style="white")
        body.append("\n")
    body.append("cost         ", style=BRAND_DIM)
    body.append(f"${_fmt_cost(cost_usd)}", style="white")
    body.append(" / ", style=BRAND_DIM)
    body.append(f"${_fmt_cost(cost_cap_usd)}", style=BRAND_DIM)
    body.append("\n")
    body.append("\n")

    # Verification line
    if verified:
        body.append("✓ ", style=f"bold {BRAND_GREEN}")
        body.append("signature verified", style="white")
    else:
        body.append("✗ ", style=f"bold {BRAND_AMBER}")
        body.append("signature unverified", style=BRAND_AMBER)
    body.append("\n")
    body.append("schema       ", style=BRAND_DIM)
    body.append(schema_full, style=BRAND_AMBER)

    # Footer subtitle inside the panel border
    subtitle = (
        f"[dim]darwin.cloud — verifiable compute for AI agents[/dim]"
        f"   [{BRAND_AMBER}]v{version}[/{BRAND_AMBER}]"
    )

    return Panel(
        body,
        title="[bold]attestation · darwin.agenticcloud[/bold]",
        subtitle=subtitle,
        border_style=BRAND_GREEN,
        padding=(1, 2),
    )


def _short_hash(h: str) -> str:
    """sha256:7b3f4a2e8c1d5f9a -> sha256:7b3f...c91a"""
    if ":" in h:
        prefix, body = h.split(":", 1)
    else:
        prefix, body = "sha256", h
    if len(body) <= 16:
        return f"{prefix}:{body}"
    return f"{prefix}:{body[:8]}...{body[-4:]}"


def _fmt_cost(usd: float) -> str:
    """Format USD cost with enough precision to actually see sub-cent values.

    < $0.01     → 6 digits (e.g. $0.000018)
    < $1        → 4 digits (e.g. $0.0240)
    >= $1       → 2 digits (e.g. $12.50)
    """
    if usd < 0.01:
        return f"{usd:.6f}"
    if usd < 1:
        return f"{usd:.4f}"
    return f"{usd:.2f}"


def _short_id(att_id: str) -> str:
    """Make attestation IDs readable.

    UUID-shaped IDs are truncated to 12 hex chars.
    Demo/manual IDs (att_demo_...) are passed through as-is so the
    substrate name stays legible.
    """
    raw = att_id.removeprefix("att_")
    # UUID = 32 hex chars (with or without hyphens). If it looks like one,
    # shorten. Otherwise leave it alone.
    hex_only = raw.replace("-", "")
    if len(hex_only) >= 32 and all(c in "0123456789abcdef" for c in hex_only.lower()):
        return f"att_{hex_only[:12]}"
    return att_id


def _fmt_timestamp(unix_ts: float) -> str:
    """Unix timestamp → ISO 8601 UTC string."""
    return datetime.fromtimestamp(unix_ts, tz=UTC).strftime("%Y-%m-%dT%H:%M:%SZ")


def _fmt_fingerprint(public_key_b64: str) -> str:
    """Shorten a base64-encoded public key into a canonical-looking fingerprint.

    ed25519:1de8debf02823...d0fc — first 13 + last 4 hex chars of sha256.
    """
    digest = hashlib.sha256(public_key_b64.encode("utf-8")).hexdigest()
    return f"ed25519:{digest[:13]}...{digest[-4:]}"


def signature_animation(console: Console, frames: float = 0.4) -> None:
    """Frame-by-frame signing animation, shown only on TTY.

    Renders a short '...verifying ed25519........' that gets a check mark.
    Total wall time is `frames` seconds. Pure cosmetic; signing happens in
    the actual signer module synchronously.
    """
    if not (console.is_terminal and not console.is_jupyter):
        return
    spinner_chars = ["╱", "─", "╲", "│"]  # noqa: RUF001
    n = int(frames / 0.06)
    for i in range(n):
        char = spinner_chars[i % len(spinner_chars)]
        dots = "." * min(7, i + 1)
        line = Text()
        line.append("  ▸ signing attestation  ", style="white")
        line.append(char, style=f"bold {BRAND_GREEN}")
        line.append(f" verifying ed25519 {dots}", style=BRAND_DIM)
        console.print(line, end="\r")
        time.sleep(0.06)
    # final state
    final = Text()
    final.append("  ▸ signing attestation  ", style="white")
    final.append("✓", style=f"bold {BRAND_GREEN}")
    final.append(" verifying ed25519 .......", style=BRAND_DIM)
    final.append(" ", style=BRAND_DIM)
    final.append("✓", style=f"bold {BRAND_GREEN}")
    console.print(final)


# -------------------------------------------------------------------
# Configuration receipt (used by `darwin mcp install`)
# -------------------------------------------------------------------


def render_mcp_install_receipt(
    config_path: str,
    server_name: str,
    python_interpreter: str,
    tool_names: list[str],
    sample_prompt: str = ('"use dac_run_python to compute 2+2 and show me the signer key id"'),
) -> Group:
    """The configuration receipt shown after a successful `darwin mcp install`."""
    parts: list = []

    body = Text()
    body.append("  ▸ Claude Desktop config installed\n", style="white")
    body.append("    ", style=BRAND_DIM)
    body.append(config_path, style=BRAND_AMBER)
    body.append("\n")
    body.append("  ▸ Server name        ", style="white")
    body.append(server_name, style=BRAND_GREEN)
    body.append("\n")
    body.append("  ▸ Python interpreter ", style="white")
    body.append(python_interpreter, style=BRAND_DIM)
    body.append("\n")
    body.append("  ▸ MCP tools exposed  ", style="white")
    body.append(str(len(tool_names)), style=BRAND_GREEN)
    body.append(" (", style=BRAND_DIM)
    body.append(", ".join(tool_names), style=BRAND_AMBER)
    body.append(")", style=BRAND_DIM)
    parts.append(body)

    parts.append(Text(""))
    parts.append(Text("  next ──────────────────────────────────────────────────", style=BRAND_DIM))

    nxt = Text()
    nxt.append("    1. ", style=BRAND_DIM)
    nxt.append("quit and restart Claude Desktop ", style="white")
    nxt.append("(cmd-q on macOS)", style=BRAND_DIM)
    nxt.append("\n")
    nxt.append("    2. ", style=BRAND_DIM)
    nxt.append("in any chat, ask:\n", style="white")
    nxt.append("       ")
    nxt.append(sample_prompt, style=f"italic {BRAND_AMBER}")
    parts.append(nxt)

    parts.append(Text(""))
    final = Text()
    final.append("  ✓ ", style=f"bold {BRAND_GREEN}")
    final.append("darwin substrate connected to claude.", style="white")
    parts.append(final)

    return Group(*parts)


# -------------------------------------------------------------------
# v0.2 attestation panel — polymorphic substrate block
# -------------------------------------------------------------------


def render_v02_attestation_panel(attestation: dict) -> Panel:
    """Engraved-certificate renderer for v0.2 attestations.

    Aesthetic: pre-1970s stock certificate, USPS certified mail,
    Pony Express station stamps. Full-center alignment, double-line
    borders, diamond dividers, gold seal markers.
    """
    from rich.align import Align
    from rich.box import DOUBLE_EDGE
    from rich.console import Group

    GOLD = "#ffb86c"
    SEPIA = "#d4a574"
    DIAMOND = " ─ ◊ ─ ◊ ─ ◊ ─ ◊ ─ ◊ ─ ◊ ─ ◊ ─ ◊ ─ ◊ ─ ◊ ─ ◊ ─ ◊ ─ ◊ ─ ◊ ─ ◊ "
    MOTTO = "✦ SECURITAS · STABILITAS · SIGNUM ✦"

    exec_result = attestation.get("execution_result", {})
    substrate = exec_result.get("substrate", {})
    evidence = substrate.get("evidence", {})
    vas = attestation.get("value_added_service") or {}

    parts: list = []

    # --- Motto + Certificate No. ---
    parts.append(Align.center(Text(MOTTO, style="bold " + GOLD)))
    parts.append(Text(""))
    cert_no = attestation.get("attestation_id", "").upper().removeprefix("ATT_")
    cert_line = Text()
    cert_line.append("CERTIFICATE No. ", style="bold " + GOLD)
    cert_line.append(cert_no, style="bold white")
    parts.append(Align.center(cert_line))
    parts.append(Text(""))

    # --- Identity block ---
    for label, value in [
        ("issued", attestation.get("issued_at", "")),
        ("workload", _short_hash(attestation.get("workload_spec_hash", ""))),
        ("output", _short_hash(exec_result.get("output_hash", ""))),
        ("cost", "$" + _fmt_cost(exec_result.get("cost_usd", 0.0))),
    ]:
        line = Text()
        line.append(label + "  ", style=BRAND_DIM)
        line.append(value, style="white")
        parts.append(Align.center(line))
    parts.append(Text(""))
    parts.append(Align.center(Text(DIAMOND, style=GOLD)))
    parts.append(Text(""))

    # --- Substrate block ---
    for label, value, vstyle in [
        ("substrate", substrate.get("id", "?"), BRAND_AMBER),
        ("schema", substrate.get("evidence_schema_id", "?"), BRAND_AMBER),
        ("sub-signer", substrate.get("identity_signer_key_id", "?"), BRAND_GREEN),
    ]:
        line = Text()
        line.append(label + "  ", style=BRAND_DIM)
        line.append(value, style=vstyle)
        parts.append(Align.center(line))
    parts.append(Text(""))

    # --- Evidence ---
    if evidence:
        parts.append(Align.center(Text("evidence", style=BRAND_DIM)))
        for key in sorted(evidence.keys()):
            val = evidence[key]
            line = Text()
            line.append(key + "  ", style=BRAND_DIM)
            line.append(_fmt_evidence_value(key, val), style="white")
            parts.append(Align.center(line))
        parts.append(Text(""))

    # --- Value-Added Service block ---
    if vas:
        parts.append(Align.center(Text("value-added", style=BRAND_DIM)))
        cce = vas.get("cost_cap_enforcement") or {}
        if cce:
            within = bool(cce.get("within_cap", False))
            marker = "✓" if within else "⚠"
            mstyle = "bold " + (GOLD if within else BRAND_AMBER)
            line = Text()
            line.append(marker + "  ", style=mstyle)
            line.append("cost cap  ", style="white")
            line.append("$" + _fmt_cost(float(cce.get("actual_usd", 0.0))), style="white")
            line.append(" / ", style=BRAND_DIM)
            line.append("$" + _fmt_cost(float(cce.get("cap_usd", 0.0))), style=BRAND_DIM)
            parts.append(Align.center(line))
        rd = vas.get("routing_decision") or {}
        if rd:
            considered = rd.get("candidates_considered", 0)
            line = Text()
            line.append("→  ", style="bold " + GOLD)
            line.append("routed  ", style="white")
            line.append(rd.get("policy", "?"), style=BRAND_AMBER)
            line.append(" (1 picked from " + str(considered) + " eligible)", style=BRAND_DIM)
            parts.append(Align.center(line))
        ids = vas.get("identity_signing") or {}
        if ids:
            line = Text()
            line.append("✓  ", style="bold " + GOLD)
            line.append("identity  ", style="white")
            line.append("anchored to public keylist", style=BRAND_DIM)
            parts.append(Align.center(line))
        parts.append(Text(""))

    parts.append(Align.center(Text(DIAMOND, style=GOLD)))
    parts.append(Text(""))

    # --- Signed block ---
    outer_signer_key = attestation.get("signer_key_id")
    if outer_signer_key:
        parts.append(Align.center(Text("✓ ATTESTATION SIGNED", style="bold " + GOLD)))
        by_line = Text()
        by_line.append("by  ", style=BRAND_DIM)
        by_line.append(outer_signer_key, style=BRAND_GREEN)
        parts.append(Align.center(by_line))
        sch_line = Text()
        sch_line.append("schema  ", style=BRAND_DIM)
        sch_line.append(
            attestation.get("schema", "darwin.cloud/agenticcloud/attestation/v0.2"),
            style=BRAND_AMBER,
        )
        parts.append(Align.center(sch_line))
    else:
        parts.append(
            Align.center(Text("⚠ substrate signed; outer signature pending", style=BRAND_AMBER))
        )
    parts.append(Text(""))

    # --- Verify instructions ---
    parts.append(Align.center(Text("verify", style=BRAND_DIM)))
    parts.append(
        Align.center(
            Text(
                "1. curl darwin-agentic-cloud.fly.dev/.well-known/substrate-keys.json",
                style=SEPIA,
            )
        )
    )
    parts.append(
        Align.center(
            Text(
                "2. confirm sub-signer public key is present and active",
                style=SEPIA,
            )
        )
    )
    parts.append(
        Align.center(
            Text(
                "3. check identity_signature against the signed payload",
                style=SEPIA,
            )
        )
    )

    subtitle = (
        "[dim]darwin.cloud  ·  verifiable compute for AI agents  ·  v0.2.0[/dim]"
        "   [" + GOLD + "]✦[/" + GOLD + "]"
    )
    title = (
        "[" + GOLD + "]✦[/" + GOLD + "]  "
        "[bold " + GOLD + "]ATTESTATION OF EXECUTION[/bold " + GOLD + "]  "
        "[dim]·[/dim]  [bold]darwin.agenticcloud[/bold]  "
        "[" + GOLD + "]✦[/" + GOLD + "]"
    )
    return Panel(
        Group(*parts),
        title=title,
        subtitle=subtitle,
        border_style=BRAND_GREEN,
        box=DOUBLE_EDGE,
        padding=(1, 3),
    )


def _fmt_evidence_value(key: str, val) -> str:
    """Render an evidence value compactly.

    Hashes are truncated. Numbers are formatted. Strings are passed through
    with reasonable upper-bound length.
    """
    if val is None:
        return "—"
    if isinstance(val, bool):
        return "true" if val else "false"
    if isinstance(val, str):
        # Hashes (hex of length 64, with or without sha256: prefix)
        if key.endswith("_hash") or (
            len(val) == 64 and all(c in "0123456789abcdef" for c in val.lower())
        ):
            return _short_hash(val)
        if len(val) > 48:
            return f"{val[:36]}…"
        return val
    if isinstance(val, int | float):
        if key.endswith("_sec"):
            return f"{val:.3f}s"
        if key.endswith("_ms"):
            return f"{val}ms"
        if key.endswith("_mb"):
            return f"{val} MB"
        return str(val)
    return str(val)


# -------------------------------------------------------------------
# Dispatcher: pick v0.1 vs v0.2 by schema
# -------------------------------------------------------------------


def render_attestation_panel_auto(attestation: dict) -> Panel:
    """Render whichever attestation panel matches the schema.

    Callers (CLI, MCP, server) use this so they don't have to track
    the schema version themselves. Returns the v0.2 panel for new
    attestations and a v0.1 panel reconstructed from the old shape
    for backward compatibility.
    """
    schema = attestation.get("schema", "")
    if "v0.2" in schema:
        return render_v02_attestation_panel(attestation)

    # Fall back to v0.1 panel construction. The old panel takes
    # positional args; we marshal them here.
    exec_result = attestation.get("execution_result", {})
    return render_attestation_panel(
        workload_hash=attestation.get("workload_spec_hash", ""),
        output_hash=exec_result.get("output_hash", ""),
        substrate=exec_result.get("substrate_id", "?"),
        signer_key_id=attestation.get("signer_key_id", "?"),
        cost_usd=exec_result.get("cost_usd", 0.0),
        cost_cap_usd=attestation.get("workload_spec", {}).get("cost_cap_usd", 0.0),
        verified=True,
        attestation_id=attestation.get("attestation_id"),
        issued_at=attestation.get("issued_at"),
        schema_full=schema,
    )
