"""Per-seat usage metering — the *tracking* half of the metering spine
(docs/ROADMAP.md High-posture): who called how many tools, when. Paired with the
gateway's *dollar* metering (per-tenant virtual key), it gives per-tenant tokens
AND dollars (docs/V5-RACK-RUNTIME.md §6, P4).

In-memory + thread-safe (the server is threaded). Counts reset on restart by
design — the rack's collector polls ``usage_report`` on an interval and
accumulates the rollup externally (a single-tenant brain's rollup IS that
tenant's usage), so durability lives in the ledger, not here.
"""
import threading
from datetime import datetime, timezone


def _now() -> str:
    return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")


class UsageMeter:
    """Per-seat tool-call counts + first/last timestamps + a per-tool breakdown."""

    def __init__(self):
        self._lock = threading.Lock()
        self._seats = {}
        self._started = _now()

    def record(self, seat_id, tool_name) -> None:
        with self._lock:
            s = self._seats.get(seat_id)
            now = _now()
            if s is None:
                s = {"calls": 0, "first": now, "last": now, "by_tool": {}}
                self._seats[seat_id] = s
            s["calls"] += 1
            s["last"] = now
            s["by_tool"][tool_name] = s["by_tool"].get(tool_name, 0) + 1

    def snapshot(self) -> dict:
        with self._lock:
            seats = {sid: {"calls": s["calls"], "first": s["first"],
                           "last": s["last"], "by_tool": dict(s["by_tool"])}
                     for sid, s in self._seats.items()}
        totals = {"calls": 0, "by_tool": {}}
        for s in seats.values():
            totals["calls"] += s["calls"]
            for tool, n in s["by_tool"].items():
                totals["by_tool"][tool] = totals["by_tool"].get(tool, 0) + n
        return {"since": self._started, "as_of": _now(), "seats": seats, "totals": totals}
