import React, { useState, useEffect, useCallback, useRef, useMemo, Fragment } from 'react';
import * as AppGo from '../../wailsjs/go/main/App.js';
import {
  formatCapacity,
  formatPartitionCapacity,
  formatRate,
  formatTransferTotal,
} from './probeFormatting.js';
import { BarChart3, Cpu, HardDrive, Globe, ClipboardList, Clipboard, Search, Check, Monitor, EyeOff, Eye, RefreshCw, MemoryStick, ArrowLeftRight } from 'lucide-react';
import Tiptop from './Tiptop.jsx';
import { Z } from '../constants/zIndex';
import { useTranslation } from '../i18n.js';

// ── Sparkline SVG ──────────────────────────────────────────────────────────
const Sparkline = React.memo(function Sparkline({ data, color = 'var(--success)', fill = true, height = 36, width = '100%' }) {
  const pts = data || [];
  const { points, fillPts } = useMemo(() => {
    if (pts.length < 2) return { points: '', fillPts: '' };
    const max = Math.max(...pts, 1);
    const W = 200; const H = height;
    const p = pts.map((v, i) => `${(i / (pts.length - 1)) * W},${H - (v / max) * (H - 2)}`).join(' ');
    return { points: p, fillPts: `0,${H} ` + p + ` ${W},${H}` };
  }, [pts, height]);
  if (pts.length < 2) return <div style={{ height }} />;
  return (
    <svg viewBox={`0 0 200 ${height}`} preserveAspectRatio="none" style={{ width, height, display: 'block' }}>
      {fill && <polygon points={fillPts} style={{ fill: color }} opacity={0.12} />}
      <polyline points={points} fill="none" style={{ stroke: color }} strokeWidth={1.5} strokeLinejoin="round" strokeLinecap="round" />
    </svg>
  );
});

// ── Memory Donut ──────────────────────────────────────────────────────────
const MemDonut = React.memo(function MemDonut({ used, cache, free, total }) {
  const r = 27; const cx = 35; const cy = 35;
  const circ = 2 * Math.PI * r;
  // 用 available 分割，保证三段 = 100%
  // 红 = used (total - available), 灰 = available - free, 绿 = free
  const f1 = total > 0 ? Math.min(Math.max(used / total, 0), 1) : 0;
  const reclaimable = total - used - free; // available - free
  const f2 = total > 0 ? Math.min(Math.max(reclaimable / total, 0), 1 - f1) : 0;
  const f3 = Math.max(1 - f1 - f2, 0);
  const seg = (frac, color, start) => frac > 0.005 ? (
    <circle cx={cx} cy={cy} r={r} fill="none" stroke={color} strokeWidth={8}
      strokeDasharray={`${frac * circ} ${circ}`}
      strokeLinecap="butt"
      transform={`rotate(${-90 + start * 360} ${cx} ${cy})`} />
  ) : null;
  return (
    <svg width={70} height={70} style={{ flexShrink: 0 }}>
      <circle cx={cx} cy={cy} r={r} fill="none" stroke="var(--border)" strokeWidth={8} />
      {seg(f1, 'var(--danger)', 0)}
      {seg(f2, 'var(--warning)', f1)}
      {seg(f3, 'var(--success)', f1 + f2)}
    </svg>
  );
});

// ── CPU Bar ────────────────────────────────────────────────────────────────
const CpuBar = React.memo(function CpuBar({ val = 0 }) {
  const pct = Math.min(Math.max(val, 0), 100);
  const color = pct > 80 ? 'var(--danger)' : pct > 50 ? 'var(--warning)' : 'var(--success)';
  return (
    <div style={{ flex: 1, height: 5, background: 'var(--border)', borderRadius: 3, overflow: 'hidden' }}>
      <div style={{ width: `${pct}%`, height: '100%', background: color, borderRadius: 3, transition: 'width 0.4s ease' }} />
    </div>
  );
});

// ── Disk Partition Row ─────────────────────────────────────────────────────
const PartRow = React.memo(function PartRow({ mount, size, avail, usedPct }) {
  const pct = Math.min(Math.max(usedPct, 0), 100);
  const color = pct > 85 ? 'var(--danger)' : pct > 60 ? 'var(--warning)' : 'var(--success)';
  return (
    <div className="probe-partition-row">
      <span className="probe-partition-mount" title={mount}>{mount}</span>
      <div className="probe-partition-bar">
        <div style={{ width: `${pct}%`, height: '100%', background: color, borderRadius: 2 }} />
      </div>
      <span className="probe-partition-value" title={String(size)}>{formatPartitionCapacity(size)}</span>
      <span className="probe-partition-value" title={String(avail)}>{formatPartitionCapacity(avail)}</span>
      <span className="probe-partition-percent" style={{ color }}>{pct}%</span>
    </div>
  );
});

// ── Section Card ───────────────────────────────────────────────────────────
const Card = React.memo(function Card({ children, style }) {
  return (
    <div style={{
      background: 'var(--surface-overlay)',
      border: '1px solid var(--border)',
      borderRadius: 10, padding: '10px 12px',
      ...style,
    }}>
      {children}
    </div>
  );
});

// ── Section Header ─────────────────────────────────────────────────────────
const SectionHeader = React.memo(function SectionHeader({ icon, title, badge, right }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 8 }}>
      <span style={{ display: 'flex', alignItems: 'center', color: 'var(--text-tertiary)' }}>{icon}</span>
      <span style={{ fontSize: 13, fontWeight: 700, color: 'var(--text-primary)', flex: 1 }}>{title}</span>
      {badge && (
        <span style={{
          fontSize: 11, fontFamily: 'var(--font-mono)', fontWeight: 600,
          color: 'var(--text-secondary)', background: 'var(--surface-overlay)',
          border: '1px solid var(--border)',
          padding: '2px 7px', borderRadius: 4,
        }}>{badge}</span>
      )}
      {right}
    </div>
  );
});

// ── Format helpers ─────────────────────────────────────────────────────────
const fmem = (mb) => {
  return formatCapacity(mb, 1);
};
const fspeed = (kb) => {
  return formatRate(kb);
};
const ftotal = (mb) => {
  return formatTransferTotal(mb);
};

function isInternalIP(ip) {
  if (!ip) return true;
  const parts = ip.trim().split('.');
  if (parts.length !== 4) return true;
  if (parts[0] === '10') return true;
  if (parts[0] === '127') return true;
  if (parts[0] === '172' && parseInt(parts[1]) >= 16 && parseInt(parts[1]) <= 31) return true;
  if (parts[0] === '192' && parts[1] === '168') return true;
  return false;
}

// ══════════════════════════════════════════════════════════════════════════
export default function ProbePanel({ sessionId, host, addToast, enabled, active, onEnable, onShowAllProcesses, onShowNetworkDetails }) {
  const { t } = useTranslation();
  const [info, setInfo] = useState(null);
  // ponytail: 合并 3 个历史数组为 1 个状态更新，减少 3 次渲染为 1 次
  const [hist, setHist] = useState({ cpu: Array(30).fill(0), up: Array(30).fill(0), down: Array(30).fill(0) });
  const [showConfirm, setShowConfirm] = useState(false);
  const [enabling, setEnabling] = useState(false);
  const [hideIP, setHideIP] = useState(() => localStorage.getItem('probeHideIP') === 'true');
  const [cpuExpanded, setCpuExpanded] = useState(false);
  const [probeError, setProbeError] = useState(null);
  const probeErrorCountRef = useRef(0);
  const staticInfoRef = useRef(null);
  const activeRef = useRef(active);
  useEffect(() => { activeRef.current = active; }, [active]);
  // ponytail: 跟踪当前 sessionId，用于丢弃切换服务器前在飞的异步响应（key remount 下冗余但安全）
  const activeSessionIdRef = useRef(sessionId);
  useEffect(() => { activeSessionIdRef.current = sessionId; }, [sessionId]);

  // 切换服务器时立即清空旧数据和静态缓存
  useEffect(() => {
    setInfo(null);
    staticInfoRef.current = null;
    setHist({ cpu: Array(30).fill(0), up: Array(30).fill(0), down: Array(30).fill(0) });
    setCpuExpanded(false);
    setProbeError(null);
    probeErrorCountRef.current = 0;
  }, [sessionId]);

  // 启用监控时获取一次静态信息（OS/时区/主机名/CPU 型号）
  // ponytail: 已缓存则跳过，避免重复 IPC
  useEffect(() => {
    if (!enabled || !active || !sessionId) return;
    if (staticInfoRef.current) return;
    let mounted = true;
    (async () => {
      try {
        const data = await AppGo.GetServerStaticInfo(sessionId);
        if (!mounted || !activeRef.current || activeSessionIdRef.current !== sessionId) return;
        staticInfoRef.current = {
          os: data.os || 'Linux',
          timezone: data.timezone || 'UTC',
          cpuModel: data.cpu?.model || '',
          ip: data.ip || '',
        };
      } catch (_) {
        if (!mounted || !activeRef.current || activeSessionIdRef.current !== sessionId) return;
        staticInfoRef.current = { os: 'Linux', timezone: 'UTC', cpuModel: '', ip: '' };
      }
    })();
    return () => { mounted = false; };
  }, [enabled, active, sessionId]);

  const handleShowAllProcesses = useCallback(() => {
    if (!sessionId || !onShowAllProcesses) return;
    onShowAllProcesses();
  }, [sessionId, onShowAllProcesses]);

  const handleShowNetworkDetails = useCallback(() => {
    if (!sessionId || !onShowNetworkDetails) return;
    onShowNetworkDetails();
  }, [sessionId, onShowNetworkDetails]);

  const fetchInfo = useCallback(async () => {
    if (!sessionId || !enabled || !activeRef.current) return;
    try {
      const data = await AppGo.SystemInfo(sessionId);
      if (!activeRef.current || activeSessionIdRef.current !== sessionId) return; // 切换服务器后丢弃旧响应
      const si = staticInfoRef.current || { os: 'Linux', timezone: 'UTC', cpuModel: '' };
      const uptimeData = data.uptime || {};
      let uptimeStr = t('0 小时');
      if (uptimeData.days > 0) {
        uptimeStr = `${uptimeData.days}${t('天')} ${uptimeData.hours}${t('小时')}`;
      } else if (uptimeData.hours > 0) {
        uptimeStr = `${uptimeData.hours}${t('小时')} ${uptimeData.mins}${t('分')}`;
      } else {
        uptimeStr = `${uptimeData.mins || 0}${t('分钟')}`;
      }
      const ni = {
        ...si,
        uptime: uptimeStr,
        cpuUsage: data.cpu?.usage || 0,
        cpuCores: data.cpu?.cores || [],
        memUsed: data.memory?.used || 0,
        memTotal: data.memory?.total || 0,
        memCache: data.memory?.cache || 0,
        memFree: data.memory?.free || 0,
        swapTotal: data.memory?.swapTotal || 0,
        swapUsed: data.memory?.swapUsed || 0,
        diskDevice: data.disk?.device || 'disk',
        diskType: data.disk?.type || 'ext4',
        diskTotal: data.disk?.total || 0,
        diskUsed: data.disk?.used || 0,
        diskPercent: data.disk?.usage || 0,
        diskReadSpeed: data.disk?.readSpeed || 0,
        diskWriteSpeed: data.disk?.writeSpeed || 0,
        diskPartitions: data.disk?.partitions || [],
        netUp: data.network?.uploadSpeed || 0,
        netDown: data.network?.downloadSpeed || 0,
        netUpTotal: data.network?.uploadTotal || 0,
        netDownTotal: data.network?.downloadTotal || 0,
        processes: data.processes || [],
      };
      setInfo(ni);
      setHist(prev => ({
        cpu: [...prev.cpu, ni.cpuUsage].slice(-30),
        up: [...prev.up, ni.netUp].slice(-30),
        down: [...prev.down, ni.netDown].slice(-30),
      }));
      probeErrorCountRef.current = 0;
      setProbeError(false);
    } catch (_) {
      probeErrorCountRef.current += 1;
      if (probeErrorCountRef.current >= 3) {
        setProbeError(true);
      }
    }
  }, [sessionId, enabled]);

  const probeTimerRef = useRef(null);

  // ── 读取探针刷新间隔（localStorage，默认 3s）────────────
  const getProbeInterval = () => {
    const v = parseInt(localStorage.getItem('probeInterval') || '3', 10);
    return v >= 1 ? v : 5;
  };

  useEffect(() => {
    if (!enabled || !active) return;
    fetchInfo();
    // ponytail: 递归 setTimeout 替代 setInterval，确保上一次 fetchInfo 完成后才排下一次，
    // 避免慢网络下多个 SystemInfo 并发在飞（请求堆叠 + 加剧竞态）
    const scheduleNext = () => {
      probeTimerRef.current = setTimeout(async () => {
        await fetchInfo();
        if (probeTimerRef.current !== null && activeRef.current) scheduleNext();
      }, getProbeInterval() * 1000);
    };
    scheduleNext();
    const onIntervalChange = () => {
      if (probeTimerRef.current) clearTimeout(probeTimerRef.current);
      if (activeRef.current) scheduleNext();
    };
    window.addEventListener('probeIntervalChanged', onIntervalChange);
    return () => {
      if (probeTimerRef.current) {
        clearTimeout(probeTimerRef.current);
        probeTimerRef.current = null;
      }
      window.removeEventListener('probeIntervalChanged', onIntervalChange);
    };
  }, [fetchInfo, enabled, active]);

  const handleConfirm = async () => {
    setShowConfirm(false);
    setEnabling(true);
    try {
      await onEnable();
    } catch (err) {
      console.error('Probe enable failed:', err);
    } finally {
      setEnabling(false);
    }
  };

  // ── Not enabled: show welcome panel ──────────────────────────────────
  if (!enabled) {
    return (
      <div style={{ display: 'flex', flexDirection: 'column', height: '100%', background: 'var(--surface-base)', position: 'relative', overflow: 'hidden' }}>
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '20px 16px', gap: 16 }}>
          <div style={{ width: 56, height: 56, borderRadius: 14, background: 'var(--surface-raised)', border: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--text-secondary)' }}><BarChart3 size={26} /></div>
          <div style={{ textAlign: 'center' }}>
            <div style={{ fontSize: 15, fontWeight: 700, color: 'var(--text-primary)', marginBottom: 6 }}>{t('系统监控')}</div>
            <div style={{ fontSize: 12, color: 'var(--text-tertiary)', lineHeight: 1.6, maxWidth: 220 }}>{t('实时查看服务器 CPU、内存、网络和磁盘使用情况')}</div>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6, width: '100%', maxWidth: 220 }}>
            {[[<Cpu size={14} />, t('CPU 每核心实时占用')], [<MemoryStick size={14} />, t('内存甜甜圈图分析')], [<Globe size={14} />, t('网络速率折线图')], [<HardDrive size={14} />, t('磁盘分区挂载表')], [<ClipboardList size={14} />, t('进程热点排行')]].map(([icon, text]) => (
              <div key={text} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 11px', borderRadius: 6, background: 'var(--surface-raised)', border: '1px solid var(--border-light)' }}>
                <span style={{ fontSize: 13, display: 'flex', alignItems: 'center', color: 'var(--text-tertiary)' }}>{icon}</span>
                <span style={{ fontSize: 12, color: 'var(--text-tertiary)' }}>{text}</span>
              </div>
            ))}
          </div>
          <button onClick={() => setShowConfirm(true)} className="btn btn-primary" style={{ marginTop: 8 }}>
            {t('开启监控')}
          </button>
        </div>
        {showConfirm && (
          <div style={{ position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.42)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 14, zIndex: Z.COMPONENT_OVERLAY }}>
            <div style={{ background: 'var(--surface-raised)', border: '1px solid var(--border)', borderRadius: 10, padding: '20px 18px', display: 'flex', flexDirection: 'column', gap: 14, boxShadow: 'var(--shadow-md)', maxWidth: 260 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <span style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--text-tertiary)' }}><Search size={16} /></span>
                <div>
                  <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--text-primary)' }}>{t('注入监控脚本')}</div>
                  <div style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>LuminSSH Probe v2</div>
                </div>
              </div>
              <div style={{ fontSize: 12, color: 'var(--text-tertiary)', lineHeight: 1.7 }}>
                {t('将在服务器写入')} <code style={{ color: 'var(--text-primary)', background: 'var(--surface-sunken)', padding: '2px 5px', borderRadius: 3, fontSize: 11 }}>~/.lumin/probe.sh</code>{t('，轻量监控脚本。')}
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
                {[
                  <div style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11.5, color: 'var(--text-tertiary)' }} key="1"><Check size={12} style={{ flexShrink: 0 }} /> {t('纯 Shell，读取 /proc 文件系统')}</div>,
                  <div style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11.5, color: 'var(--text-tertiary)' }} key="2"><Check size={12} style={{ flexShrink: 0 }} /> {t('无需安装任何软件或依赖')}</div>,
                  <div style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11.5, color: 'var(--text-tertiary)' }} key="3"><Check size={12} style={{ flexShrink: 0 }} /> {t('不修改系统配置，不常驻后台')}</div>,
                  <div style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11.5, color: 'var(--text-tertiary)' }} key="4"><Check size={12} style={{ flexShrink: 0 }} /> {t('断开连接后自动停止采集')}</div>,
                ]}
              </div>
              <div style={{ display: 'flex', gap: 8, marginTop: 4 }}>
                <button onClick={() => setShowConfirm(false)} className="btn btn-secondary btn-sm" style={{ flex: 1 }}>{t('取消')}</button>
                <button onClick={handleConfirm} disabled={enabling} className="btn btn-primary btn-sm" style={{ flex: 1 }}>
                  {enabling ? t('注入中...') : t('确认开启')}
                </button>
              </div>
            </div>
          </div>
        )}
      </div>
    );
  }

  // ── Loading / Error state ─────────────────────────────────────────────
  if (!info) {
    if (probeError) {
      return (
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', gap: 12, padding: 20 }}>
          <div style={{ width: 48, height: 48, borderRadius: '50%', background: 'rgba(var(--danger-rgb,255,77,77),0.12)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--danger)', fontSize: 22 }}>✕</div>
          <div style={{ fontSize: 13, color: 'var(--text-primary)', fontWeight: 600, textAlign: 'center' }}>{t('写入失败，请重试')}</div>
          <div style={{ fontSize: 11.5, color: 'var(--text-tertiary)', textAlign: 'center', maxWidth: 200, lineHeight: 1.5 }}>{t('监控脚本写入服务器失败，请检查连接或权限')}</div>
          <button onClick={() => { setProbeError(false); probeErrorCountRef.current = 0; }} className="btn btn-primary btn-sm" style={{ marginTop: 4 }}>
            {t('重试')}
          </button>
        </div>
      );
    }
    return (
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', gap: 10, color: 'var(--success)', opacity: 0.5 }}>
        <div style={{ fontSize: 22, animation: 'spin 1.2s linear infinite' }}>⟳</div>
        <div style={{ fontSize: 11 }}>{t('正在采集系统信息...')}</div>
      </div>
    );
  }

  const memPct = info.memTotal > 0 ? Math.round((info.memUsed / info.memTotal) * 100) : 0;
  const cores = info.cpuCores?.length > 0 ? info.cpuCores : [info.cpuUsage];
  const cpuAvg = Math.round(cores.reduce((a, b) => a + b, 0) / cores.length);
  const osParts = info.os?.split(' ') || ['Linux'];

  const displayIP = info.ip && !isInternalIP(info.ip) ? info.ip : host;

  return (
    <div className="probe-panel" style={{ display: 'flex', flexDirection: 'column', gap: 6, padding: '8px 8px', overflowY: 'auto', height: '100%', boxSizing: 'border-box' }}>

      {/* ── 系统 ── */}
      <Card>
        <div style={{ marginBottom: 6 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>
            <span style={{ display: 'flex', alignItems: 'center', color: 'var(--text-tertiary)' }}><Monitor size={14} /></span>
            <span style={{ fontSize: 13, fontWeight: 700, color: 'var(--text-primary)' }}>{t('系统')}</span>
          </div>
          {displayIP && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 3, minWidth: 0 }}>
              <span title={hideIP ? '' : displayIP} style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--accent)', fontWeight: 700, background: 'var(--accent-dim)', border: '1px solid var(--accent-border)', padding: '2px 8px', borderRadius: 4, maxWidth: 220, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', flexShrink: 1 }}>
                {hideIP ? '***.***.***.***' : displayIP}
              </span>
              <Tiptop text={t('复制 IP')} placement="bottom">
                <button onClick={() => { navigator.clipboard.writeText(displayIP); addToast?.(t('已复制') + ' ' + displayIP, 'success'); }}
                  aria-label={t('复制 IP')}
                  className="probe-icon-btn"><Clipboard size={13} /></button>
              </Tiptop>
              <Tiptop text={hideIP ? t('显示 IP') : t('隐藏 IP')} placement="bottom">
                <button onClick={() => setHideIP(p => { const next = !p; localStorage.setItem('probeHideIP', next); return next; })}
                  aria-label={hideIP ? t('显示 IP') : t('隐藏 IP')}
                  className="probe-icon-btn">{hideIP ? <Eye size={13} /> : <EyeOff size={13} />}</button>
              </Tiptop>
            </div>
          )}
        </div>
        <div style={{ display: 'flex', gap: 5, marginBottom: 6 }}>
          <span style={{ fontSize: 11.5, padding: '2px 8px', borderRadius: 4, background: 'rgba(var(--accent-rgb),0.12)', border: '1px solid rgba(var(--accent-rgb),0.3)', color: 'var(--success)', fontWeight: 700 }}>{osParts[0]}</span>
          <span style={{ fontSize: 11.5, padding: '2px 8px', borderRadius: 4, background: 'var(--surface-sunken)', border: '1px solid var(--border)', color: 'var(--text-tertiary)', flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{info.os?.replace(osParts[0], '').trim()}</span>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '4px 8px' }}>
          <div style={{ fontSize: 12, color: 'var(--text-tertiary)' }}>{t('时区')} <span style={{ color: 'var(--success)', fontFamily: 'var(--font-mono)', fontSize: 12 }}>{info.timezone}</span></div>
          <div style={{ fontSize: 12, color: 'var(--text-tertiary)' }}>{t('运行')} <span style={{ color: 'var(--success)', fontFamily: 'var(--font-mono)', fontWeight: 600, fontSize: 12 }}>{info.uptime}</span></div>
        </div>
      </Card>

      {/* ── CPU ── */}
      <Card>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 6 }}>
          <span style={{ display: 'flex', alignItems: 'center', color: 'var(--info)' }}><Cpu size={14} /></span>
          <span style={{ fontSize: 13.5, fontWeight: 700, color: 'var(--text-primary)', flex: 1 }}>CPU {cores.length > 0 ? `${cores.length}${t('核')}` : ''}</span>
          <span className="badge" style={{ fontFamily: 'var(--font-mono)', fontWeight: 700 }}>{cpuAvg}%</span>
        </div>
        <div style={{ marginBottom: 8 }}>
          <Sparkline data={hist.cpu} color="var(--info)" height={36} />
        </div>
        {info.cpuModel && <div style={{ fontSize: 11.5, color: 'var(--text-tertiary)', marginBottom: 6, wordBreak: 'break-all' }}>{info.cpuModel}</div>}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
          {(cores.length > 8 && !cpuExpanded ? cores.slice(0, 8) : cores).map((val, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ fontSize: 12, color: 'var(--success)', fontFamily: 'var(--font-mono)', width: 16, textAlign: 'right', flexShrink: 0 }}>{i}</span>
              <CpuBar val={val} />
              <span style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text-tertiary)', width: 38, textAlign: 'right', flexShrink: 0 }}>{val.toFixed(1)}%</span>
            </div>
          ))}
        </div>
        {cores.length > 8 && (
          <button onClick={() => setCpuExpanded(v => !v)} style={{ display: 'block', width: '100%', marginTop: 6, padding: '4px 0', fontSize: 11, color: 'var(--info)', background: 'rgba(var(--info-rgb),0.08)', border: '1px solid rgba(var(--info-rgb),0.2)', borderRadius: 5, cursor: 'pointer', textAlign: 'center' }}>
            {cpuExpanded ? t('收起') : `${t('展开全部')} ${cores.length} ${t('核')}`}
          </button>
        )}
      </Card>

      {/* ── 内存 ── */}
      <Card>
        <SectionHeader icon={<MemoryStick size={14} />} title={t('内存')} badge={fmem(info.memTotal)} />
        <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
          <MemDonut used={info.memUsed} cache={info.memCache} free={info.memFree} total={info.memTotal} />
          <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 5 }}>
            {[
              { dot: 'var(--danger)', label: t('已用'), val: fmem(info.memUsed) },
              { dot: 'var(--warning)', label: t('缓存'), val: fmem(info.memCache) },
              { dot: 'var(--success)', label: t('空闲'), val: fmem(info.memFree) },
            ].map(({ dot, label, val }) => (
              <div key={label} style={{ display: 'flex', alignItems: 'center', gap: 6, background: 'var(--surface-overlay)', borderRadius: 6, padding: '4px 8px' }}>
                <span style={{ width: 7, height: 7, borderRadius: '50%', background: dot, flexShrink: 0 }} />
                <span style={{ fontSize: 12.5, color: 'var(--text-tertiary)', flex: 1 }}>{label}</span>
                <span style={{ fontSize: 13.5, fontFamily: 'var(--font-mono)', color: 'var(--text-primary)', fontWeight: 600 }}>{val}</span>
              </div>
            ))}
          </div>
        </div>
        <div style={{ fontSize: 12.5, color: 'var(--text-tertiary)', textAlign: 'right', marginTop: 4 }}>
          {t('使用率')} <span style={{ color: memPct >= 80 ? 'var(--danger)' : 'var(--success)', fontWeight: 700 }}>{memPct}%</span>
        </div>
        {info.swapTotal > 0 && (
          <div style={{ marginTop: 8, paddingTop: 6, borderTop: '1px solid var(--border)' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>
              <span style={{ fontSize: 11.5, color: 'var(--text-tertiary)', display: 'inline-flex', alignItems: 'center', gap: 4 }}><ArrowLeftRight size={12} /> SWAP</span>
              <span style={{ fontSize: 11.5, fontFamily: 'var(--font-mono)', color: 'var(--text-tertiary)' }}>{fmem(info.swapTotal)}</span>
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <div style={{ flex: 1, height: 5, background: 'var(--border)', borderRadius: 3, overflow: 'hidden' }}>
                <div style={{ width: `${Math.min(info.swapUsed / info.swapTotal * 100, 100)}%`, height: '100%', background: 'var(--info)', borderRadius: 3 }} />
              </div>
              <span style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--info)', fontWeight: 600, minWidth: 50, textAlign: 'right' }}>{fmem(info.swapUsed)}</span>
              <span style={{ fontSize: 11.5, fontFamily: 'var(--font-mono)', color: 'var(--text-tertiary)', minWidth: 36, textAlign: 'right' }}>{Math.round(info.swapUsed / info.swapTotal * 100)}%</span>
            </div>
          </div>
        )}
      </Card>

      {/* ── 网络 ── */}
      <Card>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>
          <span style={{ display: 'flex', alignItems: 'center', color: 'var(--text-tertiary)' }}><Globe size={14} /></span>
          <span style={{ fontSize: 13.5, fontWeight: 700, color: 'var(--text-primary)', flex: 1 }}>{t('网络')}</span>
          <span onClick={handleShowNetworkDetails} style={{ fontSize: 11.5, color: 'var(--accent)', cursor: 'pointer', userSelect: 'none' }}>{t('查看详情')}</span>
        </div>
        <div style={{ marginBottom: 6 }}>
          <Sparkline data={hist.down} color="var(--accent)" height={36} />
        </div>
        {/* Table */}
        <div style={{ display: 'grid', gridTemplateColumns: '62px 1fr 1fr', gap: '5px 0' }}>
          <div style={{ fontSize: 11.5, color: 'var(--text-tertiary)' }} />
          <div style={{ fontSize: 11.5, color: 'var(--text-tertiary)', textAlign: 'center' }}>{t('速度')}</div>
          <div style={{ fontSize: 11.5, color: 'var(--text-tertiary)', textAlign: 'center' }}>{t('已用流量')}</div>
          {[
            { dot: 'var(--success)', label: t('上传'), speed: fspeed(info.netUp), total: ftotal(info.netUpTotal) },
            { dot: 'var(--accent)', label: t('下载'), speed: fspeed(info.netDown), total: ftotal(info.netDownTotal) },
          ].map(({ dot, label, speed, total }) => (
            <Fragment key={label}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 12.5, padding: '3px 0' }}>
                <span style={{ width: 7, height: 7, borderRadius: '50%', background: dot }} />
                <span style={{ color: 'var(--text-tertiary)' }}>{label}</span>
              </div>
              <div style={{ fontSize: 13, fontFamily: 'var(--font-mono)', color: 'var(--text-primary)', fontWeight: 600, textAlign: 'center', alignSelf: 'center' }}>{speed}</div>
              <div style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text-tertiary)', textAlign: 'center', alignSelf: 'center' }}>{total}</div>
            </Fragment>
          ))}
        </div>
      </Card>

      {/* ── 磁盘 ── */}
      <Card>
        <SectionHeader icon={<HardDrive size={14} />} title={t('磁盘')} badge={`${formatCapacity(info.diskUsed, 1)} / ${formatCapacity(info.diskTotal, 1)}`} />
        {/* Root partition info */}
        <div style={{ display: 'flex', alignItems: 'center', marginBottom: 7 }}>
          <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--success)', marginRight: 5 }} />
          <span style={{ fontSize: 12.5, color: 'var(--text-tertiary)', flex: 1, fontFamily: 'var(--font-mono)' }}>/ ({info.diskDevice})</span>
          <span style={{ fontSize: 11.5, color: 'var(--text-tertiary)', marginRight: 4 }}>{t('类型')}</span>
          <span style={{ fontSize: 11, background: 'var(--warning)', color: '#fff', padding: '1px 6px', borderRadius: 4, fontWeight: 700 }}>{info.diskType}</span>
        </div>
        {/* IO speeds */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6, marginBottom: 7 }}>
          {[
            { label: t('读/s'), val: fspeed(info.diskReadSpeed), color: 'var(--success)' },
            { label: t('写/s'), val: fspeed(info.diskWriteSpeed), color: 'var(--warning)' },
          ].map(({ label, val, color }) => (
            <div key={label} style={{ background: 'var(--surface-overlay)', borderRadius: 6, padding: '5px 8px' }}>
              <div style={{ fontSize: 11.5, color: 'var(--text-tertiary)', marginBottom: 2 }}>{label}</div>
              <div style={{ fontSize: 13.5, fontFamily: 'var(--font-mono)', color, fontWeight: 700 }}>{val}</div>
            </div>
          ))}
        </div>
        {/* Partition table header */}
        <div className="probe-partition-header">
          <span>{t('挂载')}</span>
          <span></span>
          <span>{t('大小')}</span>
          <span>{t('可用')}</span>
          <span>{t('已用%')}</span>
        </div>
        {(info.diskPartitions?.length > 0
          ? info.diskPartitions.slice(0, 4)
          : [{ mount: '/', size: `${info.diskTotal?.toFixed(0)}G`, avail: `${(info.diskTotal - info.diskUsed)?.toFixed(1)}G`, usedPct: Math.round(info.diskPercent) }]
        ).map((p, i) => (
          <PartRow key={i} mount={p.mount} size={p.size} avail={p.avail} usedPct={p.usedPct} />
        ))}
      </Card>

      {/* ── 进程管理 ── */}
      <Card style={{ marginBottom: 8 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 8 }}>
          <span style={{ display: 'flex', alignItems: 'center', color: 'var(--text-tertiary)' }}><ClipboardList size={14} /></span>
          <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--text-primary)', flex: 1 }}>{t('进程管理')}</span>
          <span onClick={handleShowAllProcesses} style={{ fontSize: 11.5, color: 'var(--accent)', cursor: 'pointer', userSelect: 'none' }}>{t('查看全部')}</span>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '44px 56px 1fr', gap: '4px 8px' }}>
          <span style={{ fontSize: 11.5, color: 'var(--text-tertiary)', fontWeight: 700 }}>CPU</span>
          <span style={{ fontSize: 11.5, color: 'var(--text-tertiary)', fontWeight: 700 }}>{t('内存')}</span>
          <span style={{ fontSize: 11.5, color: 'var(--text-tertiary)', fontWeight: 700 }}>{t('进程')}</span>
          {info.processes?.length > 0 ? info.processes.slice(0, 5).map((p, i) => (
            <Fragment key={i}>
              <span style={{ fontSize: 11.5, fontFamily: 'var(--font-mono)', color: p.cpu > 5 ? 'var(--warning)' : 'var(--text-tertiary)' }}>{p.cpu?.toFixed(1)}%</span>
              <span style={{ fontSize: 11.5, fontFamily: 'var(--font-mono)', color: 'var(--text-tertiary)' }}>{fmem(p.mem)}</span>
              <span style={{ fontSize: 11.5, fontFamily: 'var(--font-mono)', color: 'var(--text-primary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.cmd}</span>
            </Fragment>
          )) : (
            <div style={{ gridColumn: '1/-1', fontSize: 11.5, color: 'var(--text-tertiary)', textAlign: 'center', padding: '8px 0' }}>{t('暂无热点进程')}</div>
          )}
        </div>
      </Card>

    </div>
  );
}
