"""TelemetryOverlay — draws the performance metrics box on the camera view."""

from __future__ import annotations

from PySide6.QtCore import QRect, Qt, Slot
from PySide6.QtGui import QColor, QFont, QPainter, QPen

from app.config import (
    OVERLAY_BG_COLOR,
    OVERLAY_FONT_SIZE,
    OVERLAY_MARGIN,
    OVERLAY_PADDING,
    OVERLAY_TEXT_COLOR,
)
from app.overlay.overlay_layer import IOverlayLayer
from app.telemetry.telemetry_collector import TelemetrySnapshot


class TelemetryOverlay(IOverlayLayer):
    """
    Renders a semi-transparent metrics box in the top-left corner.

    Usage:
        overlay = TelemetryOverlay()
        camera_view.add_overlay_layer(overlay)
        telemetry_collector.metrics_updated.connect(overlay.on_metrics_updated)

    Display format:
        FPS req   60.0          ← what was requested from camera
        FPS got   30.2          ← what camera actually delivered
        Frame     33.1 ms
        Drop         0
        CPU sys   14.8 %        ← normalised by cpu_count (matches Task Manager)
        CPU core 118.4 %        ← per single core (can exceed 100%)
        Mem        68 MB
        Inf.dev  mps            ← inference device (only when model loaded)
        Inf.time  87 ms         ← rolling average of model() call time
    """

    def __init__(self) -> None:
        super().__init__()
        self._snapshot: TelemetrySnapshot | None = None

        self._font = QFont("Monospace")
        self._font.setStyleHint(QFont.StyleHint.TypeWriter)
        self._font.setPointSize(OVERLAY_FONT_SIZE)
        self._font.setBold(False)

    @Slot(object)
    def on_metrics_updated(self, snapshot: TelemetrySnapshot) -> None:
        """Receive a new snapshot from TelemetryCollector."""
        self._snapshot = snapshot

    # ------------------------------------------------------------------
    # IOverlayLayer
    # ------------------------------------------------------------------

    def paint(self, painter: QPainter, video_rect: QRect) -> None:
        if self._snapshot is None:
            return

        lines = self._format_lines(self._snapshot)
        if not lines:
            return

        painter.setFont(self._font)
        fm = painter.fontMetrics()
        line_height = fm.height()
        max_width = max(fm.horizontalAdvance(line) for line in lines)

        box_w = max_width + OVERLAY_PADDING * 2
        box_h = line_height * len(lines) + OVERLAY_PADDING * 2

        x = video_rect.left() + OVERLAY_MARGIN
        y = video_rect.top() + OVERLAY_MARGIN

        # Background
        painter.setBrush(QColor(*OVERLAY_BG_COLOR))
        painter.setPen(Qt.PenStyle.NoPen)
        painter.drawRoundedRect(QRect(x, y, box_w, box_h), 6, 6)

        # Text
        painter.setPen(QPen(QColor(*OVERLAY_TEXT_COLOR)))
        text_x = x + OVERLAY_PADDING
        text_y = y + OVERLAY_PADDING + fm.ascent()
        for line in lines:
            painter.drawText(text_x, text_y, line)
            text_y += line_height

    # ------------------------------------------------------------------
    # Private
    # ------------------------------------------------------------------

    @staticmethod
    def _format_lines(snap: TelemetrySnapshot) -> list[str]:
        lines: list[str] = []

        # FPS — show target if known, then actual
        if snap.target_fps is not None:
            lines.append(f"FPS req  {snap.target_fps:>6.1f}")
        lines.append(f"FPS got  {snap.fps:>6.1f}")

        lines.append(f"Frame    {snap.frame_time_ms:>6.1f} ms")
        lines.append(f"Drop     {snap.dropped_frames:>6d}")
        lines.append(f"CPU sys  {snap.cpu_percent_sys:>5.1f} %")
        lines.append(f"CPU core {snap.cpu_percent_core:>5.1f} %")

        if snap.memory_mb is not None:
            lines.append(f"Mem      {snap.memory_mb:>5.0f} MB")

        if snap.inference_device is not None:
            lines.append(f"Inf.dev  {snap.inference_device:>6s}")

        if snap.inference_time_ms is not None:
            lines.append(f"Inf.time {snap.inference_time_ms:>5.0f} ms")

        return lines
