#!/bin/bash

####################################################################
# SnowTV Player – Diagnosepanel (Technikermodus)
#
# Getriggert durch: {"action": "diag"}     via cfgCore-Polling
# Beendet durch:   {"action": "diag_off"} oder nach TIMEOUT Sek.
#
# Zeigt: LTE-Signal (RSRP/RSRQ/SNR/RSSI) mit rollender History,
#        Netzwerkstatus, Up-/Download-Speed, Ping
#
# HTML-Refresh: alle BROWSER_REFRESH Sekunden (meta refresh)
# Daten-Refresh: alle DATA_REFRESH Sekunden (Hintergrundschleife)
# Speedtest:     alle SPEEDTEST_INTERVAL Sekunden (Background-Job)
# History:       letzte HISTORY_MAX Einträge (je DATA_REFRESH Sek.)
####################################################################

DIAG_HTML="/tmp/diag.html"
DIAG_HTML_TMP="/tmp/diag.html.new"
STOP_FLAG="/tmp/diag_stop"
ST_CACHE="/tmp/diag_speedtest.json"
ST_RUNNING="/tmp/diag_speedtest_running"
HISTORY_FILE="/tmp/diag_history.csv"
LOG="/var/log/stv.log"

BROWSER_REFRESH=7      # Sekunden: meta-refresh + Progressbar-Animation
DATA_REFRESH=7         # Sekunden: Daten neu einlesen
SPEEDTEST_INTERVAL=60  # Sekunden: Speedtest wiederholen (1 Min)
HISTORY_MAX=120        # Einträge: 120 × 5s = 10 Min History
TIMEOUT=900            # Sekunden: automatischer Abbruch (15 Min)

echo "$(date)  INFO: Diagnosepanel gestartet" | tee -a "$LOG"
rm -f "$STOP_FLAG" "$HISTORY_FILE"

# ── Cleanup beim Beenden ──────────────────────────────────────────
_cleanup() {
    echo "$(date)  INFO: Diagnosepanel beendet" | tee -a "$LOG"
    rm -f "$STOP_FLAG" "$DIAG_HTML" "$DIAG_HTML_TMP" \
          "$ST_CACHE" "$ST_RUNNING" "$HISTORY_FILE"
    kill "$(pgrep -f 'speedtest-cli')" 2>/dev/null
    killall chromium 2>/dev/null
    sleep 1
    rm -f /home/snowtv/.config/chromium/Singleton*
    exec /home/snowtv/bin/chrom.sh
}
trap _cleanup EXIT INT TERM

# ── Hintergrund-Speedtest ─────────────────────────────────────────
_run_speedtest() {
    [ -f "$ST_RUNNING" ] && return
    touch "$ST_RUNNING"
    (
        speedtest-cli --json 2>/dev/null > "${ST_CACHE}.tmp" \
            && mv "${ST_CACHE}.tmp" "$ST_CACHE"
        rm -f "$ST_RUNNING"
    ) &
}

# ── Signal-Farbe: _color_eval <wert> <schwelle_rot/gelb> <schwelle_gelb/grün>
_color_eval() {
    local n="${1%.*}"
    [ -z "$n" ] && { echo "#888"; return; }
    if   [ "$n" -ge "$3" ] 2>/dev/null; then echo "#4caf50"
    elif [ "$n" -ge "$2" ] 2>/dev/null; then echo "#ff9800"
    else echo "#f44336"; fi
}

_quality_label() {
    case "$1" in
        "#4caf50") echo "Gut" ;;
        "#ff9800") echo "Akzeptabel" ;;
        "#f44336") echo "Schwach" ;;
        *)         echo "–" ;;
    esac
}

# ── HTML generieren ───────────────────────────────────────────────
_gen_html() {
    local TS UPTIME MCID HOSTNAME
    TS="$(date '+%d.%m.%Y %H:%M:%S')"
    UPTIME="$(uptime -p | sed 's/up //')"
    MCID="$(grep '^ID=' /home/snowtv/bin/mcid.cfg 2>/dev/null | cut -d= -f2 | tr -d '\r')"
    HOSTNAME="$(hostname)"

    # ── LTE-Modem ────────────────────────────────────────────────
    local HAS_MODEM=0
    local RSRP="–" RSRQ="–" SNR="–" RSSI="–" OPERATOR="–" ACCESS="–"
    local RSRP_C="#888" RSRQ_C="#888" SNR_C="#888" RSSI_C="#888"

    if sudo mmcli -m 0 > /dev/null 2>&1; then
        HAS_MODEM=1
        local SIGNAL_RAW MODEM_RAW
        SIGNAL_RAW="$(sudo mmcli -m 0 --signal-get 2>/dev/null)"
        MODEM_RAW="$(sudo mmcli -m 0 2>/dev/null)"

        RSRP="$(echo "$SIGNAL_RAW" | grep -i 'rsrp' | grep -iv 'rsrq' \
               | awk -F': ' '{print $2}' | awk '{print $1}' | head -1)"
        RSRQ="$(echo "$SIGNAL_RAW" | grep -i 'rsrq' \
               | awk -F': ' '{print $2}' | awk '{print $1}' | head -1)"
        SNR="$( echo "$SIGNAL_RAW" | grep -iE 'snr|s/n' \
               | awk -F': ' '{print $2}' | awk '{print $1}' | head -1)"
        RSSI="$(echo "$SIGNAL_RAW" | grep -i 'rssi' | grep -iv 'threshold' \
               | awk -F': ' '{print $2}' | awk '{print $1}' | head -1)"

        OPERATOR="$(echo "$MODEM_RAW" | grep -i 'operator name' \
               | awk -F': ' '{print $NF}' | tr -d "'" | xargs)"
        ACCESS="$(echo "$MODEM_RAW" | grep -i 'access tech' \
               | awk -F': ' '{print $NF}' | tr -d "'" | xargs | tr '[:lower:]' '[:upper:]')"

        [ -z "$RSRP" ] && RSRP="–"
        [ -z "$RSRQ" ] && RSRQ="–"
        [ -z "$SNR"  ] && SNR="–"
        [ -z "$RSSI" ] && RSSI="–"
        # Nullwerte als ungültig behandeln
        [ "${RSRP%.*}" = "0" ] 2>/dev/null && RSRP="–"
        [ "${RSRQ%.*}" = "0" ] 2>/dev/null && RSRQ="–"
        [ "${SNR%.*}"  = "0" ] 2>/dev/null && SNR="–"
        [ "${RSSI%.*}" = "0" ] 2>/dev/null && RSSI="–"
        [ -z "$OPERATOR" ] && OPERATOR="–"
        [ -z "$ACCESS"   ] && ACCESS="–"

        # Farbbewertung
        RSRP_C="$(_color_eval "$RSRP" "-105"  "-90")"
        RSRQ_C="$(_color_eval "$RSRQ"  "-15"  "-10")"
        SNR_C="$( _color_eval "$SNR"     "0"   "13")"
        RSSI_C="$(_color_eval "$RSSI"   "-85"  "-70")"
    fi

    # ── History-Eintrag anhängen ──────────────────────────────────
    echo "$(date +%s),${RSRP},${RSRQ},${SNR},${RSSI}" >> "$HISTORY_FILE"
    tail -"$HISTORY_MAX" "$HISTORY_FILE" > "${HISTORY_FILE}.tmp" \
        && mv "${HISTORY_FILE}.tmp" "$HISTORY_FILE"

    # JS-Arrays aus History bauen (null für fehlende Werte)
    local JS_RSRP="[]" JS_RSRQ="[]" JS_SNR="[]" JS_RSSI="[]"
    if [ -f "$HISTORY_FILE" ]; then
        JS_RSRP="[$(awk -F, '{v=$2; printf "%s,", (v=="–"||v==""?"null":v)}' "$HISTORY_FILE" | sed 's/,$//')]"
        JS_RSRQ="[$(awk -F, '{v=$3; printf "%s,", (v=="–"||v==""?"null":v)}' "$HISTORY_FILE" | sed 's/,$//')]"
        JS_SNR="[$( awk -F, '{v=$4; printf "%s,", (v=="–"||v==""?"null":v)}' "$HISTORY_FILE" | sed 's/,$//')]"
        JS_RSSI="[$(awk -F, '{v=$5; printf "%s,", (v=="–"||v==""?"null":v)}' "$HISTORY_FILE" | sed 's/,$//')]"
    fi

    # ── Speedtest-Ergebnis ────────────────────────────────────────
    local DL="–" UL="–" PING="–" ST_SERVER="" ST_STATUS
    if [ -f "$ST_CACHE" ] && [ -s "$ST_CACHE" ]; then
        local RAW_DL RAW_UL RAW_PING ST_TS ST_EPOCH NOW_EPOCH ST_AGE
        RAW_DL="$(  jq -r '.download'          "$ST_CACHE" 2>/dev/null)"
        RAW_UL="$(  jq -r '.upload'            "$ST_CACHE" 2>/dev/null)"
        RAW_PING="$(jq -r '.ping'              "$ST_CACHE" 2>/dev/null)"
        ST_SERVER="$(jq -r '.server.name // ""' "$ST_CACHE" 2>/dev/null)"
        ST_TS="$(   jq -r '.timestamp'         "$ST_CACHE" 2>/dev/null)"
        DL="$(echo "scale=1; $RAW_DL / 1000000" | bc 2>/dev/null)"
        UL="$(echo "scale=1; $RAW_UL / 1000000" | bc 2>/dev/null)"
        PING="$(printf '%.0f' "$RAW_PING" 2>/dev/null)"
        ST_EPOCH="$(date -d "$ST_TS" +%s 2>/dev/null)"
        NOW_EPOCH="$(date +%s)"
        ST_AGE=$(( (NOW_EPOCH - ${ST_EPOCH:-NOW_EPOCH}) / 60 ))
        if [ -f "$ST_RUNNING" ]; then
            ST_STATUS="Messung läuft... (letztes Ergebnis vor ${ST_AGE} Min)"
        else
            ST_STATUS="Letzte Messung vor ${ST_AGE} Min${ST_SERVER:+ &bull; ${ST_SERVER}}"
        fi
    elif [ -f "$ST_RUNNING" ]; then
        ST_STATUS="Erste Messung läuft..."
    else
        ST_STATUS="Warte auf Messung..."
    fi
    local DL_JS UL_JS ST_VERSION
    [ "$DL" = "–" ] || [ -z "$DL" ] && DL_JS="null" || DL_JS="$DL"
    [ "$UL" = "–" ] || [ -z "$UL" ] && UL_JS="null" || UL_JS="$UL"
    if [ -f "$ST_CACHE" ]; then
        ST_VERSION="$(stat -c %Y "$ST_CACHE" 2>/dev/null || echo "none")"
    else
        ST_VERSION="none"
    fi

    # ── Netzwerk-Interfaces ───────────────────────────────────────
    local IFACE_ROWS=""
    while IFS=: read -r DEV TYPE STATE; do
        [[ "$DEV" =~ ^(lo|p2p) ]] && continue
        local IP4
        IP4="$(ip -4 addr show "$DEV" 2>/dev/null | grep 'inet ' | awk '{print $2}' | head -1)"
        [ -z "$IP4" ] && IP4="–"
        local SC="#888"
        [ "$STATE" = "connected" ]    && SC="#4caf50"
        [ "$STATE" = "disconnected" ] && SC="#f44336"
        IFACE_ROWS+="<tr><td>${DEV}</td><td style='font-family:monospace'>${IP4}</td>"
        IFACE_ROWS+="<td style='color:${SC}'>${STATE}</td></tr>"
    done < <(nmcli -t -f DEVICE,TYPE,STATE device status 2>/dev/null)
    local DEFROUTE
    DEFROUTE="$(ip r | grep '^default' | head -1)"

    # ── LTE-Karte ─────────────────────────────────────────────────
    local LTE_CARD
    if [ "$HAS_MODEM" -eq 1 ]; then
        LTE_CARD="<div class='op'>${OPERATOR} &bull; ${ACCESS}</div>"
        for ROW in "RSRP:${RSRP}:dBm:${RSRP_C}" \
                   "RSRQ:${RSRQ}:dB:${RSRQ_C}"   \
                   "SNR:${SNR}:dB:${SNR_C}"       \
                   "RSSI:${RSSI}:dBm:${RSSI_C}"; do
            IFS=: read -r LBL VAL UNIT COL <<< "$ROW"
            QL="$(_quality_label "$COL")"
            if [ "$LBL" = "RSRQ" ]; then
                LTE_CARD+="<div class='sig-row sig-row--key'>"
                LTE_CARD+="<span class='sig-lbl sig-lbl--key'>${LBL}</span>"
                LTE_CARD+="<span class='sig-val sig-val--key' style='color:${COL}'>${VAL}</span>"
                LTE_CARD+="<span class='sig-unit sig-unit--key'>${UNIT}</span>"
                LTE_CARD+="<span class='sig-ql sig-ql--key' style='color:${COL}'>${QL}</span>"
            else
                LTE_CARD+="<div class='sig-row'>"
                LTE_CARD+="<span class='sig-lbl'>${LBL}</span>"
                LTE_CARD+="<span class='sig-val' style='color:${COL}'>${VAL}</span>"
                LTE_CARD+="<span class='sig-unit'>${UNIT}</span>"
                LTE_CARD+="<span class='sig-ql' style='color:${COL}'>${QL}</span>"
            fi
            LTE_CARD+="</div>"
        done
    else
        LTE_CARD="<div style='color:#666;margin-top:16px'>Kein LTE-Modem verbaut</div>"
    fi

    # ── HTML schreiben ────────────────────────────────────────────
    cat > "$DIAG_HTML_TMP" << HTMLEOF
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="${BROWSER_REFRESH}">
<title>SnowTV Diagnose ${MCID}</title>
<style>
html,body{height:100%}
*{box-sizing:border-box;margin:0;padding:0}
body{
  overflow:hidden;
  display:flex;flex-direction:column;
  background:#111;color:#e0e0e0;
  font-family:'Segoe UI',Arial,sans-serif;font-size:50px;
  padding:12px 28px 20px}
h1{font-size:1.1em;color:#90caf9;margin-bottom:2px;flex-shrink:0}
.meta{font-size:.55em;color:#666;margin-bottom:10px;flex-shrink:0}
.grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:10px;flex-shrink:0}
.card{background:#1c1c1c;border-radius:8px;padding:14px;border:1px solid #2a2a2a}
.card h2{font-size:.52em;color:#546e7a;text-transform:uppercase;letter-spacing:.12em;margin-bottom:8px}
.op{font-size:.6em;color:#aaa;margin-bottom:6px}
.sig-row{display:flex;align-items:baseline;gap:12px;margin-bottom:8px;opacity:.55}
.sig-row--key{opacity:1;background:rgba(255,255,255,0.04);border-radius:6px;
  padding:6px 8px;margin:4px -8px 10px;gap:14px}
.sig-lbl{font-size:.52em;color:#666;width:110px;flex-shrink:0}
.sig-lbl--key{font-size:.56em;color:#90a4ae;width:110px;flex-shrink:0}
.sig-val{font-size:1.5em;font-weight:700;line-height:1}
.sig-val--key{font-size:2.1em;font-weight:700;line-height:1;filter:brightness(1.4)}
.sig-unit{font-size:.52em;color:#666}
.sig-unit--key{font-size:.56em;color:#90a4ae}
.sig-ql{font-size:.52em;font-weight:700;margin-left:4px}
.sig-ql--key{font-size:.6em;font-weight:700;margin-left:6px;filter:brightness(1.3)}
.gauge-row{display:flex;align-items:center;gap:8px}
.gauge-box{flex:1;min-width:0}
.gauge-wrap{position:relative;width:100%;padding-top:72%}
.gauge-wrap canvas{position:absolute;top:0;left:0;width:100%;height:100%}
.gauge-lbl{font-size:.42em;color:#666;text-align:center;margin-top:2px}
.gauge-ping{flex:0 0 auto;text-align:center;padding:0 10px}
.ping-val{font-size:1.3em;font-weight:700;color:#ff9800}
.ping-lbl{font-size:.42em;color:#666;margin-top:2px}
.st-status{font-size:.48em;color:#555;margin-top:6px}
table{width:100%;border-collapse:collapse;font-size:.58em}
td,th{padding:4px 8px;text-align:left;border-bottom:1px solid #222}
th{color:#546e7a;font-weight:normal}
.defroute{font-size:.46em;color:#444;margin-top:6px;font-family:monospace;word-break:break-all}
/* History Charts – füllen verbleibende Höhe */
.hist-grid{
  display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:10px;
  flex:1;min-height:0}
.hist-card{
  background:#1c1c1c;border-radius:8px;border:1px solid #2a2a2a;
  overflow:hidden;display:flex;flex-direction:column}
.hist-hdr{
  padding:8px 12px 4px;flex-shrink:0;
  display:flex;justify-content:space-between;align-items:baseline}
.hist-lbl{font-size:.5em;color:#546e7a;text-transform:uppercase;letter-spacing:.1em}
.hist-cur{font-size:.7em;font-weight:700}
.hist-ql{font-size:.42em;margin-left:6px}
.canvas-wrap{flex:1;position:relative;min-height:0}
canvas{position:absolute;top:0;left:0;width:100%;height:100%}
/* Progress Bar */
.progress-wrap{position:fixed;bottom:0;left:0;right:0;height:10px;background:#1a1a1a}
@keyframes countdown{from{width:100%}to{width:0%}}
.progress-bar{height:100%;background:linear-gradient(90deg,#1565c0,#64b5f6);
  animation:countdown ${BROWSER_REFRESH}s linear forwards}
</style>
</head>
<body>

<h1>&#9881; SnowTV Diagnose &ndash; Player ${MCID}</h1>
<div class="meta">${HOSTNAME} &nbsp;&bull;&nbsp; ${TS} &nbsp;&bull;&nbsp; ${UPTIME}</div>

<div class="grid">
  <div class="card">
    <h2>LTE Signal</h2>
    ${LTE_CARD}
  </div>
  <div class="card">
    <h2>Geschwindigkeit</h2>
    <div class="gauge-row">
      <div class="gauge-box">
        <div class="gauge-wrap"><canvas id="g_dl"></canvas></div>
        <div class="gauge-lbl">&#8595; Download</div>
      </div>
      <div class="gauge-box">
        <div class="gauge-wrap"><canvas id="g_ul"></canvas></div>
        <div class="gauge-lbl">&#8593; Upload</div>
      </div>
      <div class="gauge-ping">
        <div class="ping-val">${PING}</div>
        <div class="ping-lbl">ms Ping</div>
      </div>
    </div>
    <div class="st-status">${ST_STATUS}</div>
  </div>
</div>

<div class="card" style="margin-bottom:10px;flex-shrink:0">
  <h2>Netzwerk</h2>
  <table>
    <tr><th>Interface</th><th>IP-Adresse</th><th>Status</th></tr>
    ${IFACE_ROWS}
  </table>
  <div class="defroute">${DEFROUTE}</div>
</div>

<div class="hist-grid">
  <div class="hist-card">
    <div class="hist-hdr">
      <span class="hist-lbl">RSRP</span>
      <span><span class="hist-cur" style="color:${RSRP_C}">${RSRP} dBm</span><span class="hist-ql" style="color:${RSRP_C}">$(_quality_label "$RSRP_C")</span></span>
    </div>
    <div class="canvas-wrap"><canvas id="c_rsrp"></canvas></div>
  </div>
  <div class="hist-card">
    <div class="hist-hdr">
      <span class="hist-lbl">RSRQ</span>
      <span><span class="hist-cur" style="color:${RSRQ_C}">${RSRQ} dB</span><span class="hist-ql" style="color:${RSRQ_C}">$(_quality_label "$RSRQ_C")</span></span>
    </div>
    <div class="canvas-wrap"><canvas id="c_rsrq"></canvas></div>
  </div>
  <div class="hist-card">
    <div class="hist-hdr">
      <span class="hist-lbl">SNR</span>
      <span><span class="hist-cur" style="color:${SNR_C}">${SNR} dB</span><span class="hist-ql" style="color:${SNR_C}">$(_quality_label "$SNR_C")</span></span>
    </div>
    <div class="canvas-wrap"><canvas id="c_snr"></canvas></div>
  </div>
  <div class="hist-card">
    <div class="hist-hdr">
      <span class="hist-lbl">RSSI</span>
      <span><span class="hist-cur" style="color:${RSSI_C}">${RSSI} dBm</span><span class="hist-ql" style="color:${RSSI_C}">$(_quality_label "$RSSI_C")</span></span>
    </div>
    <div class="canvas-wrap"><canvas id="c_rssi"></canvas></div>
  </div>
</div>

<div class="progress-wrap"><div class="progress-bar"></div></div>

<script>
// ── Tacho-Gauge (8 Uhr → 12 Uhr → 4 Uhr, 240°) ───────────────────
function drawGauge(id, value, maxVal, thr) {
  var c = document.getElementById(id);
  if (!c) return;
  c.width  = c.offsetWidth  || 400;
  c.height = c.offsetHeight || 290;
  var ctx = c.getContext('2d');
  var W = c.width, H = c.height;
  ctx.clearRect(0, 0, W, H);

  var cx = W / 2, cy = H * 0.65;
  var r  = Math.min(W * 0.44, cy * 0.92);
  var lw = r * 0.17;

  // 8 Uhr = 5π/6, 4 Uhr = π/6, Sweep = 4π/3 (240°), clockwise
  var startA = 5 * Math.PI / 6;
  var endA   = Math.PI / 6;
  var sweep  = 4 * Math.PI / 3;

  // Hintergrunds-Arc: 8 Uhr → 12 Uhr → 4 Uhr
  ctx.beginPath();
  ctx.arc(cx, cy, r, startA, endA, false);
  ctx.strokeStyle = '#2a2a2a';
  ctx.lineWidth = lw;
  ctx.lineCap = 'round';
  ctx.stroke();

  // Farbe nach Wert
  var color = value === null ? '#444'
    : value < thr[0] ? '#f44336'
    : value < thr[1] ? '#ff9800'
    : '#4caf50';

  // Wert-Arc: von 8 Uhr clockwise um pct × 240°
  if (value !== null && value > 0) {
    var pct = Math.min(value / maxVal, 1);
    ctx.beginPath();
    ctx.arc(cx, cy, r, startA, startA + sweep * pct, false);
    ctx.strokeStyle = color;
    ctx.lineWidth = lw;
    ctx.lineCap = 'round';
    ctx.stroke();
  }

  // Zahl
  var txt = value === null ? '–' : value.toFixed(1);
  ctx.fillStyle = color;
  ctx.font = 'bold ' + Math.round(r * 0.50) + 'px Segoe UI,Arial,sans-serif';
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  ctx.fillText(txt, cx, cy - r * 0.28);

  // Einheit
  ctx.fillStyle = '#555';
  ctx.font = Math.round(r * 0.20) + 'px Segoe UI,Arial,sans-serif';
  ctx.fillText('Mbit/s', cx, cy - r * 0.28 + r * 0.38);
}

function animateGauge(id, target, maxVal, thr) {
  if (target === null) { drawGauge(id, null, maxVal, thr); return; }
  var start = null, dur = 650;
  function step(ts) {
    if (!start) start = ts;
    var p = Math.min((ts - start) / dur, 1);
    var e = 1 - Math.pow(1 - p, 3);  // easeOutCubic
    drawGauge(id, target * e, maxVal, thr);
    if (p < 1) requestAnimationFrame(step);
  }
  requestAnimationFrame(step);
}

var dl_val = ${DL_JS};
var ul_val = ${UL_JS};
var st_version = '${ST_VERSION}';
var prev_version = localStorage.getItem('diag_st_version') || '';
var st_changed = st_version !== 'none' && st_version !== prev_version;
if (st_changed) localStorage.setItem('diag_st_version', st_version);
if (st_changed) {
  animateGauge('g_dl', dl_val, 150, [10, 30]);
  animateGauge('g_ul', ul_val,  50, [ 3, 10]);
} else {
  drawGauge('g_dl', dl_val, 150, [10, 30]);
  drawGauge('g_ul', ul_val,  50, [ 3, 10]);
}

// ── Verlaufs-Charts ───────────────────────────────────────────────
function drawChart(id, data, minY, maxY, color, thr) {
  var c = document.getElementById(id);
  if (!c) return;
  c.width  = c.offsetWidth  || 600;
  c.height = c.offsetHeight || 200;
  var ctx = c.getContext('2d');
  var W = c.width, H = c.height;
  ctx.clearRect(0, 0, W, H);
  ctx.fillStyle = '#161616';
  ctx.fillRect(0, 0, W, H);

  var yp = function(v) { return H - (v - minY) / (maxY - minY) * H; };

  // Farbzonen und Schwelllinien
  if (thr) {
    var zones = [
      [minY, thr[0], 'rgba(244,67,54,0.35)'],
      [thr[0], thr[1], 'rgba(255,152,0,0.30)'],
      [thr[1], maxY, 'rgba(76,175,80,0.28)']
    ];
    zones.forEach(function(z) {
      var y1 = Math.min(yp(z[0]), yp(z[1]));
      var y2 = Math.max(yp(z[0]), yp(z[1]));
      ctx.fillStyle = z[2];
      ctx.fillRect(0, y1, W, y2 - y1);
    });
    thr.forEach(function(t) {
      ctx.strokeStyle = 'rgba(255,255,255,0.18)';
      ctx.lineWidth = 1;
      ctx.setLineDash([6, 6]);
      ctx.beginPath();
      ctx.moveTo(0, yp(t));
      ctx.lineTo(W, yp(t));
      ctx.stroke();
      ctx.setLineDash([]);
    });
  }

  // Linie zeichnen
  var valid = data.filter(function(v) { return v !== null; });
  if (valid.length < 2) return;

  ctx.strokeStyle = color;
  ctx.lineWidth = 4;
  ctx.lineJoin = 'round';
  ctx.lineCap = 'round';
  ctx.beginPath();
  var started = false;
  data.forEach(function(v, i) {
    if (v === null) { started = false; return; }
    var x = i / (data.length - 1) * W;
    var y = Math.max(2, Math.min(H - 2, yp(v)));
    if (!started) { ctx.moveTo(x, y); started = true; }
    else ctx.lineTo(x, y);
  });
  ctx.stroke();

  // Aktueller Wert: Punkt am rechten Ende
  var last = null;
  for (var i = data.length - 1; i >= 0; i--) {
    if (data[i] !== null) { last = data[i]; break; }
  }
  if (last !== null) {
    var lx = W - 4;
    var ly = Math.max(2, Math.min(H - 2, yp(last)));
    ctx.beginPath();
    ctx.arc(lx, ly, 7, 0, Math.PI * 2);
    ctx.fillStyle = color;
    ctx.fill();
  }
}

var rsrp = ${JS_RSRP};
var rsrq = ${JS_RSRQ};
var snr  = ${JS_SNR};
var rssi = ${JS_RSSI};

drawChart('c_rsrp', rsrp, -130, -50,  '#90caf9', [-105, -90]);
drawChart('c_rsrq', rsrq,  -20,   0,  '#ce93d8', [ -15, -10]);
drawChart('c_snr',  snr,   -10,  30,  '#a5d6a7', [   0,  13]);
drawChart('c_rssi', rssi, -120, -50,  '#ffcc80', [ -85, -70]);
</script>
</body>
</html>
HTMLEOF

    mv "$DIAG_HTML_TMP" "$DIAG_HTML"
}

# ── Chromium auf Diagnosepanel umschalten ─────────────────────────
killall chromium 2>/dev/null
sleep 1
rm -f /home/snowtv/.config/chromium/Singleton*

# Diag-Profil vorbereiten: Translate-Dialoge dauerhaft deaktivieren
DIAG_PROFILE="/home/snowtv/.config/chromium/Diag"
mkdir -p "$DIAG_PROFILE"
cat > "$DIAG_PROFILE/Preferences" << 'PREFEOF'
{
  "translate":{"enabled":false},
  "translate_site_blacklist":[],
  "browser":{"has_seen_welcome_page":true},
  "profile":{"default_content_setting_values":{}},
  "intl":{"accept_languages":"de-CH,de"},
  "credentials_enable_service":false,
  "credentials_enable_autosignin":false
}
PREFEOF

export DISPLAY=:0.0
export XDG_RUNTIME_DIR="/run/user/1000"
setsid chromium \
    --profile-directory="Diag" \
    --use-gl=egl \
    --no-sandbox \
    --disable-gpu-sandbox \
    --disable-translate \
    --disable-features=TranslateUI \
    --lang=de-CH \
    --disable-infobars \
    --no-first-run \
    --disable-suggestions-service \
    --disable-save-password-bubble \
    --autoplay-policy=no-user-gesture-required \
    --start-maximized \
    --noerrdialogs \
    --disable-background-networking \
    --dns-prefetch-disable \
    --password-store=basic \
    --disable-extensions \
    --kiosk "file://${DIAG_HTML}" &

# Signal-Polling aktivieren (sonst liefert --signal-get keine Werte)
sudo mmcli -m 0 --signal-setup="${DATA_REFRESH}" 2>/dev/null

# Erster Speedtest sofort
_run_speedtest

# ── Hauptschleife ─────────────────────────────────────────────────
START_TIME="$(date +%s)"
LAST_SPEEDTEST="$(date +%s)"

while true; do
    NOW="$(date +%s)"

    if [ -f "$STOP_FLAG" ]; then
        echo "$(date)  INFO: Diagnosepanel: diag_off empfangen" | tee -a "$LOG"
        exit 0
    fi
    if [ $(( NOW - START_TIME )) -ge "$TIMEOUT" ]; then
        echo "$(date)  INFO: Diagnosepanel: Timeout (${TIMEOUT}s)" | tee -a "$LOG"
        exit 0
    fi

    if [ $(( NOW - LAST_SPEEDTEST )) -ge "$SPEEDTEST_INTERVAL" ] && [ ! -f "$ST_RUNNING" ]; then
        _run_speedtest
        LAST_SPEEDTEST="$NOW"
    fi

    _gen_html
    sleep "$DATA_REFRESH"
done
