"""Horizontal stream-rate sparkline for the AIS stream tab.

X = time (rolling window), Y = messages/second. The line is coloured by the
StreamHealth state: green normal, yellow degraded, red stopped. Drawn with
QPainter so it has no external dependency.
"""
from qgis.PyQt.QtWidgets import QWidget
from qgis.PyQt.QtGui import QPainter, QPen, QColor, QBrush
from qgis.PyQt.QtCore import Qt

from .stream_health import GREEN, YELLOW, RED

_COLOR = {GREEN: "#2e9e4f", YELLOW: "#d6b13b", RED: "#d63b3b"}


def _enum(obj, scope, name):
    """Qt5/Qt6-safe enum lookup, e.g. _enum(QPainter,'RenderHint','Antialiasing')."""
    return getattr(getattr(obj, scope, obj), name)


class StreamRateGraph(QWidget):
    def __init__(self, parent=None):
        """Create the sparkline widget with an empty series and a fixed height."""
        super().__init__(parent)
        self._series = []          # [(t, rate), ...]
        self._state = GREEN
        self._baseline = None
        self._window = 180
        self.setMinimumHeight(56)
        self.setMaximumHeight(72)
        self.setToolTip("Stream rate (messages/sec). "
                        "Green = normal, yellow = degraded, red = stopped.")

    def update_from(self, health):
        """Pull the latest series / state / baseline from a StreamHealth and
        request a repaint."""
        self._series = health.series()
        self._state = health.state
        self._baseline = health.baseline
        self._window = health.graph_window
        self.update()

    def paintEvent(self, _event):
        """Draw the rate line (coloured by health state), the dashed baseline
        guide and the current-rate label; shows a placeholder until 2+ samples."""
        p = QPainter(self)
        try:
            p.setRenderHint(_enum(QPainter, "RenderHint", "Antialiasing"), True)
        except Exception:
            pass
        w = self.width()
        h = self.height()
        pad = 4

        # background
        p.fillRect(self.rect(), QColor("#ffffff"))

        if len(self._series) < 2:
            p.setPen(QColor("#888"))
            p.drawText(self.rect(), _enum(Qt, "AlignmentFlag", "AlignCenter"),
                       "waiting for stream…")
            p.end()
            return

        t0 = self._series[0][0]
        t1 = self._series[-1][0]
        span = max(t1 - t0, 1.0)
        peak = max((r for _t, r in self._series), default=1)
        peak = max(peak, (self._baseline or 0), 1)

        def X(t):
            """Map a timestamp to a pixel x within the padded plot area."""
            return pad + (t - t0) / span * (w - 2 * pad)

        def Y(r):
            """Map a rate to a pixel y (inverted, 0 at the bottom)."""
            return h - pad - (r / peak) * (h - 2 * pad)

        # baseline guide (dashed grey)
        if self._baseline:
            pen = QPen(QColor("#bbb"))
            pen.setStyle(_enum(Qt, "PenStyle", "DashLine"))
            p.setPen(pen)
            yb = Y(self._baseline)
            p.drawLine(pad, int(yb), w - pad, int(yb))

        # the rate line
        pen = QPen(QColor(_COLOR.get(self._state, "#2e9e4f")))
        pen.setWidth(2)
        p.setPen(pen)
        pts = [(X(t), Y(r)) for t, r in self._series]
        for i in range(1, len(pts)):
            p.drawLine(int(pts[i - 1][0]), int(pts[i - 1][1]),
                       int(pts[i][0]), int(pts[i][1]))

        # current rate label
        p.setPen(QColor("#333"))
        cur = self._series[-1][1]
        p.drawText(pad, pad + 10, f"{cur} msg/s")
        p.end()
