import { useWebSocket } from '../hooks/useWebSocket';
import { api } from '../api/client';
import { useState, useEffect, useMemo, lazy, Suspense, type CSSProperties } from 'react';
import { Link } from 'react-router-dom';
import type { Share, ServerConfig } from '../types';
import { getSetupStatus } from '../help/setupStatus';
import SetupBanner from '../components/SetupBanner';
import GaugeRing from '../components/Charts/GaugeRing';
import NeonCard from '../components/NeonCard/NeonCard';
import { FleetPipelineStatus, ActivityPulse } from '../components/Visual/VisualComponents';
import {
  AlertBanner,
  PoolStatusPanel,
  AIActivityPanel,
  EarningsEstimator,
  FleetHealthCard,
  ContributionBars,
  UnderperformerList,
  OSArchBreakdown,
  LANGroupView,
} from '../components/Fleet/FleetPanels';
import AgentRemoteActions from '../components/Fleet/AgentRemoteActions';
import FleetToolbar from '../components/Fleet/FleetToolbar';
import ErrorBoundary from '../components/ErrorBoundary';

const HashrateChart = lazy(() => import('../components/Charts/HashrateChart'));
const FleetTopologyMap = lazy(() => import('../components/Visual/3D/FleetTopologyMap'));
const MatrixStreamOverlay = lazy(() => import('../components/Visual/MatrixStreamOverlay'));

function ChartPlaceholder({ height }: { height: number }) {
  return <div style={{ height, opacity: 0.35 }} className="font-tech" aria-hidden />;
}
import {
  DEFAULT_FLEET_FILTERS,
  filterFleetAgents,
  agentIsIdleMiner,
  formatHashrate,
  formatUptime,
} from '../help/fleetFilters';
import type { FleetFilterState } from '../help/fleetFilters';
import {
  computeFleetHealth,
  contributionBars,
  findUnderperformers,
  fleetMedianHashrate,
  groupBySubnet,
  osArchBreakdown,
} from '../help/fleetAnalytics';
import './Pages.css';

/** Format GPU KawPoW hashrate (H/s units, displayed as MH/s or GH/s). */
function formatGPUHashrate(hps: number): string {
  if (!hps || hps <= 0) return '0 H/s';
  if (hps >= 1e9) return `${(hps / 1e9).toFixed(2)} GH/s`;
  if (hps >= 1e6) return `${(hps / 1e6).toFixed(2)} MH/s`;
  if (hps >= 1e3) return `${(hps / 1e3).toFixed(2)} KH/s`;
  return `${hps.toFixed(0)} H/s`;
}

export default function DashboardPage() {
  const { isConnected, agents, recentShares, fleetAlerts, poolStatus, aiActivity } = useWebSocket();
  const [shares, setShares] = useState<Share[]>([]);
  const [restAlerts, setRestAlerts] = useState<typeof fleetAlerts>([]);
  const [restPools, setRestPools] = useState<typeof poolStatus>([]);
  const [restAI, setRestAI] = useState<typeof aiActivity>([]);
  const [subtitle, setSubtitle] = useState('security is just an emotion');
  const [hashHistory, setHashHistory] = useState<{ time: string; value: number }[]>([]);
  const [acceptHistory, setAcceptHistory] = useState<{ time: string; value: number }[]>([]);
  const [cpuHistory, setCpuHistory] = useState<{ time: string; value: number }[]>([]);
  const [memHistory, setMemHistory] = useState<{ time: string; value: number }[]>([]);
  const [hasBuilds, setHasBuilds] = useState(false);
  const [filters, setFilters] = useState<FleetFilterState>(DEFAULT_FLEET_FILTERS);
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
  const [bulkBusy, setBulkBusy] = useState(false);
  const [showMatrix, setShowMatrix] = useState(false);
  const [advancedMode, setAdvancedMode] = useState<boolean>(() => {
    try { return localStorage.getItem('aether-dash-advanced') === '1'; } catch { return false; }
  });
  const [xmrPrice, setXmrPrice] = useState<number | null>(null);
  const [calibrateConfig, setCalibrateConfig] = useState<ServerConfig | null>(null);

  const toggleAdvanced = () =>
    setAdvancedMode((prev) => {
      const next = !prev;
      try { localStorage.setItem('aether-dash-advanced', next ? '1' : '0'); } catch { /* ignore */ }
      return next;
    });

  useEffect(() => {
    api.getRecentShares(20).then(setShares).catch(console.error);
    api.listBuilds().then((b) => setHasBuilds(b.length > 0)).catch(console.error);
    api.getConfig()
      .then((cfg) => {
        setCalibrateConfig(cfg);
        const s = cfg.server?.dashboard_subtitle?.trim();
        if (s) setSubtitle(s);
      })
      .catch(console.error);
    api.getAlerts().then(setRestAlerts).catch(console.error);
    api.getPoolStatus().then(setRestPools).catch(console.error);
    api.getAIActivity().then(setRestAI).catch(console.error);
    // XMR market price — refresh every 10 min matching server-side cache TTL
    const fetchPrice = () => api.getXmrPrice().then((r) => setXmrPrice(r.usd)).catch(() => {});
    fetchPrice();
    const priceTimer = setInterval(fetchPrice, 10 * 60 * 1000);
    return () => clearInterval(priceTimer);
  }, []);

  useEffect(() => {
    if (recentShares.length > 0) {
      setShares((prev) => {
        const merged = [...recentShares, ...prev];
        const seen = new Set<string>();
        return merged.filter((s) => {
          const key = s.id != null ? String(s.id) : `${s.agent_id}-${s.hash}-${s.timestamp}`;
          if (seen.has(key)) return false;
          seen.add(key);
          return true;
        }).slice(0, 20);
      });
    }
  }, [recentShares]);

  const totalHashrate = agents.reduce((sum, a) => sum + a.hashrate_15m, 0);
  const onlineCount = agents.filter((a) => a.status === 'online').length;
  const totalShares = agents.reduce((sum, a) => sum + a.shares_total, 0);
  const acceptedShares = agents.reduce((sum, a) => sum + a.shares_good, 0);
  const rejectedShares = agents.reduce((sum, a) => sum + a.shares_bad, 0);
  const acceptRate = totalShares > 0 ? (acceptedShares / totalShares) * 100 : 0;

  // ── Ravencoin / GPU fleet stats ────────────────────────────────────────────
  const gpuAgents = useMemo(
    () => agents.filter((a) => a.gpu_miner_active && a.status === 'online'),
    [agents]
  );
  const totalGPUHashrate = useMemo(
    () => gpuAgents.reduce((sum, a) => sum + (a.gpu_hashrate_15m ?? 0), 0),
    [gpuAgents]
  );
  const gpuHashrate15s = useMemo(
    () => gpuAgents.reduce((sum, a) => sum + (a.gpu_hashrate_15s ?? 0), 0),
    [gpuAgents]
  );
  const bestGPUAgent = useMemo(
    () => gpuAgents.sort((a, b) => (b.gpu_hashrate_15m ?? 0) - (a.gpu_hashrate_15m ?? 0))[0] ?? null,
    [gpuAgents]
  );
  const gpuModels = useMemo(
    () => [...new Set(gpuAgents.map((a) => a.gpu_model).filter(Boolean))],
    [gpuAgents]
  );
  const hasGPUMining = gpuAgents.length > 0;
  const avgCpu = agents.length > 0 ? agents.reduce((s, a) => s + a.cpu_usage_pct, 0) / agents.length : 0;
  const avgMem = agents.length > 0 ? agents.reduce((s, a) => s + a.memory_usage_pct, 0) / agents.length : 0;
  const onlinePct = agents.length > 0 ? (onlineCount / agents.length) * 100 : 0;

  useEffect(() => {
    const now = new Date().toLocaleTimeString();
    setHashHistory((prev) => [...prev.slice(-59), { time: now, value: totalHashrate }]);
    setAcceptHistory((prev) => [...prev.slice(-59), { time: now, value: acceptRate }]);
    setCpuHistory((prev) => [...prev.slice(-59), { time: now, value: avgCpu }]);
    setMemHistory((prev) => [...prev.slice(-59), { time: now, value: avgMem }]);
  }, [totalHashrate, acceptRate, avgCpu, avgMem]);

  const filteredAgents = useMemo(() => filterFleetAgents(agents, filters), [agents, filters]);

  const topAgents = useMemo(
    () => [...filteredAgents].sort((a, b) => b.hashrate_15m - a.hashrate_15m).slice(0, 12),
    [filteredAgents]
  );
  const maxAgentHash = Math.max(...topAgents.map((a) => a.hashrate_15m), 1);

  const activityItems = useMemo(
    () =>
      shares.slice(0, 12).map((s) => ({
        id: String(s.id ?? `${s.agent_id}-${s.hash}`),
        label: s.accepted ? 'OK' : 'BAD',
        ok: s.accepted,
        time: s.timestamp ? new Date(s.timestamp).toLocaleTimeString() : undefined,
      })),
    [shares]
  );

  const totalShareCount = agents.reduce((sum, a) => sum + a.shares_total, 0);
  const alerts = fleetAlerts.length > 0 ? fleetAlerts : restAlerts;
  const pools = poolStatus.length > 0 ? poolStatus : restPools;
  const aiEntries = aiActivity.length > 0 ? aiActivity : restAI;
  const agentNameMap = useMemo(
    () => Object.fromEntries(agents.map((a) => [a.id, a.name])),
    [agents]
  );

  // ── Extra pretty numbers ───────────────────────────────────────────────────
  const bestAgent = useMemo(
    () => agents.filter((a) => a.status === 'online').sort((a, b) => b.hashrate_15m - a.hashrate_15m)[0] ?? null,
    [agents]
  );
  const totalCores = useMemo(
    () => agents.filter((a) => a.status === 'online').reduce((s, a) => s + (a.cpu_cores || 0), 0),
    [agents]
  );
  const totalUptimeHours = useMemo(
    () => agents.reduce((s, a) => s + (a.uptime_seconds || 0), 0) / 3600,
    [agents]
  );
  const sharesPerHour = useMemo(() => {
    // Estimate from recent share log timestamps
    if (shares.length < 2) return 0;
    const times = shares.map((s) => new Date(s.timestamp).getTime()).filter((t) => !isNaN(t)).sort((a, b) => b - a);
    if (times.length < 2) return 0;
    const spanMs = times[0] - times[times.length - 1];
    if (spanMs <= 0) return 0;
    return Math.round((times.length / spanMs) * 3_600_000);
  }, [shares]);

  // ── Resource pressure fleet stats ─────────────────────────────────────────
  const onlineAgents = useMemo(() => agents.filter(a => a.status === 'online'), [agents]);

  const hottestNode = useMemo(() => {
    let best: typeof agents[0] | null = null;
    let max = -Infinity;
    for (const a of onlineAgents) {
      const t = a.gpu_temp_c ?? a.cpu_temp_c ?? -1;
      if (t > max) { max = t; best = a; }
    }
    return best && max > 0 ? { agent: best, temp: max } : null;
  }, [onlineAgents]);

  const minDiskNode = useMemo(() => {
    let best: typeof agents[0] | null = null;
    let min = Infinity;
    for (const a of onlineAgents) {
      if (a.disk_free_pct !== undefined && a.disk_free_pct < min) {
        min = a.disk_free_pct; best = a;
      }
    }
    return best ? { agent: best, pct: min } : null;
  }, [onlineAgents]);

  const throttledCount = useMemo(
    () => onlineAgents.filter(a => a.cpu_throttle).length,
    [onlineAgents]
  );

  // ── Analytics ─────────────────────────────────────────────────────────────
  const fleetHealth = useMemo(() => computeFleetHealth(agents, pools), [agents, pools]);
  const contribs = useMemo(() => contributionBars(agents), [agents]);
  const underperformers = useMemo(() => findUnderperformers(agents), [agents]);
  const medianHash = useMemo(() => fleetMedianHashrate(agents), [agents]);
  const lanGroups = useMemo(() => groupBySubnet(agents), [agents]);
  const platforms = useMemo(() => osArchBreakdown(agents), [agents]);

  const handleBulkAction = async (action: string) => {
    let targetIds = [...selectedIds];
    if (action === 'restart_idle') {
      targetIds = agents.filter((a) => selectedIds.has(a.id) && agentIsIdleMiner(a)).map((a) => a.id);
      if (targetIds.length === 0) {
        alert('No selected online agents with idle hashrate.');
        return;
      }
      action = 'restart';
    }
    const onlineIds = targetIds.filter((id) => agents.find((a) => a.id === id)?.status === 'online');
    if (onlineIds.length === 0) return;
    if (action === 'stop' && !window.confirm(`Stop ${onlineIds.length} agent(s)?`)) return;
    setBulkBusy(true);
    try {
      await api.sendBulkCommand(onlineIds, action);
    } catch (err) {
      console.error(err);
      alert(err instanceof Error ? err.message : 'Bulk command failed');
    } finally {
      setBulkBusy(false);
    }
  };

  const setupStatus = getSetupStatus(calibrateConfig);

  return (
    <div className="page fade-in command-deck">
      <SetupBanner status={setupStatus} />
      <AlertBanner alerts={alerts} />

      {/* Fleet Health — always above the fold */}
      <FleetHealthCard health={fleetHealth} />

      <header className="deck-hero">
        <div className="deck-hero-text">
          <p className="deck-eyebrow font-tech">PERSONAL NETWORK · LIVE TELEMETRY</p>
          <h1>Command Deck</h1>
          <p className="page-subtitle">{subtitle}</p>
        </div>
        <div className="deck-hero-status">
          <div className={`live-beacon ${isConnected ? 'on' : ''}`}>
            <span className="beacon-ring" />
            <span className="beacon-core" />
          </div>
          <div>
            <span className="font-tech live-label">{isConnected ? 'SIGNAL LOCKED' : 'RECONNECTING'}</span>
            <span className="live-sub">{agents.length} nodes registered</span>
          </div>
          <button
            className={`dash-mode-btn${advancedMode ? ' active' : ''}`}
            onClick={toggleAdvanced}
            title={advancedMode ? 'Switch to Overview (hide charts / logs)' : 'Switch to Advanced (show all panels)'}
          >
            {advancedMode ? '[OVERVIEW]' : '[ADVANCED]'}
          </button>
          {advancedMode && (
            <button
              className="button matrix-toggle-btn"
              onClick={() => setShowMatrix(true)}
              style={{ background: 'transparent', border: '1px solid #0f0', color: '#0f0', fontFamily: 'monospace' }}
            >
              [RAW_STREAM]
            </button>
          )}
        </div>
      </header>

      <NeonCard accent="green" className="section" hud>
        <h2 className="section-title font-display" style={{ marginBottom: '0.25rem' }}>
          <span className="section-ornament">◆</span> Fleet Pipeline
          <span className="section-line" />
        </h2>
        <p className="form-hint" style={{ marginTop: 0 }}>
          Visual progress — lit nodes mean that stage is active. <Link to="/guide">Open Field Guide →</Link>
        </p>
        <FleetPipelineStatus
          hasBuilds={hasBuilds}
          agentCount={agents.length}
          onlineCount={onlineCount}
          hasHashrate={totalHashrate > 0}
          hasShares={totalShareCount > 0}
        />
      </NeonCard>

      <section className="gauge-row">
        <NeonCard accent="cyan" className="gauge-card" hud>
          <GaugeRing
            value={totalHashrate}
            max={Math.max(totalHashrate * 1.2, 1000)}
            label="Fleet Hash"
            sublabel="15m avg"
            color="var(--neon-cyan)"
            size={110}
          />
        </NeonCard>
        <NeonCard accent="green" className="gauge-card" hud>
          <GaugeRing value={onlinePct} label="Online" sublabel={`${onlineCount}/${agents.length}`} color="var(--neon-green)" size={110} />
        </NeonCard>
        <NeonCard accent="purple" className="gauge-card" hud>
          <GaugeRing value={acceptRate} label="Accept" sublabel="share rate" color="var(--neon-purple)" size={110} />
        </NeonCard>
        <NeonCard accent="amber" className="gauge-card" hud>
          <GaugeRing value={avgCpu} label="CPU" sublabel={`RAM ${avgMem.toFixed(0)}%`} color="var(--neon-amber)" size={110} />
        </NeonCard>
      </section>

      <div className="grid-4 stats-grid steampunk-stats">
        <NeonCard accent="cyan" className="stat-card-wrap">
          <div className="stat-label font-tech">Total Hashrate</div>
          <div className="stat-value hashrate neon-glow-cyan">{formatHashrate(totalHashrate)}</div>
          <div className="stat-sub">{onlineCount} engines firing</div>
        </NeonCard>
        <EarningsEstimator hashrate={totalHashrate} xmrPrice={xmrPrice} />
        <NeonCard accent="green" className="stat-card-wrap">
          <div className="stat-label font-tech">Fleet Online</div>
          <div className="stat-value accepted">{onlineCount} <span className="stat-dim">/ {agents.length}</span></div>
          <div className="stat-sub">{agents.length - onlineCount} dormant</div>
        </NeonCard>
        <NeonCard accent="purple" className="stat-card-wrap">
          <div className="stat-label font-tech">Accept Rate</div>
          <div className="stat-value neon-glow-purple">{acceptRate.toFixed(1)}%</div>
          <div className="stat-sub">{acceptedShares} valid · {rejectedShares} rejected</div>
        </NeonCard>
        <NeonCard accent="amber" className="stat-card-wrap">
          <div className="stat-label font-tech">Resources</div>
          <div className="stat-value">{avgCpu.toFixed(0)}% CPU</div>
          <div className="stat-sub">{avgMem.toFixed(0)}% memory · fleet mean</div>
        </NeonCard>

        {/* ── Pretty numbers row ── */}
        <NeonCard accent="gold" className="stat-card-wrap">
          <div className="stat-label font-tech">Top Miner</div>
          {bestAgent ? (
            <>
              <div className="stat-value neon-glow-gold" style={{ fontSize: '1.1rem' }}>
                {bestAgent.name.length > 14 ? bestAgent.name.slice(0, 13) + '…' : bestAgent.name}
              </div>
              <div className="stat-sub">{formatHashrate(bestAgent.hashrate_15m)} · {bestAgent.cpu_cores}c</div>
            </>
          ) : (
            <>
              <div className="stat-value stat-dim">—</div>
              <div className="stat-sub">no miners online</div>
            </>
          )}
        </NeonCard>

        <NeonCard accent="cyan" className="stat-card-wrap">
          <div className="stat-label font-tech">Fleet Compute</div>
          <div className="stat-value neon-glow-cyan">
            {totalCores > 0 ? totalCores.toLocaleString() : '—'}
            <span className="stat-dim" style={{ fontSize: '0.8em' }}> cores</span>
          </div>
          <div className="stat-sub">{onlineCount} nodes active</div>
        </NeonCard>

        <NeonCard accent="green" className="stat-card-wrap">
          <div className="stat-label font-tech">Fleet Uptime</div>
          <div className="stat-value accepted">
            {totalUptimeHours >= 1 ? totalUptimeHours.toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ',') : '< 1'}
            <span className="stat-dim" style={{ fontSize: '0.8em' }}> hrs</span>
          </div>
          <div className="stat-sub">cumulative across fleet</div>
        </NeonCard>

        <NeonCard accent="purple" className="stat-card-wrap">
          <div className="stat-label font-tech">Shares / hr</div>
          <div className="stat-value neon-glow-purple">
            {sharesPerHour > 0 ? sharesPerHour.toLocaleString() : '—'}
          </div>
          <div className="stat-sub">{totalShares.toLocaleString()} total submitted</div>
        </NeonCard>

        {/* ── Resource Pressure cards ──────────────────────────────────────── */}
        <NeonCard
          accent={hottestNode && hottestNode.temp > 80 ? 'amber' : 'cyan'}
          className="stat-card-wrap"
        >
          <div className="stat-label font-tech">Hottest Node</div>
          {hottestNode ? (
            <>
              <div className={`stat-value ${hottestNode.temp > 80 ? 'neon-glow-amber' : 'neon-glow-cyan'}`}>
                {hottestNode.temp}
                <span className="stat-dim" style={{ fontSize: '0.8em' }}>°C</span>
              </div>
              <div className="stat-sub" title={hottestNode.agent.id}>
                {hottestNode.agent.name.length > 14 ? hottestNode.agent.name.slice(0, 13) + '…' : hottestNode.agent.name}
                {hottestNode.temp > 80 && ' ⚠'}
              </div>
            </>
          ) : (
            <>
              <div className="stat-value stat-dim">—</div>
              <div className="stat-sub">no temp data</div>
            </>
          )}
        </NeonCard>

        <NeonCard
          accent={minDiskNode && minDiskNode.pct < 10 ? 'amber' : 'green'}
          className="stat-card-wrap"
        >
          <div className="stat-label font-tech">Min Disk Free</div>
          {minDiskNode ? (
            <>
              <div className={`stat-value ${minDiskNode.pct < 10 ? 'neon-glow-amber' : 'accepted'}`}>
                {minDiskNode.pct}
                <span className="stat-dim" style={{ fontSize: '0.8em' }}>%</span>
              </div>
              <div className="stat-sub" title={minDiskNode.agent.id}>
                {minDiskNode.agent.name.length > 14 ? minDiskNode.agent.name.slice(0, 13) + '…' : minDiskNode.agent.name}
                {minDiskNode.pct < 10 && ' ⚠ low'}
              </div>
            </>
          ) : (
            <>
              <div className="stat-value stat-dim">—</div>
              <div className="stat-sub">no disk data</div>
            </>
          )}
        </NeonCard>

        <NeonCard
          accent={throttledCount > 0 ? 'amber' : 'purple'}
          className="stat-card-wrap"
        >
          <div className="stat-label font-tech">CPU Throttled</div>
          <div className={`stat-value ${throttledCount > 0 ? 'neon-glow-amber' : 'neon-glow-purple'}`}>
            {throttledCount}
            <span className="stat-dim" style={{ fontSize: '0.8em' }}> node{throttledCount !== 1 ? 's' : ''}</span>
          </div>
          <div className="stat-sub">
            {throttledCount === 0 ? 'fleet running at full speed' : `${throttledCount} below 80% rated freq`}
          </div>
        </NeonCard>
      </div>

      {/* ═══════════════════════════════════════════════════════════════════
           MONERO SUBHEADING — clarify the section above belongs to XMR
           ═══════════════════════════════════════════════════════════════════ */}
      <div className="mining-coin-label monero-label">
        <span className="coin-badge xmr-badge">XMR</span>
        <span className="coin-name font-tech">MONERO</span>
        <span className="coin-algo font-tech">· RandomX CPU ·</span>
        <span className="coin-hr font-tech">{formatHashrate(totalHashrate)}</span>
      </div>

      {/* ═══════════════════════════════════════════════════════════════════
           RAVENCOIN GPU SECTION
           ═══════════════════════════════════════════════════════════════════ */}
      {hasGPUMining && (
        <div className="rvn-section">
          <div className="mining-coin-label rvn-label">
            <span className="coin-badge rvn-badge">RVN</span>
            <span className="coin-name font-tech">RAVENCOIN</span>
            <span className="coin-algo font-tech">· KawPoW GPU ·</span>
            <span className="coin-hr font-tech rvn-hashrate">{formatGPUHashrate(totalGPUHashrate)}</span>
          </div>

          {/* Gauge row */}
          <section className="gauge-row rvn-gauges">
            <NeonCard accent="gold" className="gauge-card" hud>
              <GaugeRing
                value={totalGPUHashrate}
                max={Math.max(totalGPUHashrate * 1.2, 1e6)}
                label="GPU Hash"
                sublabel="15m avg"
                color="var(--neon-gold)"
                size={110}
              />
            </NeonCard>
            <NeonCard accent="amber" className="gauge-card" hud>
              <GaugeRing
                value={gpuHashrate15s}
                max={Math.max(gpuHashrate15s * 1.2, 1e6)}
                label="GPU Live"
                sublabel="15s sample"
                color="var(--neon-amber)"
                size={110}
              />
            </NeonCard>
            <NeonCard accent="cyan" className="gauge-card" hud>
              <GaugeRing
                value={gpuAgents.length}
                max={Math.max(agents.length, 1)}
                label="GPU Rigs"
                sublabel={`of ${agents.length} nodes`}
                color="var(--neon-cyan)"
                size={110}
              />
            </NeonCard>
          </section>

          {/* Stats cards */}
          <div className="grid-4 stats-grid rvn-stats-grid">
            <NeonCard accent="gold" className="stat-card-wrap rvn-stat-card">
              <div className="stat-label font-tech">GPU Fleet Hash</div>
              <div className="stat-value rvn-hashrate neon-glow-gold">{formatGPUHashrate(totalGPUHashrate)}</div>
              <div className="stat-sub">{gpuAgents.length} GPU rig{gpuAgents.length !== 1 ? 's' : ''} firing</div>
            </NeonCard>

            <NeonCard accent="amber" className="stat-card-wrap rvn-stat-card">
              <div className="stat-label font-tech">Top GPU Rig</div>
              {bestGPUAgent ? (
                <>
                  <div className="stat-value neon-glow-amber" style={{ fontSize: '1.1rem' }}>
                    {(bestGPUAgent.name.length > 14 ? bestGPUAgent.name.slice(0, 13) + '…' : bestGPUAgent.name)}
                  </div>
                  <div className="stat-sub">{formatGPUHashrate(bestGPUAgent.gpu_hashrate_15m ?? 0)} · {bestGPUAgent.gpu_model ?? 'GPU'}</div>
                </>
              ) : (
                <><div className="stat-value stat-dim">—</div><div className="stat-sub">none active</div></>
              )}
            </NeonCard>

            <NeonCard accent="cyan" className="stat-card-wrap rvn-stat-card">
              <div className="stat-label font-tech">GPU Models</div>
              <div className="stat-value neon-glow-cyan" style={{ fontSize: '1rem', lineHeight: '1.3' }}>
                {gpuModels.length > 0 ? (
                  gpuModels.slice(0, 2).map((m) => (
                    <div key={m} style={{ fontSize: '0.8em', fontFamily: 'var(--font-tech)' }}>{m}</div>
                  ))
                ) : (
                  <span className="stat-dim">—</span>
                )}
              </div>
              <div className="stat-sub">{gpuModels.length} distinct model{gpuModels.length !== 1 ? 's' : ''}</div>
            </NeonCard>

            <NeonCard accent="purple" className="stat-card-wrap rvn-stat-card">
              <div className="stat-label font-tech">GPU Live Rate</div>
              <div className="stat-value neon-glow-purple">{formatGPUHashrate(gpuHashrate15s)}</div>
              <div className="stat-sub">15-second snapshot</div>
            </NeonCard>
          </div>

          {/* Per-rig GPU breakdown */}
          {gpuAgents.length > 0 && (
            <NeonCard accent="gold" className="rvn-rig-table-card" hud>
              <div className="stat-label font-tech" style={{ marginBottom: '0.75rem' }}>GPU Rig Detail</div>
              <div className="rvn-rig-table">
                {gpuAgents.map((a) => {
                  const hr = a.gpu_hashrate_15m ?? 0;
                  const pct = totalGPUHashrate > 0 ? (hr / totalGPUHashrate) * 100 : 0;
                  return (
                    <div key={a.id} className="rvn-rig-row">
                      <span className="rvn-rig-name font-tech">{a.name}</span>
                      <span className="rvn-rig-model">{a.gpu_model ?? '—'}</span>
                      <span className="rvn-rig-hr neon-glow-gold">{formatGPUHashrate(hr)}</span>
                      <div className="rvn-rig-bar-wrap">
                        <div
                          className="rvn-rig-bar"
                          style={{ width: `${pct.toFixed(1)}%` } as React.CSSProperties}
                        />
                      </div>
                      <span className="rvn-rig-pct">{pct.toFixed(1)}%</span>
                      {(a.gpu_temp_c ?? 0) > 0 && (
                        <span className={`rvn-rig-temp ${(a.gpu_temp_c ?? 0) > 80 ? 'temp-hot' : ''}`}>
                          {a.gpu_temp_c}°C
                        </span>
                      )}
                    </div>
                  );
                })}
              </div>
            </NeonCard>
          )}
        </div>
      )}

      {/* ── Analytics row — always visible ─────────────────────────────────── */}
      <ContributionBars bars={contribs} xmrPrice={xmrPrice} />
      <UnderperformerList underperformers={underperformers} medianHashrate={medianHash} />
      {(platforms.length > 0 || lanGroups.length > 1) && (
        <div className="grid-2" style={{ gap: '1rem', marginTop: '1rem' }}>
          <OSArchBreakdown platforms={platforms} />
          <LANGroupView groups={lanGroups} />
        </div>
      )}

      <PoolStatusPanel pools={pools} />

      {/* ── Advanced-only panels ─────────────────────────────────────────────── */}
      {advancedMode && <AIActivityPanel entries={aiEntries} agentNames={agentNameMap} />}

      <Suspense fallback={<ChartPlaceholder height={300} />}>
        <div className="grid-2 chart-row">
          <NeonCard accent="cyan" tilt3d>
            <HashrateChart data={hashHistory} title="Fleet Hashrate Wave" color="#00f5ff" unit="H/s" height={300} />
          </NeonCard>
          <NeonCard accent="purple" tilt3d>
            <HashrateChart data={acceptHistory} title="Accept Rate Pulse" color="#a855f7" unit="%" height={300} />
          </NeonCard>
        </div>
      </Suspense>

      {advancedMode && (
        <Suspense fallback={<ChartPlaceholder height={220} />}>
          <div className="grid-2 chart-row">
            <NeonCard accent="magenta" tilt3d>
              <HashrateChart data={cpuHistory} title="CPU Pressure" color="#ff2da6" unit="%" height={220} />
            </NeonCard>
            <NeonCard accent="brass" tilt3d>
              <HashrateChart data={memHistory} title="Memory Load — Fleet Average" color="#ffb020" unit="%" height={220} />
            </NeonCard>
          </div>
        </Suspense>
      )}

      <NeonCard accent="purple" className="section" hud>
        <h2 className="section-title font-display">
          <span className="section-ornament">◆</span> Share Activity Pulse
          <span className="section-line" />
        </h2>
        <ActivityPulse items={activityItems} />
      </NeonCard>

      <section className="section">
        <ErrorBoundary
          fallback={
            <div className="card">
              <p className="form-hint">3D fleet map unavailable on this GPU — rest of the deck still works.</p>
            </div>
          }
        >
          <Suspense fallback={<ChartPlaceholder height={360} />}>
            <FleetTopologyMap agents={agents} />
          </Suspense>
        </ErrorBoundary>
      </section>

      <section className="section">
        <h2 className="section-title font-display">
          <span className="section-ornament">◆</span> Machine Roster
          <span className="section-line" />
        </h2>
        {agents.length > 0 && (
          <FleetToolbar
            agents={agents}
            filters={filters}
            onChange={setFilters}
            selectedCount={selectedIds.size}
            filteredCount={filteredAgents.length}
            onSelectAllFiltered={() => setSelectedIds(new Set(filteredAgents.map((a) => a.id)))}
            onBulkAction={handleBulkAction}
            bulkBusy={bulkBusy}
          />
        )}
        <div className="agent-grid">          {agents.length === 0 && (
            <NeonCard accent="brass" className="empty-state">
              <div className="empty-icon">⚙</div>
              <h3>No miners on the wire</h3>
              <p>Forge an installer, deploy once per machine — nodes appear here with live neon telemetry.</p>
            </NeonCard>
          )}
          {topAgents.map((agent, i) => (
            <NeonCard
              key={agent.id}
              accent={agent.status === 'online' ? 'cyan' : 'brass'}
              className="agent-card detailed machine-panel"
              style={{ animationDelay: `${i * 0.05}s` } as CSSProperties}
            >
              <div className="agent-card-header">
                <div className="agent-name">
                  <input
                    type="checkbox"
                    className="checkbox"
                    checked={selectedIds.has(agent.id)}
                    onChange={(e) => {
                      setSelectedIds((prev) => {
                        const next = new Set(prev);
                        if (e.target.checked) next.add(agent.id);
                        else next.delete(agent.id);
                        return next;
                      });
                    }}
                  />
                  <span className={`status-dot ${agent.status}`} />
                  <span>{agent.name}</span>
                  {agent.platform && (
                    <span className="agent-tag-chip platform-badge" title={agent.os_version || agent.platform}>
                      {agent.platform}{agent.arch ? `/${agent.arch}` : ''}
                    </span>
                  )}
                </div>
                <span className={`status-badge ${agent.status}`}>{agent.status}</span>
              </div>
              {(agent.tags?.length ?? 0) > 0 && (
                <div style={{ marginBottom: '0.35rem' }}>
                  {agent.tags!.map((t) => (
                    <span key={t} className="agent-tag-chip">{t}</span>
                  ))}
                </div>
              )}              <div className="agent-hash-bar">
                <div
                  className="agent-hash-fill"
                  style={{ width: `${(agent.hashrate_15m / maxAgentHash) * 100}%` }}
                />
              </div>
              <div className="agent-detail-lines">
                <div><span>Hash 15m</span><strong className="neon-glow-cyan">{formatHashrate(agent.hashrate_15m)}</strong></div>
                <div><span>Hash 1m</span><strong>{formatHashrate(agent.hashrate_1m)}</strong></div>
                <div><span>CPU / RAM</span><strong>{agent.cpu_usage_pct.toFixed(0)}% / {agent.memory_usage_pct.toFixed(0)}%</strong></div>
                <div><span>Hardware</span><strong>{agent.cpu_cores} cores · {agent.memory_gb} GB</strong></div>
                <div><span>Shares</span><strong>{agent.shares_good} ok · {agent.shares_bad} bad</strong></div>
                <div><span>Node</span><strong className="mono-sm">{agent.ip || '—'} · {agent.id.slice(0, 8)}</strong></div>
                <div><span>Uptime</span><strong>{formatUptime(agent.uptime_seconds)}</strong></div>
              </div>
              <AgentRemoteActions agent={agent} compact online={agent.status === 'online'} />
            </NeonCard>
          ))}
          {agents.length > 0 && topAgents.length === 0 && (
            <NeonCard accent="brass" className="empty-state">
              <p>No agents match current filters.</p>
            </NeonCard>
          )}
        </div>
      </section>
      {advancedMode && (
        <section className="section">
          <h2 className="section-title font-display">
            <span className="section-ornament">◆</span> Share Log
            <span className="section-line" />
          </h2>
          <NeonCard accent="brass" className="table-card" hud>
            <table className="shares-table steampunk-table">
              <thead>
                <tr>
                  <th>Time</th>
                  <th>Agent</th>
                  <th>Status</th>
                  <th>Hash</th>
                </tr>
              </thead>
              <tbody>
                {shares.length === 0 && (
                  <tr><td colSpan={4} className="empty-table">No shares yet — awaiting proof of work...</td></tr>
                )}
                {shares.map((share) => (
                  <tr key={share.id ?? `${share.agent_id}-${share.hash}-${share.timestamp}`}>
                    <td className="time-cell font-tech">{formatShareTime(share.timestamp)}</td>
                    <td className="mono-sm">{share.agent_id?.substring(0, 8)}…</td>
                    <td>
                      <span className={`status-badge ${share.accepted ? 'online' : 'error'}`}>
                        {share.accepted ? 'Accepted' : 'Rejected'}
                      </span>
                    </td>
                    <td className="hash-cell mono-sm">{share.hash?.substring(0, 24)}…</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </NeonCard>
        </section>
      )}
      {showMatrix && (
        <Suspense fallback={null}>
          <MatrixStreamOverlay active onClose={() => setShowMatrix(false)} />
        </Suspense>
      )}
      <footer style={{ marginTop: '3rem', paddingTop: '1rem', borderTop: '1px solid #333', textAlign: 'center', color: '#ff4444', fontSize: '0.85rem', fontFamily: 'monospace' }}>
        ⚠️ DISCLAIMER: Use only on personal machines on your own network. Anything else is a crime.
      </footer>
    </div>
  );
}

export function formatShareTime(t: string): string {
  return new Date(t).toLocaleTimeString();
}
