# -*- coding: utf-8 -*-
"""Netzwerk-Auslastung: aktueller Download und Upload in Byte/s.

Die Balken skalieren sich automatisch auf den höchsten Wert der letzten
~60 Sekunden, damit sie auch bei kleinen Datenraten brauchbar aussehen.
"""
import psutil
from collections import deque
from PyQt5.QtCore import QTimer, Qt
from PyQt5.QtGui import QPainter, QColor, QLinearGradient, QFont
from PyQt5.QtWidgets import QVBoxLayout, QLabel, QWidget, QSizePolicy

from modules.base import DashboardModule


def fmt_rate(bps: float) -> str:
    """Bytes/s in lesbare Einheit. Wir zeigen Byte (übliche Anzeige)."""
    if bps < 1024:
        return f"{bps:6.0f}  B/s"
    if bps < 1024 * 1024:
        return f"{bps / 1024:6.1f} KB/s"
    if bps < 1024 * 1024 * 1024:
        return f"{bps / (1024 * 1024):6.2f} MB/s"
    return f"{bps / (1024 ** 3):6.2f} GB/s"


class Bar(QWidget):
    """Wie in system_info.py - Balken mit Gradient, Wert von 0..1."""

    def __init__(self, color_a: str, color_b: str, parent=None):
        super().__init__(parent)
        self.fill = 0.0
        self._ca = QColor(color_a)
        self._cb = QColor(color_b)
        self.setMinimumHeight(8)
        self.setMaximumHeight(8)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

    def set_fill(self, frac: float):
        self.fill = max(0.0, min(1.0, frac))
        self.update()

    def paintEvent(self, _):
        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing, True)
        r = self.rect()
        p.setPen(Qt.NoPen)
        p.setBrush(QColor(255, 255, 255, 24))
        p.drawRoundedRect(r, 4, 4)
        if self.fill > 0:
            w = int(r.width() * self.fill)
            grad = QLinearGradient(0, 0, r.width(), 0)
            grad.setColorAt(0.0, self._ca)
            grad.setColorAt(1.0, self._cb)
            p.setBrush(grad)
            p.drawRoundedRect(0, 0, w, r.height(), 4, 4)


class NetworkModule(DashboardModule):
    INTERVAL_MS = 1000
    WINDOW = 60  # Sekunden für rollendes Maximum

    def __init__(self, parent=None):
        super().__init__(parent)
        outer = QVBoxLayout(self)
        outer.setContentsMargins(2, 2, 2, 2)
        outer.setSpacing(6)

        self.down_lbl, self.down_bar = self._row("DOWN  ↓", "#00E5FF", "#7CFF00")
        self.up_lbl, self.up_bar = self._row("UP    ↑", "#FF00C8", "#FFB300")
        self.total_lbl = QLabel("seit Start  ↓ 0 B   ↑ 0 B")
        f = QFont("Segoe UI", 8)
        self.total_lbl.setFont(f)
        self.total_lbl.setStyleSheet("color: #9EE6FF; letter-spacing: 0.5px;")
        self.total_lbl.setAlignment(Qt.AlignCenter)

        for lbl, bar in [(self.down_lbl, self.down_bar), (self.up_lbl, self.up_bar)]:
            box = QVBoxLayout()
            box.setSpacing(2)
            box.addWidget(lbl)
            box.addWidget(bar)
            outer.addLayout(box)
        outer.addWidget(self.total_lbl)

        io = psutil.net_io_counters()
        self._last_recv = io.bytes_recv
        self._last_sent = io.bytes_sent
        self._start_recv = io.bytes_recv
        self._start_sent = io.bytes_sent
        self._recv_hist = deque(maxlen=self.WINDOW)
        self._sent_hist = deque(maxlen=self.WINDOW)

        self._timer = QTimer(self)
        self._timer.timeout.connect(self._refresh)
        self._timer.start(self.INTERVAL_MS)

    def _row(self, name: str, c1: str, c2: str):
        lbl = QLabel(f"{name}    --")
        f = QFont("Consolas", 9)
        f.setBold(True)
        lbl.setFont(f)
        lbl.setStyleSheet("color: #E8F4FF;")
        return lbl, Bar(c1, c2)

    def _refresh(self):
        io = psutil.net_io_counters()
        dt = self.INTERVAL_MS / 1000.0
        recv_rate = max(0.0, (io.bytes_recv - self._last_recv) / dt)
        sent_rate = max(0.0, (io.bytes_sent - self._last_sent) / dt)
        self._last_recv = io.bytes_recv
        self._last_sent = io.bytes_sent

        self._recv_hist.append(recv_rate)
        self._sent_hist.append(sent_rate)
        # Mindest-Skala: 64 KB/s, damit der Balken bei Leerlauf nicht zappelt
        max_recv = max(max(self._recv_hist), 64 * 1024)
        max_sent = max(max(self._sent_hist), 64 * 1024)

        self.down_lbl.setText(f"DOWN  ↓   {fmt_rate(recv_rate)}")
        self.up_lbl.setText(f"UP    ↑   {fmt_rate(sent_rate)}")
        self.down_bar.set_fill(recv_rate / max_recv)
        self.up_bar.set_fill(sent_rate / max_sent)

        total_r = io.bytes_recv - self._start_recv
        total_s = io.bytes_sent - self._start_sent
        self.total_lbl.setText(
            f"seit Start  ↓ {self._fmt_bytes(total_r)}   ↑ {self._fmt_bytes(total_s)}"
        )

    @staticmethod
    def _fmt_bytes(b: int) -> str:
        # Summen in Byte/KB/MB/GB für Anzeige „seit Start"
        if b < 1024:
            return f"{b} B"
        if b < 1024 * 1024:
            return f"{b / 1024:.1f} KB"
        if b < 1024 * 1024 * 1024:
            return f"{b / (1024 * 1024):.1f} MB"
        return f"{b / (1024 ** 3):.2f} GB"


MODULE_TITLE = "Netzwerk"
MODULE_CLASS = NetworkModule
