"""
Null/headless display backend.
"""

import json
import time
from pathlib import Path
from typing import Any


class NullDisplay:
    """Headless/null display - discards all output.

    This display does nothing - useful for headless benchmarking
    or when no display output is needed. Captures last buffer
    for testing purposes. Supports frame recording for replay
    and file export/import.
    """

    width: int = 80
    height: int = 24
    _last_buffer: list[str] | None = None

    def __init__(self):
        self._last_buffer = None
        self._is_recording = False
        self._recorded_frames: list[dict[str, Any]] = []
        self._frame_count = 0

    def init(self, width: int, height: int, reuse: bool = False) -> None:
        """Initialize display with dimensions.

        Args:
            width: Terminal width in characters
            height: Terminal height in rows
            reuse: Ignored for NullDisplay (no resources to reuse)
        """
        self.width = width
        self.height = height
        self._last_buffer = None

    def show(self, buffer: list[str], border: bool = False) -> None:
        import sys

        from engine.display import get_monitor, render_border

        fps = 0.0
        frame_time = 0.0
        monitor = get_monitor()
        if monitor:
            stats = monitor.get_stats()
            avg_ms = stats.get("pipeline", {}).get("avg_ms", 0) if stats else 0
            frame_count = stats.get("frame_count", 0) if stats else 0
            if avg_ms and frame_count > 0:
                fps = 1000.0 / avg_ms
                frame_time = avg_ms

        if border:
            buffer = render_border(buffer, self.width, self.height, fps, frame_time)

        self._last_buffer = buffer

        if self._is_recording:
            self._recorded_frames.append(
                {
                    "frame_number": self._frame_count,
                    "buffer": buffer,
                    "width": self.width,
                    "height": self.height,
                }
            )

        if self._frame_count <= 5 or self._frame_count % 10 == 0:
            sys.stdout.write("\n" + "=" * 80 + "\n")
            sys.stdout.write(
                f"Frame {self._frame_count} (buffer height: {len(buffer)})\n"
            )
            sys.stdout.write("=" * 80 + "\n")
            for i, line in enumerate(buffer[:30]):
                sys.stdout.write(f"{i:2}: {line}\n")
            if len(buffer) > 30:
                sys.stdout.write(f"... ({len(buffer) - 30} more lines)\n")
            sys.stdout.flush()

        if monitor:
            t0 = time.perf_counter()
            chars_in = sum(len(line) for line in buffer)
            elapsed_ms = (time.perf_counter() - t0) * 1000
            monitor.record_effect("null_display", elapsed_ms, chars_in, chars_in)

        self._frame_count += 1

    def start_recording(self) -> None:
        """Begin recording frames."""
        self._is_recording = True
        self._recorded_frames = []

    def stop_recording(self) -> None:
        """Stop recording frames."""
        self._is_recording = False

    def get_frames(self) -> list[list[str]]:
        """Get recorded frames as list of buffers.

        Returns:
            List of buffers, each buffer is a list of strings (lines)
        """
        return [frame["buffer"] for frame in self._recorded_frames]

    def get_recorded_data(self) -> list[dict[str, Any]]:
        """Get full recorded data including metadata.

        Returns:
            List of frame dicts with 'frame_number', 'buffer', 'width', 'height'
        """
        return self._recorded_frames

    def clear_recording(self) -> None:
        """Clear recorded frames."""
        self._recorded_frames = []

    def save_recording(self, filepath: str | Path) -> None:
        """Save recorded frames to a JSON file.

        Args:
            filepath: Path to save the recording
        """
        path = Path(filepath)
        data = {
            "version": 1,
            "display": "null",
            "width": self.width,
            "height": self.height,
            "frame_count": len(self._recorded_frames),
            "frames": self._recorded_frames,
        }
        path.write_text(json.dumps(data, indent=2))

    def load_recording(self, filepath: str | Path) -> list[dict[str, Any]]:
        """Load recorded frames from a JSON file.

        Args:
            filepath: Path to load the recording from

        Returns:
            List of frame dicts
        """
        path = Path(filepath)
        data = json.loads(path.read_text())
        self._recorded_frames = data.get("frames", [])
        self.width = data.get("width", 80)
        self.height = data.get("height", 24)
        return self._recorded_frames

    def replay_frames(self) -> list[list[str]]:
        """Get frames for replay.

        Returns:
            List of buffers for replay
        """
        return self.get_frames()

    def clear(self) -> None:
        pass

    def cleanup(self) -> None:
        pass

    def get_dimensions(self) -> tuple[int, int]:
        """Get current dimensions.

        Returns:
            (width, height) in character cells
        """
        return (self.width, self.height)

    def is_quit_requested(self) -> bool:
        """Check if quit was requested (optional protocol method)."""
        return False

    def clear_quit_request(self) -> None:
        """Clear quit request (optional protocol method)."""
        pass
