/**
 * SystemHealth.jsx — System resource monitoring and ROS2 node status.
 *
 * Topics:
 *   /diagnostics  (diagnostic_msgs/DiagnosticArray)
 *     Each DiagnosticStatus has: name, level (0=OK,1=WARN,2=ERROR,3=STALE)
 *                                message, hardware_id, values: [{key,value}]
 *     Expected KeyValue sources (from tegrastats bridge / custom nodes):
 *       cpu_temp_c, gpu_temp_c, ram_used_mb, ram_total_mb,
 *       disk_used_gb, disk_total_gb, gpu_used_mb, gpu_total_mb
 */

import { useEffect, useState } from 'react';

const LEVEL_CONFIG = {
  0: { label: 'OK',    color: 'text-green-400', bg: 'bg-green-950', border: 'border-green-800', dot: 'bg-green-400' },
  1: { label: 'WARN',  color: 'text-amber-400', bg: 'bg-amber-950', border: 'border-amber-800', dot: 'bg-amber-400 animate-pulse' },
  2: { label: 'ERROR', color: 'text-red-400',   bg: 'bg-red-950',   border: 'border-red-800',   dot: 'bg-red-400 animate-pulse' },
  3: { label: 'STALE', color: 'text-gray-500',  bg: 'bg-gray-900',  border: 'border-gray-700',  dot: 'bg-gray-500' },
};

function ResourceBar({ label, used, total, unit, warnPct = 80 }) {
  if (total == null || total === 0) return null;
  const pct = Math.round((used / total) * 100);
  const warn = pct >= warnPct;
  const crit = pct >= 95;
  const color = crit ? '#ef4444' : warn ? '#f59e0b' : '#06b6d4';

  return (
    <div className="space-y-1">
      <div className="flex justify-between text-xs">
        <span className="text-gray-500">{label}</span>
        <span className={warn ? 'text-amber-400' : 'text-gray-400'}>
          {typeof used === 'number' ? used.toFixed(1) : used}/{typeof total === 'number' ? total.toFixed(1) : total} {unit}
          <span className="text-gray-600 ml-1">({pct}%)</span>
        </span>
      </div>
      <div className="w-full h-2.5 bg-gray-900 rounded overflow-hidden border border-gray-800">
        <div
          className="h-full transition-all duration-500 rounded"
          style={{ width: `${pct}%`, background: color }}
        />
      </div>
    </div>
  );
}

function TempGauge({ label, tempC }) {
  if (tempC == null) return null;
  const warn = tempC > 75;
  const crit = tempC > 90;
  const pct  = Math.min(100, (tempC / 100) * 100);
  const color = crit ? '#ef4444' : warn ? '#f59e0b' : '#22c55e';

  return (
    <div className="bg-gray-950 rounded-lg border border-cyan-950 p-3 text-center">
      <div className="text-gray-600 text-xs">{label}</div>
      <div className="text-2xl font-bold mt-1" style={{ color }}>
        {tempC.toFixed(0)}°C
      </div>
      <div className="w-full h-1.5 bg-gray-900 rounded overflow-hidden mt-1.5">
        <div className="h-full rounded" style={{ width: `${pct}%`, background: color }} />
      </div>
    </div>
  );
}

function NodeRow({ status }) {
  const cfg = LEVEL_CONFIG[status.level] ?? LEVEL_CONFIG[3];
  return (
    <div className={`flex items-center gap-2 rounded px-3 py-1.5 border text-xs ${cfg.bg} ${cfg.border}`}>
      <div className={`w-1.5 h-1.5 rounded-full shrink-0 ${cfg.dot}`} />
      <span className="text-gray-300 font-bold truncate flex-1" title={status.name}>{status.name}</span>
      <span className={`${cfg.color} shrink-0`}>{status.message || cfg.label}</span>
    </div>
  );
}

export function SystemHealth({ subscribe }) {
  const [resources, setResources] = useState({
    cpuTemp: null, gpuTemp: null,
    ramUsed: null, ramTotal: null,
    diskUsed: null, diskTotal: null,
    gpuUsed: null, gpuTotal: null,
  });
  const [nodes, setNodes] = useState([]);
  const [lastTs, setLastTs] = useState(null);

  useEffect(() => {
    const unsub = subscribe('/diagnostics', 'diagnostic_msgs/DiagnosticArray', (msg) => {
      setLastTs(Date.now());

      // Parse each DiagnosticStatus
      const nodeList = [];

      for (const status of msg.status ?? []) {
        const kv = {};
        for (const pair of status.values ?? []) kv[pair.key] = pair.value;

        // Resource metrics
        setResources(prev => {
          const next = { ...prev };
          if (kv.cpu_temp_c   !== undefined) next.cpuTemp  = parseFloat(kv.cpu_temp_c);
          if (kv.gpu_temp_c   !== undefined) next.gpuTemp  = parseFloat(kv.gpu_temp_c);
          if (kv.ram_used_mb  !== undefined) next.ramUsed  = parseFloat(kv.ram_used_mb) / 1024;
          if (kv.ram_total_mb !== undefined) next.ramTotal = parseFloat(kv.ram_total_mb) / 1024;
          if (kv.disk_used_gb !== undefined) next.diskUsed  = parseFloat(kv.disk_used_gb);
          if (kv.disk_total_gb!== undefined) next.diskTotal = parseFloat(kv.disk_total_gb);
          if (kv.gpu_used_mb  !== undefined) next.gpuUsed  = parseFloat(kv.gpu_used_mb);
          if (kv.gpu_total_mb !== undefined) next.gpuTotal = parseFloat(kv.gpu_total_mb);
          return next;
        });

        // Collect all statuses as node rows
        nodeList.push({ name: status.name, level: status.level, message: status.message });
      }

      if (nodeList.length > 0) {
        setNodes(nodeList);
      }
    });
    return unsub;
  }, [subscribe]);

  const stale = lastTs && Date.now() - lastTs > 10000;
  const errorCount = nodes.filter(n => n.level === 2).length;
  const warnCount  = nodes.filter(n => n.level === 1).length;

  return (
    <div className="space-y-4">
      {/* Summary banner */}
      {nodes.length > 0 && (
        <div className={`flex items-center gap-3 rounded-lg border p-3 ${
          errorCount > 0 ? 'bg-red-950 border-red-800' :
          warnCount  > 0 ? 'bg-amber-950 border-amber-800' :
          'bg-green-950 border-green-800'
        }`}>
          <div className={`w-3 h-3 rounded-full ${
            errorCount > 0 ? 'bg-red-400 animate-pulse' :
            warnCount  > 0 ? 'bg-amber-400 animate-pulse' : 'bg-green-400'
          }`} />
          <div className="text-sm font-bold">
            {errorCount > 0 ? `${errorCount} ERROR${errorCount > 1 ? 'S' : ''}` :
             warnCount  > 0 ? `${warnCount} WARNING${warnCount > 1 ? 'S' : ''}` :
             'All systems nominal'}
          </div>
          <div className="ml-auto text-xs text-gray-500">{nodes.length} nodes</div>
          {stale && <div className="text-red-400 text-xs">STALE</div>}
        </div>
      )}

      {/* Temperatures */}
      {(resources.cpuTemp != null || resources.gpuTemp != null) && (
        <div className="grid grid-cols-2 gap-3">
          <TempGauge label="CPU TEMP" tempC={resources.cpuTemp} />
          <TempGauge label="GPU TEMP" tempC={resources.gpuTemp} />
        </div>
      )}

      {/* Resource bars */}
      <div className="bg-gray-950 rounded-lg border border-cyan-950 p-4 space-y-3">
        <div className="text-cyan-700 text-xs font-bold tracking-widest">SYSTEM RESOURCES</div>
        <ResourceBar label="RAM"        used={resources.ramUsed}  total={resources.ramTotal}  unit="GB" />
        <ResourceBar label="GPU MEM"    used={resources.gpuUsed}  total={resources.gpuTotal}  unit="MB" />
        <ResourceBar label="DISK"       used={resources.diskUsed} total={resources.diskTotal} unit="GB" warnPct={85} />
        {resources.ramUsed == null && resources.gpuUsed == null && resources.diskUsed == null && (
          <div className="text-gray-600 text-xs">
            Waiting for resource metrics from /diagnostics…
            <div className="mt-1 text-gray-700">Expected keys: cpu_temp_c, gpu_temp_c, ram_used_mb, disk_used_gb</div>
          </div>
        )}
      </div>

      {/* Node list */}
      <div className="bg-gray-950 rounded-lg border border-cyan-950 p-4">
        <div className="flex items-center justify-between mb-3">
          <div className="text-cyan-700 text-xs font-bold tracking-widest">ROS2 NODE HEALTH</div>
          <div className="text-gray-600 text-xs">{nodes.length} statuses</div>
        </div>
        {nodes.length === 0 ? (
          <div className="text-gray-600 text-xs text-center py-4 border border-dashed border-gray-800 rounded">
            Waiting for /diagnostics…
          </div>
        ) : (
          <div className="space-y-1.5 max-h-80 overflow-y-auto">
            {/* Sort: errors first, then warns, then OK */}
            {[...nodes]
              .sort((a, b) => (b.level ?? 0) - (a.level ?? 0))
              .map((n, i) => <NodeRow key={i} status={n} />)
            }
          </div>
        )}
      </div>
    </div>
  );
}
