/**
 * FleetPanel.jsx — Multi-robot fleet management dashboard.
 *
 * Sub-views (internal tab nav):
 *   Robots | Map | Missions | Video | Alerts | Detail
 *
 * Uses useFleet() for multi-robot WebSocket multiplexing.
 * Robot detail re-uses single-robot panel components via subscribeRobot adapter.
 *
 * Video streaming:
 *   http://<host>:<videoPort>/stream?topic=<videoTopic>&type=ros_compressed
 *   (web_video_server / mjpeg_server)
 */

import { useState, useRef, useCallback, useEffect } from 'react';
import { useFleet } from '../hooks/useFleet.js';

// Reusable single-robot detail panels (re-used via subscribeRobot adapter)
import { ImuPanel }     from './ImuPanel.jsx';
import { BatteryPanel } from './BatteryPanel.jsx';
import { MotorPanel }   from './MotorPanel.jsx';
import { ControlMode }  from './ControlMode.jsx';
import { SystemHealth } from './SystemHealth.jsx';

// ── Constants ───────────────────────────────────────────────────────────────

const VARIANT_COLORS = {
  balance: 'text-cyan-400  border-cyan-800',
  rover:   'text-green-400 border-green-800',
  tank:    'text-amber-400 border-amber-800',
  social:  'text-purple-400 border-purple-800',
};

const FLEET_VIEWS = [
  { id: 'robots',   label: 'Robots'   },
  { id: 'map',      label: 'Fleet Map'},
  { id: 'missions', label: 'Missions' },
  { id: 'video',    label: 'Video'    },
  { id: 'alerts',   label: 'Alerts'   },
];

// ── Add-Robot modal ──────────────────────────────────────────────────────────

function AddRobotModal({ onAdd, onClose }) {
  const [form, setForm] = useState({
    name: '', variant: 'balance', host: '', port: '9090',
    videoPort: '8080', videoTopic: '/camera/panoramic/compressed',
  });
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!form.host.trim()) return;
    onAdd({
      ...form,
      port: Number(form.port),
      videoPort: Number(form.videoPort),
    });
    onClose();
  };

  return (
    <div className="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50 p-4">
      <div className="bg-gray-950 border border-cyan-800 rounded-lg p-5 w-full max-w-md">
        <div className="flex items-center justify-between mb-4">
          <span className="text-cyan-400 font-bold tracking-widest text-sm">ADD ROBOT</span>
          <button onClick={onClose} className="text-gray-600 hover:text-gray-300">✕</button>
        </div>
        <form onSubmit={handleSubmit} className="space-y-3">
          <div className="grid grid-cols-2 gap-3">
            <label className="col-span-2 space-y-1">
              <span className="text-gray-500 text-xs">Display Name</span>
              <input className="w-full bg-gray-900 border border-gray-700 rounded px-2 py-1.5 text-sm text-gray-200 focus:outline-none focus:border-cyan-700"
                value={form.name} onChange={e => set('name', e.target.value)} placeholder="SaltyBot #2" />
            </label>
            <label className="space-y-1">
              <span className="text-gray-500 text-xs">Variant</span>
              <select className="w-full bg-gray-900 border border-gray-700 rounded px-2 py-1.5 text-sm text-gray-200 focus:outline-none focus:border-cyan-700"
                value={form.variant} onChange={e => set('variant', e.target.value)}>
                <option value="balance">Balance</option>
                <option value="rover">Rover</option>
                <option value="tank">Tank</option>
                <option value="social">Social</option>
              </select>
            </label>
            <label className="space-y-1">
              <span className="text-gray-500 text-xs">Rosbridge Host</span>
              <input className="w-full bg-gray-900 border border-gray-700 rounded px-2 py-1.5 text-sm text-gray-200 focus:outline-none focus:border-cyan-700"
                value={form.host} onChange={e => set('host', e.target.value)} placeholder="192.168.1.101" required />
            </label>
            <label className="space-y-1">
              <span className="text-gray-500 text-xs">Rosbridge Port</span>
              <input type="number" className="w-full bg-gray-900 border border-gray-700 rounded px-2 py-1.5 text-sm text-gray-200 focus:outline-none focus:border-cyan-700"
                value={form.port} onChange={e => set('port', e.target.value)} />
            </label>
            <label className="space-y-1">
              <span className="text-gray-500 text-xs">Video Port</span>
              <input type="number" className="w-full bg-gray-900 border border-gray-700 rounded px-2 py-1.5 text-sm text-gray-200 focus:outline-none focus:border-cyan-700"
                value={form.videoPort} onChange={e => set('videoPort', e.target.value)} />
            </label>
            <label className="space-y-1">
              <span className="text-gray-500 text-xs">Video Topic</span>
              <input className="w-full bg-gray-900 border border-gray-700 rounded px-2 py-1.5 text-sm text-gray-200 focus:outline-none focus:border-cyan-700"
                value={form.videoTopic} onChange={e => set('videoTopic', e.target.value)} />
            </label>
          </div>
          <div className="flex gap-2 justify-end pt-2">
            <button type="button" onClick={onClose}
              className="px-3 py-1.5 rounded border border-gray-700 text-gray-400 hover:text-gray-200 text-sm">Cancel</button>
            <button type="submit"
              className="px-3 py-1.5 rounded bg-cyan-950 border border-cyan-700 text-cyan-300 hover:bg-cyan-900 text-sm font-bold">Add Robot</button>
          </div>
        </form>
      </div>
    </div>
  );
}

// ── Sub-view: Robots List ────────────────────────────────────────────────────

function SocBar({ soc }) {
  const color = soc < 20 ? '#ef4444' : soc < 40 ? '#f59e0b' : '#22c55e';
  return (
    <div className="flex items-center gap-1.5 min-w-[60px]">
      <div className="flex-1 h-1.5 bg-gray-800 rounded overflow-hidden">
        <div className="h-full rounded" style={{ width: `${soc}%`, background: color }} />
      </div>
      <span className="text-xs w-7 text-right" style={{ color }}>{soc}%</span>
    </div>
  );
}

function RobotCard({ robot, connection, data, onSelect, onRemove }) {
  const conn = connection ?? { connected: false, error: null };
  const d = data ?? {};
  const varColor = VARIANT_COLORS[robot.variant] ?? 'text-gray-400 border-gray-700';

  return (
    <div
      className="bg-gray-950 border border-gray-800 rounded-lg p-3 flex flex-col gap-2 cursor-pointer hover:border-cyan-800 transition-colors"
      onClick={() => onSelect(robot.id)}
    >
      {/* Header row */}
      <div className="flex items-center gap-2">
        <div className={`w-2 h-2 rounded-full shrink-0 ${conn.connected ? 'bg-green-400' : conn.error ? 'bg-red-500 animate-pulse' : 'bg-gray-700'}`} />
        <span className="font-bold text-sm text-gray-200 flex-1 truncate">{robot.name || robot.id}</span>
        <span className={`text-xs border rounded px-1.5 py-0.5 font-mono uppercase ${varColor}`}>{robot.variant}</span>
        <button
          className="text-gray-700 hover:text-red-500 ml-1 text-xs"
          title="Remove robot"
          onClick={e => { e.stopPropagation(); onRemove(robot.id); }}
        >✕</button>
      </div>

      {/* Address */}
      <div className="text-xs text-gray-600 font-mono">{robot.host}:{robot.port}</div>

      {/* Telemetry row */}
      {conn.connected ? (
        <div className="grid grid-cols-2 gap-x-3 gap-y-1 text-xs">
          <div className="flex items-center justify-between">
            <span className="text-gray-600">Battery</span>
            <SocBar soc={Math.round(d.battery?.soc ?? 0)} />
          </div>
          <div className="flex items-center justify-between">
            <span className="text-gray-600">State</span>
            <span className={`font-bold ${
              d.state === 'ARMED' ? 'text-green-400' :
              d.state === 'TILT FAULT' ? 'text-red-400 animate-pulse' :
              d.state ? 'text-amber-400' : 'text-gray-600'
            }`}>{d.state ?? '—'}</span>
          </div>
          <div className="flex items-center justify-between col-span-2">
            <span className="text-gray-600">Pipeline</span>
            <span className={`font-bold ${
              d.pipeline === 'speaking' ? 'text-cyan-400' :
              d.pipeline === 'thinking' ? 'text-purple-400' :
              d.pipeline === 'listening' ? 'text-green-400' :
              'text-gray-600'
            }`}>{d.pipeline ?? '—'}</span>
          </div>
          {d.pose && (
            <div className="col-span-2 text-gray-600">
              pos <span className="text-cyan-600">{d.pose.x.toFixed(1)},{d.pose.y.toFixed(1)}</span>
              {' '}hdg <span className="text-cyan-600">{(d.pose.yaw * 180 / Math.PI).toFixed(0)}°</span>
            </div>
          )}
        </div>
      ) : (
        <div className="text-xs text-gray-700">
          {conn.error ? <span className="text-red-700">⚠ {conn.error}</span> : 'Connecting…'}
        </div>
      )}

      {d.alerts?.length > 0 && (
        <div className="flex flex-wrap gap-1">
          {d.alerts.slice(0, 3).map((a, i) => (
            <span key={i} className={`text-xs px-1 rounded border ${
              a.level >= 2 ? 'bg-red-950 border-red-800 text-red-400' : 'bg-amber-950 border-amber-800 text-amber-400'
            }`}>{a.name}</span>
          ))}
        </div>
      )}
    </div>
  );
}

function RobotsView({ robots, connections, robotData, onSelect, onRemove, onAdd, onScan, scanning }) {
  return (
    <div className="space-y-3">
      <div className="flex items-center gap-2 flex-wrap">
        <div className="text-cyan-700 text-xs font-bold tracking-widest">
          FLEET — {robots.length} ROBOT{robots.length !== 1 ? 'S' : ''}
        </div>
        <div className="ml-auto flex gap-2">
          <button
            onClick={onScan}
            disabled={scanning}
            className="px-3 py-1 rounded border border-gray-700 text-gray-400 hover:border-cyan-700 hover:text-cyan-300 text-xs disabled:opacity-50"
          >{scanning ? 'Scanning…' : 'Scan LAN'}</button>
          <button
            onClick={onAdd}
            className="px-3 py-1 rounded bg-cyan-950 border border-cyan-700 text-cyan-300 hover:bg-cyan-900 text-xs font-bold"
          >+ Add Robot</button>
        </div>
      </div>
      {robots.length === 0 ? (
        <div className="text-center text-gray-600 text-sm py-10 border border-dashed border-gray-800 rounded-lg">
          No robots configured. Add one or scan the LAN.
        </div>
      ) : (
        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
          {robots.map(r => (
            <RobotCard
              key={r.id}
              robot={r}
              connection={connections[r.id]}
              data={robotData[r.id]}
              onSelect={onSelect}
              onRemove={onRemove}
            />
          ))}
        </div>
      )}
    </div>
  );
}

// ── Sub-view: Fleet Map ──────────────────────────────────────────────────────

const ROBOT_COLORS = ['#06b6d4','#f97316','#22c55e','#a855f7','#f59e0b','#ec4899','#84cc16','#38bdf8'];

function FleetMapView({ robots, robotData, onSelect }) {
  const canvasRef = useRef(null);
  const [zoom, setZoom] = useState(30); // px per metre
  const [pan, setPan]   = useState({ x: 0, y: 0 });
  const dragging = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    const W = canvas.width, H = canvas.height;

    ctx.clearRect(0, 0, W, H);
    ctx.fillStyle = '#050510';
    ctx.fillRect(0, 0, W, H);

    // Grid
    ctx.strokeStyle = '#0d1b2a';
    ctx.lineWidth = 1;
    const gridSpacing = zoom;
    const offX = (W / 2 + pan.x) % gridSpacing;
    const offY = (H / 2 + pan.y) % gridSpacing;
    for (let x = offX; x < W; x += gridSpacing) {
      ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, H); ctx.stroke();
    }
    for (let y = offY; y < H; y += gridSpacing) {
      ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(W, y); ctx.stroke();
    }

    // Origin cross
    const cx = W / 2 + pan.x;
    const cy = H / 2 + pan.y;
    ctx.strokeStyle = '#1e3a4a';
    ctx.lineWidth = 1;
    ctx.beginPath(); ctx.moveTo(cx - 10, cy); ctx.lineTo(cx + 10, cy); ctx.stroke();
    ctx.beginPath(); ctx.moveTo(cx, cy - 10); ctx.lineTo(cx, cy + 10); ctx.stroke();

    // Draw each robot that has pose data
    robots.forEach((robot, i) => {
      const d = robotData[robot.id];
      if (!d?.pose) return;
      const color = ROBOT_COLORS[i % ROBOT_COLORS.length];

      const rx = cx + d.pose.x * zoom;
      const ry = cy - d.pose.y * zoom;
      const arrowLen = Math.max(14, zoom * 0.5);

      // Heading line
      ctx.strokeStyle = color;
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.moveTo(rx, ry);
      ctx.lineTo(rx + Math.cos(d.pose.yaw) * arrowLen, ry - Math.sin(d.pose.yaw) * arrowLen);
      ctx.stroke();

      // Body circle
      ctx.fillStyle = color;
      ctx.shadowBlur = 10;
      ctx.shadowColor = color;
      ctx.beginPath();
      ctx.arc(rx, ry, 7, 0, Math.PI * 2);
      ctx.fill();
      ctx.shadowBlur = 0;

      // Label
      ctx.fillStyle = color;
      ctx.font = '9px monospace';
      ctx.textAlign = 'center';
      ctx.fillText(robot.name || robot.id, rx, ry - 12);
    });
  }, [robots, robotData, zoom, pan]);

  const onMouseDown = e => { dragging.current = { x: e.clientX - pan.x, y: e.clientY - pan.y }; };
  const onMouseMove = e => {
    if (!dragging.current) return;
    setPan({ x: e.clientX - dragging.current.x, y: e.clientY - dragging.current.y });
  };
  const onMouseUp = () => { dragging.current = null; };

  const botsWithPose = robots.filter(r => robotData[r.id]?.pose);

  return (
    <div className="space-y-3">
      <div className="flex items-center gap-2 flex-wrap">
        <div className="text-cyan-700 text-xs font-bold tracking-widest">FLEET MAP</div>
        <div className="flex items-center gap-1 ml-auto">
          <button onClick={() => setZoom(z => Math.min(z * 1.5, 200))}
            className="px-2 py-1 rounded border border-gray-700 text-gray-300 hover:border-cyan-700 text-sm">+</button>
          <span className="text-gray-500 text-xs w-16 text-center">{zoom.toFixed(0)}px/m</span>
          <button onClick={() => setZoom(z => Math.max(z / 1.5, 5))}
            className="px-2 py-1 rounded border border-gray-700 text-gray-300 hover:border-cyan-700 text-sm">−</button>
          <button onClick={() => { setZoom(30); setPan({ x: 0, y: 0 }); }}
            className="px-2 py-1 rounded border border-gray-700 text-gray-400 hover:text-gray-200 text-xs ml-2">Reset</button>
        </div>
      </div>
      <div className="bg-gray-950 rounded-lg border border-cyan-950 overflow-hidden">
        <canvas
          ref={canvasRef} width={600} height={400}
          className="w-full cursor-grab active:cursor-grabbing block"
          onMouseDown={onMouseDown} onMouseMove={onMouseMove}
          onMouseUp={onMouseUp} onMouseLeave={onMouseUp}
        />
      </div>
      {/* Legend */}
      <div className="flex flex-wrap gap-3 text-xs">
        {robots.map((r, i) => (
          <button key={r.id}
            className="flex items-center gap-1.5 hover:opacity-80"
            onClick={() => onSelect(r.id)}
          >
            <div className="w-2.5 h-2.5 rounded-full" style={{ background: ROBOT_COLORS[i % ROBOT_COLORS.length] }} />
            <span className="text-gray-500">{r.name || r.id}</span>
            {botsWithPose.find(b => b.id === r.id) ? null : (
              <span className="text-gray-700">(no pose)</span>
            )}
          </button>
        ))}
      </div>
    </div>
  );
}

// ── Sub-view: Mission Dispatch ───────────────────────────────────────────────

function MissionsView({ robots, connections, sendGoal, sendPatrol }) {
  const [targetId, setTargetId]  = useState('');
  const [mode, setMode]          = useState('goal'); // 'goal' | 'patrol'
  const [goalX, setGoalX]        = useState('');
  const [goalY, setGoalY]        = useState('');
  const [goalYaw, setGoalYaw]    = useState('0');
  const [waypoints, setWaypoints] = useState('');
  const [sent, setSent]          = useState(null);

  const connected = robots.filter(r => connections[r.id]?.connected);

  const handleSend = () => {
    if (!targetId) return;
    if (mode === 'goal') {
      sendGoal(targetId, parseFloat(goalX), parseFloat(goalY), parseFloat(goalYaw) * Math.PI / 180);
      setSent(`Goal → (${goalX}, ${goalY}) sent to ${targetId}`);
    } else {
      try {
        const pts = waypoints.trim().split('\n').map(line => {
          const [x, y, yaw = 0] = line.split(',').map(Number);
          return { x, y, yaw: yaw * Math.PI / 180 };
        });
        sendPatrol(targetId, pts);
        setSent(`Patrol (${pts.length} wpts) sent to ${targetId}`);
      } catch {
        setSent('Error parsing waypoints');
      }
    }
    setTimeout(() => setSent(null), 4000);
  };

  return (
    <div className="space-y-4 max-w-lg">
      <div className="text-cyan-700 text-xs font-bold tracking-widest">MISSION DISPATCH</div>

      {connected.length === 0 && (
        <div className="text-amber-700 text-xs border border-amber-900 rounded p-3">
          No robots connected. Connect at least one robot to dispatch missions.
        </div>
      )}

      <div className="space-y-3">
        <label className="block space-y-1">
          <span className="text-gray-500 text-xs">Target Robot</span>
          <select
            className="w-full bg-gray-900 border border-gray-700 rounded px-2 py-1.5 text-sm text-gray-200 focus:outline-none focus:border-cyan-700"
            value={targetId} onChange={e => setTargetId(e.target.value)}
          >
            <option value="">— Select robot —</option>
            {connected.map(r => (
              <option key={r.id} value={r.id}>{r.name || r.id}</option>
            ))}
          </select>
        </label>

        <div className="flex gap-2">
          {['goal', 'patrol'].map(m => (
            <button key={m}
              onClick={() => setMode(m)}
              className={`px-3 py-1.5 rounded border text-xs font-bold uppercase tracking-wider ${
                mode === m
                  ? 'bg-cyan-950 border-cyan-700 text-cyan-300'
                  : 'border-gray-700 text-gray-500 hover:text-gray-300'
              }`}
            >{m === 'goal' ? 'Single Goal' : 'Patrol Route'}</button>
          ))}
        </div>

        {mode === 'goal' ? (
          <div className="grid grid-cols-3 gap-2">
            {[['X (m)', goalX, setGoalX], ['Y (m)', goalY, setGoalY], ['Yaw (°)', goalYaw, setGoalYaw]].map(([lbl, val, setter]) => (
              <label key={lbl} className="space-y-1">
                <span className="text-gray-500 text-xs">{lbl}</span>
                <input type="number" step="0.1"
                  className="w-full bg-gray-900 border border-gray-700 rounded px-2 py-1.5 text-sm text-gray-200 focus:outline-none focus:border-cyan-700"
                  value={val} onChange={e => setter(e.target.value)} placeholder="0" />
              </label>
            ))}
          </div>
        ) : (
          <label className="block space-y-1">
            <span className="text-gray-500 text-xs">Waypoints (x,y,yaw° per line)</span>
            <textarea
              rows={5}
              placeholder="0,0,0&#10;2,0,90&#10;2,2,180&#10;0,2,270"
              className="w-full bg-gray-900 border border-gray-700 rounded px-2 py-1.5 text-sm text-gray-200 focus:outline-none focus:border-cyan-700 font-mono"
              value={waypoints} onChange={e => setWaypoints(e.target.value)}
            />
          </label>
        )}

        <button
          onClick={handleSend}
          disabled={!targetId}
          className="w-full py-2 rounded bg-cyan-950 border border-cyan-700 text-cyan-300 hover:bg-cyan-900 font-bold text-sm tracking-wider disabled:opacity-40 disabled:cursor-not-allowed"
        >SEND MISSION</button>

        {sent && (
          <div className="text-green-400 text-xs border border-green-900 rounded p-2">{sent}</div>
        )}
      </div>

      <div className="bg-gray-950 border border-gray-800 rounded p-3 text-xs text-gray-600 space-y-1">
        <div className="text-gray-500 font-bold">Publish targets</div>
        <div>/goal_pose (geometry_msgs/PoseStamped) — single Nav2 goal</div>
        <div>/outdoor/waypoints (geometry_msgs/PoseArray) — GPS follower patrol</div>
      </div>
    </div>
  );
}

// ── Sub-view: Video Grid ─────────────────────────────────────────────────────

function VideoFeed({ robot, connected }) {
  const [error, setError] = useState(false);
  const src = `http://${robot.host}:${robot.videoPort}/stream?topic=${encodeURIComponent(robot.videoTopic)}&type=ros_compressed`;

  return (
    <div className="bg-gray-950 rounded-lg border border-gray-800 overflow-hidden">
      <div className="flex items-center gap-2 px-2 py-1.5 border-b border-gray-800">
        <div className={`w-1.5 h-1.5 rounded-full ${connected ? 'bg-green-400' : 'bg-gray-700'}`} />
        <span className="text-xs text-gray-400 font-mono truncate flex-1">{robot.name || robot.id}</span>
        <span className="text-xs text-gray-700">{robot.videoTopic.split('/').pop()}</span>
      </div>
      {!connected ? (
        <div className="aspect-video flex items-center justify-center text-gray-700 text-xs">
          Robot disconnected
        </div>
      ) : error ? (
        <div className="aspect-video flex items-center justify-center text-red-900 text-xs text-center px-4">
          Stream unavailable<br />
          <span className="text-gray-700">{robot.host}:{robot.videoPort}</span>
        </div>
      ) : (
        <img
          src={src}
          alt={`${robot.name} camera`}
          className="w-full aspect-video object-cover block bg-black"
          onError={() => setError(true)}
        />
      )}
    </div>
  );
}

function VideoView({ robots, connections }) {
  return (
    <div className="space-y-3">
      <div className="text-cyan-700 text-xs font-bold tracking-widest">VIDEO GRID</div>
      {robots.length === 0 ? (
        <div className="text-gray-600 text-xs text-center py-8">No robots configured.</div>
      ) : (
        <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
          {robots.map(r => (
            <VideoFeed key={r.id} robot={r} connected={connections[r.id]?.connected} />
          ))}
        </div>
      )}
      <div className="text-xs text-gray-700">
        Streams via web_video_server on port {robots[0]?.videoPort ?? 8080}.
        Start with: <code className="text-gray-600">ros2 run web_video_server web_video_server</code>
      </div>
    </div>
  );
}

// ── Sub-view: Alert Panel ────────────────────────────────────────────────────

function AlertsView({ robots, robotData, connections }) {
  const allAlerts = robots.flatMap(r => {
    const d = robotData[r.id];
    if (!d?.alerts?.length) return [];
    return d.alerts.map(a => ({ ...a, robotId: r.id, robotName: r.name || r.id }));
  });

  const errors = allAlerts.filter(a => a.level >= 2);
  const warns  = allAlerts.filter(a => a.level === 1);
  const offline = robots.filter(r => !connections[r.id]?.connected);

  return (
    <div className="space-y-4">
      <div className="text-cyan-700 text-xs font-bold tracking-widest">FLEET ALERTS</div>

      {/* Summary */}
      <div className="grid grid-cols-3 gap-3">
        {[
          { label: 'ERRORS',  count: errors.length,  color: errors.length  ? 'text-red-400 bg-red-950 border-red-800'    : 'text-gray-600 bg-gray-900 border-gray-800' },
          { label: 'WARNINGS',count: warns.length,   color: warns.length   ? 'text-amber-400 bg-amber-950 border-amber-800' : 'text-gray-600 bg-gray-900 border-gray-800' },
          { label: 'OFFLINE', count: offline.length, color: offline.length ? 'text-gray-400 bg-gray-900 border-gray-700'  : 'text-gray-600 bg-gray-900 border-gray-800' },
        ].map(({ label, count, color }) => (
          <div key={label} className={`rounded-lg border p-3 text-center ${color}`}>
            <div className="text-2xl font-bold">{count}</div>
            <div className="text-xs tracking-widest mt-0.5">{label}</div>
          </div>
        ))}
      </div>

      {/* Offline robots */}
      {offline.length > 0 && (
        <div className="bg-gray-950 rounded-lg border border-gray-700 p-3">
          <div className="text-gray-500 text-xs font-bold mb-2">OFFLINE ROBOTS</div>
          <div className="space-y-1">
            {offline.map(r => (
              <div key={r.id} className="flex items-center gap-2 text-xs">
                <div className="w-1.5 h-1.5 rounded-full bg-gray-600" />
                <span className="text-gray-400">{r.name || r.id}</span>
                <span className="text-gray-700">{r.host}:{r.port}</span>
                {connections[r.id]?.error && (
                  <span className="text-red-800">{connections[r.id].error}</span>
                )}
              </div>
            ))}
          </div>
        </div>
      )}

      {/* Alert list */}
      {allAlerts.length === 0 ? (
        <div className="text-gray-600 text-xs text-center py-6 border border-dashed border-gray-800 rounded">
          {robots.length === 0 ? 'No robots configured.' : 'No active alerts across fleet.'}
        </div>
      ) : (
        <div className="space-y-2">
          {[...allAlerts]
            .sort((a, b) => b.level - a.level)
            .map((a, i) => (
              <div key={i} className={`flex items-start gap-2 rounded border px-3 py-2 text-xs ${
                a.level >= 2 ? 'bg-red-950 border-red-800' : 'bg-amber-950 border-amber-800'
              }`}>
                <div className={`w-1.5 h-1.5 rounded-full mt-0.5 shrink-0 ${a.level >= 2 ? 'bg-red-400 animate-pulse' : 'bg-amber-400'}`} />
                <div className="flex-1">
                  <span className="font-bold text-gray-300">{a.name}</span>
                  {a.message && <span className="text-gray-500 ml-2">{a.message}</span>}
                </div>
                <span className="text-gray-500 shrink-0">{a.robotName}</span>
              </div>
            ))
          }
        </div>
      )}
    </div>
  );
}

// ── Sub-view: Robot Detail ───────────────────────────────────────────────────

const DETAIL_TABS = [
  { id: 'imu',     label: 'IMU'     },
  { id: 'battery', label: 'Battery' },
  { id: 'motors',  label: 'Motors'  },
  { id: 'control', label: 'Control' },
  { id: 'health',  label: 'Health'  },
];

function RobotDetail({ robot, connection, data, subscribeRobot, onBack }) {
  const [tab, setTab] = useState('imu');

  // Adapter: wrap subscribeRobot(id, ...) to match subscribe(name, type, cb) signature
  const subscribe = useCallback(
    (name, type, cb) => subscribeRobot(robot.id, name, type, cb),
    [subscribeRobot, robot.id]
  );

  const conn = connection ?? { connected: false };

  return (
    <div className="space-y-3">
      {/* Back + header */}
      <div className="flex items-center gap-3">
        <button
          onClick={onBack}
          className="text-gray-500 hover:text-cyan-300 text-xs border border-gray-700 hover:border-cyan-800 rounded px-2 py-1"
        >← Back</button>
        <div className="flex items-center gap-2">
          <div className={`w-2 h-2 rounded-full ${conn.connected ? 'bg-green-400' : 'bg-gray-700'}`} />
          <span className="font-bold text-gray-200">{robot.name || robot.id}</span>
          <span className="text-gray-600 text-sm">{robot.host}:{robot.port}</span>
          <span className={`text-xs border rounded px-1.5 py-0.5 font-mono uppercase ${VARIANT_COLORS[robot.variant] ?? 'text-gray-400 border-gray-700'}`}>
            {robot.variant}
          </span>
        </div>
        {data?.battery?.soc != null && (
          <div className="ml-auto flex items-center gap-1.5">
            <SocBar soc={Math.round(data.battery.soc)} />
            <span className="text-xs text-gray-600">{data.battery.voltage?.toFixed(1)}V</span>
          </div>
        )}
      </div>

      {/* Detail tabs */}
      <div className="flex gap-0.5 border-b border-gray-800">
        {DETAIL_TABS.map(t => (
          <button key={t.id} onClick={() => setTab(t.id)}
            className={`px-3 py-2 text-xs font-bold tracking-wider border-b-2 transition-colors ${
              tab === t.id
                ? 'border-cyan-500 text-cyan-300'
                : 'border-transparent text-gray-600 hover:text-gray-300'
            }`}
          >{t.label}</button>
        ))}
      </div>

      {!conn.connected ? (
        <div className="text-gray-600 text-sm text-center py-10">
          Robot disconnected {conn.error ? `— ${conn.error}` : ''}
        </div>
      ) : (
        <div>
          {tab === 'imu'     && <ImuPanel     subscribe={subscribe} />}
          {tab === 'battery' && <BatteryPanel subscribe={subscribe} />}
          {tab === 'motors'  && <MotorPanel   subscribe={subscribe} />}
          {tab === 'control' && <ControlMode  subscribe={subscribe} />}
          {tab === 'health'  && <SystemHealth subscribe={subscribe} />}
        </div>
      )}
    </div>
  );
}

// ── Root FleetPanel ──────────────────────────────────────────────────────────

export function FleetPanel() {
  const {
    robots, addRobot, removeRobot,
    connections, robotData,
    subscribeRobot, sendGoal, sendPatrol,
    scanning, scanSubnet,
  } = useFleet();

  const [view, setView]         = useState('robots');
  const [selectedId, setSelectedId] = useState(null);
  const [showAdd, setShowAdd]   = useState(false);

  const handleSelect = useCallback((id) => {
    setSelectedId(id);
  }, []);

  const handleBack = useCallback(() => {
    setSelectedId(null);
  }, []);

  const handleScanLan = useCallback(async () => {
    const baseIp = robots[0]?.host ?? '192.168.1.100';
    const found = await scanSubnet(baseIp, [9090, 9092]);
    found.forEach(({ host, port }, i) => {
      const existingHosts = robots.map(r => r.host);
      if (!existingHosts.includes(host)) {
        addRobot({
          id: `discovered-${Date.now()}-${i}`,
          name: `Discovered ${host}`,
          variant: 'balance',
          host,
          port,
        });
      }
    });
  }, [robots, scanSubnet, addRobot]);

  // If a robot is selected → show RobotDetail overlay
  if (selectedId) {
    const robot = robots.find(r => r.id === selectedId);
    if (robot) {
      return (
        <RobotDetail
          robot={robot}
          connection={connections[robot.id]}
          data={robotData[robot.id]}
          subscribeRobot={subscribeRobot}
          onBack={handleBack}
        />
      );
    }
    setSelectedId(null);
  }

  return (
    <div className="space-y-4">
      {/* Fleet sub-nav */}
      <div className="flex gap-0.5 border-b border-gray-800">
        {FLEET_VIEWS.map(v => (
          <button key={v.id} onClick={() => setView(v.id)}
            className={`px-3 py-2 text-xs font-bold tracking-wider border-b-2 transition-colors ${
              view === v.id
                ? 'border-cyan-500 text-cyan-300'
                : 'border-transparent text-gray-600 hover:text-gray-300'
            }`}
          >{v.label.toUpperCase()}</button>
        ))}
      </div>

      {/* Content */}
      {view === 'robots' && (
        <RobotsView
          robots={robots}
          connections={connections}
          robotData={robotData}
          onSelect={handleSelect}
          onRemove={removeRobot}
          onAdd={() => setShowAdd(true)}
          onScan={handleScanLan}
          scanning={scanning}
        />
      )}
      {view === 'map' && (
        <FleetMapView robots={robots} robotData={robotData} onSelect={handleSelect} />
      )}
      {view === 'missions' && (
        <MissionsView
          robots={robots}
          connections={connections}
          sendGoal={sendGoal}
          sendPatrol={sendPatrol}
        />
      )}
      {view === 'video' && (
        <VideoView robots={robots} connections={connections} />
      )}
      {view === 'alerts' && (
        <AlertsView robots={robots} robotData={robotData} connections={connections} />
      )}

      {showAdd && (
        <AddRobotModal onAdd={addRobot} onClose={() => setShowAdd(false)} />
      )}
    </div>
  );
}
