"""Standalone mode: canonical event logger."""

import json
import sys
import time
import uuid
from dataclasses import dataclass, field
from typing import Any, TextIO


@dataclass
class StandaloneEvent:
    """Canonical Kivot event in standalone mode."""

    type: str  # "run.started", "model.delta", etc.
    run_id: str
    seq: int
    ts: float  # seconds since run start
    payload: dict


class StandaloneEventLogger:
    """Formats and prints canonical events to stderr."""

    def __init__(self, run_id: str, *, output: TextIO | None = None) -> None:
        self._run_id = run_id
        self._output = output if output is not None else sys.stderr
        self._seq = 0
        self._start_time = time.monotonic()
        self._events: list[StandaloneEvent] = []

    def emit(self, event_type: str, **payload: Any) -> StandaloneEvent:
        self._seq += 1
        event = StandaloneEvent(
            type=event_type,
            run_id=self._run_id,
            seq=self._seq,
            ts=time.monotonic() - self._start_time,
            payload=payload,
        )
        self._events.append(event)
        self._print(event)
        return event

    @property
    def events(self) -> list[StandaloneEvent]:
        return list(self._events)

    def _print(self, event: StandaloneEvent) -> None:
        type_col = f"[{event.type}]".ljust(24)
        detail = self._format_detail(event)
        print(f"{type_col} {detail}", file=self._output)

    def _format_detail(self, event: StandaloneEvent) -> str:
        p = event.payload
        match event.type:
            case "run.started":
                return f"run_id={event.run_id} (standalone mode)"
            case "model.start":
                return f"model={p.get('model', '?')}"
            case "model.delta":
                text = p.get("text", "")
                truncated = (text[:60] + "...") if len(text) > 60 else text
                return f'"{truncated}"'
            case "model.end":
                return f"model={p.get('model', '?')}"
            case "tool.call.started":
                tool = p.get("tool_name", "?")
                args = p.get("arguments", {})
                return f"tool={tool}, args={_compact_json(args)}"
            case "tool.call.completed":
                tool = p.get("tool_name", "?")
                result_str = str(p.get("result", ""))
                truncated = (result_str[:60] + "...") if len(result_str) > 60 else result_str
                dur = p.get("duration_ms", 0)
                return f'tool={tool}, result="{truncated}", duration={dur:.1f}ms'
            case "message.emitted":
                content = p.get("content", "")
                truncated = (content[:80] + "...") if len(content) > 80 else content
                return f'"{truncated}"'
            case "run.completed":
                dur = p.get("duration_s", 0)
                tokens = p.get("total_tokens", 0)
                cost = p.get("cost_usd", 0)
                return f"duration={dur:.1f}s, tokens={tokens}, cost=${cost:.4f}"
            case "run.failed":
                return f"error={p.get('error', 'unknown')}"
            case "agent.updated":
                return f"agent={p.get('agent', '?')}"
            case _:
                return str(p)


def _compact_json(obj: Any) -> str:
    """Compact JSON for terminal display."""
    if isinstance(obj, str):
        try:
            obj = json.loads(obj)
        except (json.JSONDecodeError, TypeError):
            return obj
    return json.dumps(obj, ensure_ascii=False, separators=(",", ":"))


def generate_local_run_id() -> str:
    """Generate a ULID-like local run ID."""
    ts_hex = f"{int(time.time() * 1000):012x}"
    rand = uuid.uuid4().hex[:10]
    return f"local_{ts_hex}{rand}"
