"""Console reporter: one narrative, two destinations.

Every line an ADW prints ALSO lands in the db as a `log` event, so the swim-lane
UI reads the same story the terminal does. Both go through `_emit` — print and
trace cannot drift. Plain sequential lines only: no spinners, no live displays,
so a CI log reads exactly like a terminal.
"""

from __future__ import annotations

from rich.console import Console as RichConsole
from rich.markup import escape
from rich.panel import Panel
from rich.text import Text

from .data_types import EnvelopeBase, EventRecord, Phase

KIND_COLOR = {"engineer": "cyan", "agent": "magenta", "code": "yellow"}
MAX_LINE = 160          # dynamic text (summaries, violations, errors) is clipped


def _clip(text: str, limit: int = MAX_LINE) -> str:
    text = " ".join(str(text).split())
    return text if len(text) <= limit else text[: limit - 1] + "…"


class Console:
    """Bound to one run's tracer. Reachable as `run.console` everywhere."""

    def __init__(self, tracer, adw_id: str):
        self.tracer = tracer
        self.adw_id = adw_id
        self.phase_id = ""          # current lane — log events attach to it
        self.phase_name = ""
        self.results: list[str] = []            # phase statuses, for the summary
        self._finished = False                  # the summary panel prints once
        self._out = RichConsole(highlight=False, soft_wrap=True)

    # ── the one helper: print AND trace, always together ────────────────────
    def _emit(self, markup: str, level: str = "info", renderable=None) -> None:
        text = Text.from_markup(markup)
        self._out.print(renderable if renderable is not None else text)
        self.tracer.event(EventRecord(
            adw_id=self.adw_id, phase_id=self.phase_id, type="log",
            name=self.phase_name or "console",
            payload={"message": text.plain, "level": level}))

    # ── session ─────────────────────────────────────────────────────────────
    def session_started(self, adw_id: str, engineer: str) -> None:
        self._emit(f"[bold cyan]adw_id:[/bold cyan] [bold]{escape(adw_id)}[/bold]"
                   f"   [dim]engineer[/dim] {escape(engineer)}")

    def session_finished(self, ok: bool, tokens: int, cost: float, db_path: str) -> None:
        if self._finished:
            return
        self._finished = True
        passed = sum(1 for r in self.results if r == "success")
        status = "[green]✓ success[/green]" if ok else "[red]✗ fail[/red]"
        rows = [f" [dim]status[/dim]   {status}",
                f" [dim]phases[/dim]   {passed}/{len(self.results)} passed",
                f" [dim]tokens[/dim]   {tokens:,}",
                f" [dim]cost[/dim]     ${cost:.4f}",
                f" [dim]adw_id[/dim]   {escape(self.adw_id)}",
                f" [dim]db[/dim]       {escape(str(db_path))}",
                f" [dim]next[/dim]     [bold]just phases {escape(self.adw_id)}[/bold]"]
        panel = Panel(Text.from_markup("\n".join(rows)),
                      title="[bold]ADW complete[/bold]",
                      border_style="green" if ok else "red", expand=False)
        plain = (f"session {self.adw_id} {'success' if ok else 'fail'} · "
                 f"{passed}/{len(self.results)} phases · {tokens:,} tokens · ${cost:.4f}")
        self._emit(escape(plain), level="info" if ok else "error", renderable=panel)

    # ── phases ──────────────────────────────────────────────────────────────
    def phase_started(self, phase: Phase) -> None:
        self.phase_id, self.phase_name = phase.phase_id, phase.params.name
        p = phase.params
        color = KIND_COLOR.get(p.kind, "white")
        line = (f"[bold {color}]▶ {phase.seq:02d} {escape(p.name)}[/bold {color}]"
                f"  [{color}]{p.kind}[/{color}] [dim]· {escape(p.owner)}[/dim]")
        if p.description:
            line += f"  [dim]{escape(_clip(p.description))}[/dim]"
        self._emit(line)

    def phase_ended(self, phase: Phase, seconds: float) -> None:
        ok = phase.status == "success"
        self.results.append(phase.status)
        line = (f"  {'[green]✓[/green]' if ok else '[red]✗[/red]'} "
                f"{escape(phase.params.name)} [dim]{seconds:.1f}s[/dim]")
        if not ok and phase.error:
            line += f"  [red]{escape(_clip(phase.error))}[/red]"
        self._emit(line, level="info" if ok else "error")
        self.phase_id, self.phase_name = "", ""

    def note(self, message: str) -> None:
        """Free-form detail inside the current phase — what `ph.log()` recorded."""
        self._emit(f"  [dim]· {escape(_clip(message))}[/dim]")

    # ── agents ──────────────────────────────────────────────────────────────
    def agent_started(self, name: str, model: str, session_id: str) -> None:
        self._emit(f"  [magenta]▸[/magenta] {escape(name)} [dim]{escape(model)}[/dim]"
                   f"  [dim]session {escape(session_id)}[/dim]")

    def agent_finished(self, name: str, tokens: int, cost: float) -> None:
        self._emit(f"  [dim]└ {escape(name)} used {tokens:,} tokens · ${cost:.4f}[/dim]")

    def retry(self, name: str, attempt: int, limit: int, reason: str) -> None:
        self._emit(f"  [yellow]⟳[/yellow] {escape(name)} retry {attempt}/{limit} "
                   f"[dim]— same session · {escape(_clip(reason))}[/dim]", level="warn")

    # ── verification ────────────────────────────────────────────────────────
    def gate_result(self, name: str, report) -> None:
        """A gate reports WHAT it checked, not just whether it passed."""
        ok = report.passed
        mark = "[green]✓[/green]" if ok else "[red]✗[/red]"
        summary = (f"{len(report.checks)} checked" if ok
                   else f"[red]{len(report.violations)} of {len(report.checks)} failed[/red]")
        self._emit(f"  {mark} gate [dim]{escape(name)}[/dim] [dim]{summary}[/dim]",
                   level="info" if ok else "error")
        for check in report.checks:
            style = "dim" if check.ok else "dim red"
            detail = f" — {_clip(check.note)}" if check.note else ""
            self._emit(f"    [{style}]{'·' if check.ok else '✗'} {escape(_clip(check.item))}"
                       f"{escape(detail)}[/{style}]", level="info" if check.ok else "error")

    def envelope_summary(self, envelope: EnvelopeBase) -> None:
        ok = envelope.status == "success"
        line = (f"  {'[green]✓[/green]' if ok else '[red]✗[/red]'} "
                f"{type(envelope).__name__} [dim]{escape(_clip(envelope.summary))}[/dim]")
        self._emit(line, level="info" if ok else "error")
        if envelope.artifacts:
            self._emit(f"    [dim]artifacts: {escape(_clip(', '.join(envelope.artifacts)))}[/dim]")
