"""Lightweight runtime metrics utilities."""

from __future__ import annotations

import time
from collections import deque
from dataclasses import dataclass, field
from typing import Any, Deque, Dict, Iterable, Optional, Tuple

from hieromem_core.events import EventType


@dataclass
class RollingCounter:
    """Accumulates counts over a sliding time window."""

    window_s: int = 300
    _events: Deque[Tuple[float, int]] = field(default_factory=deque)

    def add(self, delta: int = 1, ts: Optional[float] = None) -> None:
        now = ts or time.time()
        self._events.append((now, delta))
        self._evict(now)

    def count(self, now: Optional[float] = None) -> int:
        current = now or time.time()
        self._evict(current)
        return sum(delta for _, delta in self._events)

    def rate(self, now: Optional[float] = None) -> float:
        current = now or time.time()
        self._evict(current)
        if not self.window_s:
            return float(self.count(current))
        return self.count(current) / float(self.window_s)

    def _evict(self, now: float) -> None:
        cutoff = now - self.window_s
        while self._events and self._events[0][0] < cutoff:
            self._events.popleft()


def recent_event_count(events: Iterable[Any], window_s: int = 300) -> int:
    """Count events whose timestamps fall within the provided window."""

    cutoff = time.time() - window_s
    total = 0
    for event in events:
        ts = getattr(event, "timestamp", None)
        if ts is None:
            continue
        if hasattr(ts, "timestamp"):
            event_ts = ts.timestamp()
        else:
            event_ts = float(ts)
        if event_ts >= cutoff:
            total += 1
    return total


def event_type_counter(
        events: Iterable[Any], *, window_s: int = 300) -> Dict[str, int]:
    """Return counts of events by type over the recent window."""

    cutoff = time.time() - window_s
    counts: Dict[str, int] = {}
    for event in events:
        ts = getattr(event, "timestamp", None)
        if ts is None:
            continue
        if hasattr(ts, "timestamp"):
            event_ts = ts.timestamp()
        else:
            event_ts = float(ts)
        if event_ts < cutoff:
            continue
        event_type = getattr(event, "event_type", None)
        if isinstance(event_type, EventType):
            key = event_type.value
        else:
            key = str(event_type)
        counts[key] = counts.get(key, 0) + 1
    return counts
