"""
Ring buffer for storing raw video frames.
Used to cut VAR clips when a close call is triggered.
"""

import threading
import numpy as np
from collections import deque
from typing import Optional, List, Tuple


class FrameRingBuffer:
    """Thread-safe ring buffer that stores the last N seconds of raw frames."""

    def __init__(self, max_seconds=10, fps=30):
        self.max_frames = max_seconds * fps
        self.fps = fps
        self.buffer = deque(maxlen=self.max_frames)
        self.lock = threading.Lock()
        self.frame_count = 0

    def push(self, frame: np.ndarray, timestamp: float, sensor_id: int):
        with self.lock:
            self.buffer.append((frame.copy(), timestamp, sensor_id, self.frame_count))
            self.frame_count += 1

    def get_clip(self, seconds_before: float, seconds_after: float = 0) -> List[Tuple]:
        """Extract a clip from the buffer.

        Returns list of (frame, timestamp, sensor_id, frame_number) tuples.
        """
        with self.lock:
            if not self.buffer:
                return []

            latest_ts = self.buffer[-1][1]
            start_ts = latest_ts - seconds_before
            end_ts = latest_ts + seconds_after

            return [
                entry for entry in self.buffer
                if start_ts <= entry[1] <= end_ts
            ]

    def get_last_n_frames(self, n: int, sensor_id: Optional[int] = None) -> List[Tuple]:
        with self.lock:
            frames = list(self.buffer)
            if sensor_id is not None:
                frames = [f for f in frames if f[2] == sensor_id]
            return frames[-n:]

    def __len__(self):
        with self.lock:
            return len(self.buffer)
