"""Append-only JSONL event logger."""

from __future__ import annotations

import json
from datetime import datetime, timezone
from pathlib import Path


class EventLogger:
    """Write structured events to a JSONL file.

    Each event is a JSON object on its own line with a ``timestamp`` and
    ``type`` field prepended automatically. By default, events also include
    ``elapsed_s`` relative to the logger's ``start_time``.

    Usage::

        logger = EventLogger(Path("runs/my-run/events.jsonl"))
        logger.log("tool_start", tool="bash", input="ls -la")
        logger.log("tool_end", tool="bash", output="...")
        logger.close()

    The file can be read back with :meth:`read`::

        events = EventLogger.read(Path("runs/my-run/events.jsonl"))
    """

    def __init__(
        self,
        path: Path,
        *,
        start_time: datetime | None = None,
        include_elapsed_s: bool = True,
    ) -> None:
        self.path = path
        self.path.parent.mkdir(parents=True, exist_ok=True)
        self._fh = self.path.open("a")
        self.start_time = start_time or datetime.now(timezone.utc)
        self.include_elapsed_s = include_elapsed_s

    def log(self, event_type: str, **kwargs: object) -> None:
        """Append one event."""
        now = datetime.now(timezone.utc)
        record = {
            "timestamp": now.isoformat(),
            "type": event_type,
            **kwargs,
        }
        if self.include_elapsed_s:
            record["elapsed_s"] = round((now - self.start_time).total_seconds(), 3)
        self._fh.write(json.dumps(record) + "\n")
        self._fh.flush()

    def close(self) -> None:
        self._fh.close()

    def __enter__(self) -> "EventLogger":
        return self

    def __exit__(self, *_: object) -> None:
        self.close()

    @staticmethod
    def read(path: Path) -> list[dict]:
        """Read all events from a JSONL file. Returns [] if the file doesn't exist."""
        if not path.exists():
            return []
        events = []
        for line in path.read_text().splitlines():
            line = line.strip()
            if line:
                try:
                    events.append(json.loads(line))
                except json.JSONDecodeError:
                    pass
        return events
