"""events.py: the small vocabulary of UX events an agent emits, and a terminal renderer.

The idea: instead of going quiet and returning one final blob, the agent EMITS events as it works.
A UI subscribes to the stream and shows each one, so the user sees progress, the answer appearing
live, citations, and the cost. Each event is just a dict with a "type". A real web UI consumes the
same events over Server-Sent Events (see app.py); here we render them to the terminal.

Event types:
  status   : a short progress note      {"type":"status","text":"searching the knowledge base"}
  tool     : a tool was called          {"type":"tool","name":"search_kb","query":"..."}
  citation : a source the answer used   {"type":"citation","id":"D1"}
  token    : a chunk of the answer       {"type":"token","text":"Dana "}
  cost     : final cost/latency report  {"type":"cost","usd":0.0006,"tokens":120}
  done     : the run finished            {"type":"done"}
  error    : something failed safely     {"type":"error","text":"service unavailable"}
"""

import sys


def status(text):     return {"type": "status", "text": text}
def tool(name, **kw): return {"type": "tool", "name": name, **kw}
def citation(doc_id): return {"type": "citation", "id": doc_id}
def token(text):      return {"type": "token", "text": text}
def cost(usd, tokens): return {"type": "cost", "usd": usd, "tokens": tokens}
def done():           return {"type": "done"}
def error(text):      return {"type": "error", "text": text}


def render(stream, out=sys.stdout):
    """Consume an event stream and show it like a simple UI would. Returns the assembled answer."""
    answer, cites = [], []
    for ev in stream:
        t = ev["type"]
        if t == "status":
            print(f"  ... {ev['text']}", file=out)
        elif t == "tool":
            extra = " ".join(f"{k}={v}" for k, v in ev.items() if k not in ("type", "name"))
            print(f"  [tool] {ev['name']} {extra}".rstrip(), file=out)
        elif t == "citation":
            cites.append(ev["id"])
        elif t == "token":
            answer.append(ev["text"])
            out.write(ev["text"]); out.flush()        # the live, token-by-token effect
        elif t == "cost":
            print(f"\n  [cost ${ev['usd']:.5f}, {ev['tokens']} tokens]", file=out)
        elif t == "error":
            print(f"\n  [error] {ev['text']}", file=out)
        elif t == "done":
            if cites:
                print(f"  [sources: {', '.join(cites)}]", file=out)
    return "".join(answer)
