"""Rolling transcript of the conversation.

The speech bubble hides itself after a few seconds, which is fine for chat
but bad for anything you actually needed to read (a command's output, a
number, a URL). This keeps the last HISTORY_LIMIT turns so the tray's
History window — and click-to-copy on the bubble — have something to show.

Pure logic, no Qt: the UI half is ui/history_window.py.
"""

from __future__ import annotations

from collections import deque
from dataclasses import dataclass
from typing import Iterable, Optional

USER = "you"
PET = "bolt"
SYSTEM = "system"


@dataclass(frozen=True)
class Entry:
    role: str
    text: str
    timestamp: Optional[float] = None  # time.time(); None when not recorded

    def formatted(self, clock=None) -> str:
        label = {USER: "You", PET: "Bolt", SYSTEM: "—"}.get(self.role, self.role)
        stamp = clock(self.timestamp) if (clock and self.timestamp) else None
        return f"[{stamp}] {label}: {self.text}" if stamp else f"{label}: {self.text}"


class ConversationHistory:
    def __init__(self, limit: int = 100):
        self._entries: deque[Entry] = deque(maxlen=max(1, limit))

    def add(self, role: str, text: str, timestamp: Optional[float] = None) -> Optional[Entry]:
        text = (text or "").strip()
        if not text:
            return None
        entry = Entry(role=role, text=text, timestamp=timestamp)
        self._entries.append(entry)
        return entry

    def entries(self) -> list[Entry]:
        return list(self._entries)

    def last(self, role: Optional[str] = None) -> Optional[Entry]:
        for entry in reversed(self._entries):
            if role is None or entry.role == role:
                return entry
        return None

    def clear(self) -> None:
        self._entries.clear()

    def as_text(self, clock=None, entries: Optional[Iterable[Entry]] = None) -> str:
        return "\n".join(e.formatted(clock) for e in (entries if entries is not None else self._entries))

    def __len__(self) -> int:
        return len(self._entries)
