// Device screen — engineer/ops console wired to MQTT
function DeviceScreen({ device, log, broker, topicCounts, onPublish, wifiAttempt, onDismissWifiAttempt }) {
  const [ssid, setSsid] = React.useState('');
  const [wifiPass, setWifiPass] = React.useState('');
  const [showPass, setShowPass] = React.useState(false);
  const [status, setStatus] = React.useState(null);

  const lvlColor = { info: 'var(--ink-3)', ok: 'oklch(0.55 0.15 145)', warn: 'oklch(0.6 0.17 60)', err: 'oklch(0.55 0.2 25)' };

  const show = (kind, msg) => { setStatus({ kind, msg }); setTimeout(() => setStatus(null), 3000); };
  const send = (payload, label) => {
    const ok = onPublish(payload);
    show(ok ? 'ok' : 'err', ok ? `${label} sent` : 'Not connected');
  };

  const boardId = device.boardId || '—';
  const espFW = device.espFW ? `v${device.espFW}` : '—';
  const radarFW = device.radarFW ? `v${device.radarFW}` : '—';
  const uptimeStr = device.uptimeH != null ? `${device.uptimeH.toFixed(1)} h` : '—';
  const vitalsIntStr = device.vitalsInterval != null ? `${device.vitalsInterval} s` : '—';
  const brokerLabel = { connected: 'Connected', connecting: 'Connecting', closed: 'Disconnected', error: 'Error', disconnected: 'Disconnected' }[broker] || broker;
  const brokerColor = broker === 'connected' ? 'oklch(0.55 0.15 145)' : broker === 'error' ? 'oklch(0.55 0.2 25)' : 'oklch(0.6 0.1 80)';

  const deviceOnlineSub = device.lastMsgSec == null
    ? 'No messages yet'
    : device.lastMsgSec < 10 ? `Last msg ${device.lastMsgSec}s ago` : `Stale · ${device.lastMsgSec}s ago`;
  const isOnline = device.lastMsgSec != null && device.lastMsgSec < 15;

  const topicRows = [
    ['vitals', '→', 'Device vitals', topicCounts.vitals || 0],
    ['target', '→', 'Radar target', topicCounts.target || 0],
    ['status', '→', 'Heartbeat', topicCounts.status || 0],
    ['lwt', '→', 'Last will', topicCounts.lwt || 0],
    ...Object.keys(topicCounts).filter(t => t.startsWith('sleep/')).map(t => [t, '←', t.endsWith('/summary') ? 'Session summary' : 'Sleep epoch', topicCounts[t]]),
  ];

  return (
    <>
      <div className="page-header">
        <div>
          <div className="page-eyebrow">Device console</div>
          <h1 className="page-title">{boardId}</h1>
          <div className="page-subtitle row items-center gap-12" style={{ display: 'inline-flex', flexWrap: 'wrap' }}>
            <span className="row items-center gap-4">
              <span className="live-dot" style={{
                background: isOnline ? 'oklch(0.65 0.17 145)' : 'oklch(0.6 0.02 260)',
                boxShadow: isOnline ? '0 0 0 3px oklch(0.65 0.17 145 / 0.2)' : 'none',
              }}/>
              {isOnline ? 'Online' : 'Offline'}
            </span>
            <span>·</span>
            <span>{deviceOnlineSub}</span>
            <span>·</span>
            <span className="mono">{(device.msgCount || 0).toLocaleString()} msgs</span>
          </div>
        </div>
        <div className="row gap-8">
          <button className="btn" onClick={() => send('ping', 'Ping')}>Ping</button>
          <button className="btn btn-danger" onClick={() => {
            if (confirm('Reboot the device? It will be unavailable for ~15s.')) send('reboot', 'Reboot');
          }}>Reboot</button>
        </div>
      </div>

      {status && (
        <div className="card-flat" style={{ marginBottom: 16, color: status.kind === 'ok' ? 'oklch(0.4 0.15 145)' : 'oklch(0.5 0.2 25)' }}>
          {status.msg}
        </div>
      )}

      {wifiAttempt && <WifiAttemptBanner attempt={wifiAttempt} onDismiss={onDismissWifiAttempt} />}

      <div className="grid-2" style={{ marginBottom: 16 }}>
        {/* Device info */}
        <div className="card">
          <div className="card-title">Hardware &amp; firmware</div>
          <div className="col gap-8">
            {[
              ['Board ID', boardId],
              ['ESP firmware', espFW],
              ['Radar firmware', radarFW],
              ['MAC', device.mac || '—'],
              ['IP', device.ip || '—'],
              ['Uptime', uptimeStr],
              ['Vitals interval', vitalsIntStr],
            ].map(([k, v]) => (
              <div key={k} className="row justify-between" style={{ padding: '8px 0', borderBottom: '1px solid var(--line)' }}>
                <span className="text-sm text-ink-3">{k}</span>
                <span className="text-sm mono">{v}</span>
              </div>
            ))}
          </div>
        </div>

        {/* Network */}
        <div className="card">
          <div className="card-title">Network</div>
          <div className="col gap-16">
            <div className="row items-center gap-12" style={{ padding: 14, background: 'var(--bg-sunken)', borderRadius: 10 }}>
              <Icon name="wifi" size={20}/>
              <div className="flex-1">
                <div className="text-sm" style={{ fontWeight: 500 }}>{device.ssid || '—'}</div>
                <div className="text-xs text-ink-3 mono">
                  {device.rssi != null ? `RSSI ${device.rssi} dBm · ${device.rssi > -60 ? 'strong' : device.rssi > -75 ? 'ok' : 'weak'}` : 'unknown'}
                </div>
              </div>
              <span className="stage-chip" style={{ background: 'oklch(0.94 0.06 145)', color: 'oklch(0.4 0.12 145)' }}>
                {device.ssid ? 'Connected' : '—'}
              </span>
            </div>
            <div className="col gap-8">
              <label className="text-xs text-ink-3" style={{ textTransform: 'uppercase', letterSpacing: '0.1em', fontWeight: 600 }}>Update WiFi</label>
              <input className="btn" style={{ width: '100%', padding: '10px 14px', textAlign: 'left', fontFamily: 'inherit' }}
                value={ssid} onChange={e => setSsid(e.target.value)} placeholder="SSID" />
              <div style={{ position: 'relative' }}>
                <input type={showPass ? 'text' : 'password'} className="btn"
                  style={{ width: '100%', padding: '10px 42px 10px 14px', textAlign: 'left', fontFamily: 'inherit' }}
                  value={wifiPass} onChange={e => setWifiPass(e.target.value)} placeholder="Password" autoComplete="off" />
                <button type="button" onClick={() => setShowPass(v => !v)} aria-label={showPass ? 'Hide password' : 'Show password'}
                  style={{
                    position: 'absolute', right: 6, top: '50%', transform: 'translateY(-50%)',
                    background: 'transparent', border: 'none', padding: 6, cursor: 'pointer',
                    color: 'var(--ink-3)', display: 'grid', placeItems: 'center',
                  }}>
                  <EyeIcon open={showPass} size={16}/>
                </button>
              </div>
              <div className="row gap-8">
                <button className="btn btn-primary" onClick={() => {
                  if (!ssid) { show('err', 'SSID required'); return; }
                  send({ set_wifi: { ssid, password: wifiPass } }, 'WiFi credentials');
                  setSsid(''); setWifiPass('');
                }}>Push to device</button>
                <button className="btn btn-ghost" onClick={() => { setSsid(''); setWifiPass(''); }}>Clear form</button>
                <button className="btn btn-ghost btn-danger" onClick={() => {
                  if (confirm('Clear stored WiFi on device and reboot?')) send({ clear_wifi: true }, 'WiFi clear');
                }}>Clear stored</button>
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* MQTT / broker */}
      <div className="card" style={{ marginBottom: 16 }}>
        <div className="row justify-between items-center" style={{ marginBottom: 16 }}>
          <div className="card-title" style={{ margin: 0 }}>MQTT bridge</div>
          <span className="stage-chip" style={{ background: 'oklch(0.94 0.06 145)', color: brokerColor }}>
            <span className="stage-dot" style={{ background: brokerColor }}/> {brokerLabel} · HiveMQ
          </span>
        </div>
        <div className="grid-4">
          {topicRows.map(([t, dir, desc, count]) => (
            <div key={t} className="col gap-4" style={{ padding: 12, background: 'var(--bg-sunken)', borderRadius: 8 }}>
              <span className="mono text-xs text-ink-3">{dir} {t}</span>
              <span className="text-sm" style={{ fontWeight: 500 }}>{desc}</span>
              <span className="num text-xs text-ink-3">{count.toLocaleString()} msgs</span>
            </div>
          ))}
        </div>
      </div>

      {/* Activity log */}
      <div className="card">
        <div className="row justify-between items-center" style={{ marginBottom: 16 }}>
          <div className="card-title" style={{ margin: 0 }}>Activity log</div>
          <div className="row gap-8">
            <span className="text-xs text-ink-3">{log.length} entries</span>
          </div>
        </div>
        <div className="mono" style={{
          background: 'var(--bg-sunken)',
          borderRadius: 8,
          padding: 16,
          fontSize: 12,
          lineHeight: 1.8,
          maxHeight: 280,
          overflow: 'auto',
        }}>
          {log.length === 0 && <div className="text-ink-3">No activity yet.</div>}
          {log.map((l, i) => (
            <div key={i} className="row gap-12">
              <span className="text-ink-3">{l.t}</span>
              <span style={{ color: lvlColor[l.lvl], textTransform: 'uppercase', fontSize: 10, width: 40 }}>{l.lvl}</span>
              <span>{l.msg}</span>
            </div>
          ))}
        </div>
      </div>
    </>
  );
}

function EyeIcon({ open, size = 16 }) {
  const p = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.6, strokeLinecap: 'round', strokeLinejoin: 'round' };
  if (open) {
    return <svg {...p}><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></svg>;
  }
  return <svg {...p}><path d="M17.94 17.94A10.94 10.94 0 0 1 12 19c-7 0-11-7-11-7a19.78 19.78 0 0 1 4.06-4.88"/><path d="M9.9 4.24A10.94 10.94 0 0 1 12 4c7 0 11 7 11 7a19.69 19.69 0 0 1-3.08 4.06"/><path d="M9.88 9.88a3 3 0 0 0 4.24 4.24"/><path d="M1 1l22 22"/></svg>;
}

function WifiAttemptBanner({ attempt, onDismiss }) {
  const { status, requestedSsid, actualSsid, requestedAt } = attempt;
  const since = Math.max(0, Math.round((Date.now() - requestedAt) / 1000));

  if (status === 'pending') {
    return (
      <div className="card" style={{
        marginBottom: 16, padding: '14px 18px',
        borderLeft: '3px solid var(--accent)', background: 'var(--accent-soft)',
        display: 'flex', alignItems: 'center', gap: 16,
      }}>
        <div className="flex-1">
          <div style={{ fontWeight: 600, color: 'var(--accent-ink)', fontSize: 14 }}>Verifying WiFi change…</div>
          <div className="text-xs text-ink-3" style={{ marginTop: 2 }}>
            Waiting for device to reboot and reconnect to <span className="mono">{requestedSsid}</span> ({since}s elapsed).
          </div>
        </div>
      </div>
    );
  }

  if (status === 'ok') {
    return (
      <div className="card" style={{
        marginBottom: 16, padding: '14px 18px',
        borderLeft: '3px solid oklch(0.6 0.16 145)', background: 'oklch(0.95 0.05 145)',
        display: 'flex', alignItems: 'center', gap: 16,
      }}>
        <div className="flex-1">
          <div style={{ fontWeight: 600, color: 'oklch(0.35 0.15 145)', fontSize: 14 }}>✓ WiFi change confirmed</div>
          <div className="text-xs" style={{ marginTop: 2, color: 'oklch(0.4 0.1 145)' }}>
            Device is now on <span className="mono">{actualSsid}</span>.
          </div>
        </div>
        <button className="btn btn-sm btn-ghost" onClick={onDismiss}>Dismiss</button>
      </div>
    );
  }

  if (status === 'failed') {
    return (
      <div className="card" style={{
        marginBottom: 16, padding: '14px 18px',
        borderLeft: '3px solid oklch(0.55 0.2 25)', background: 'oklch(0.96 0.04 25)',
        display: 'flex', alignItems: 'flex-start', gap: 16,
      }}>
        <div className="flex-1">
          <div style={{ fontWeight: 600, color: 'oklch(0.4 0.18 25)', fontSize: 14 }}>⚠ WiFi change failed</div>
          <div className="text-sm" style={{ marginTop: 4, color: 'oklch(0.35 0.1 25)', lineHeight: 1.5 }}>
            You requested <span className="mono" style={{ fontWeight: 600 }}>{requestedSsid}</span>, but the device fell back and is now on <span className="mono" style={{ fontWeight: 600 }}>{actualSsid}</span>. Check the SSID and password for typos.
          </div>
        </div>
        <button className="btn btn-sm btn-ghost" onClick={onDismiss}>Dismiss</button>
      </div>
    );
  }

  if (status === 'timeout') {
    return (
      <div className="card" style={{
        marginBottom: 16, padding: '14px 18px',
        borderLeft: '3px solid oklch(0.6 0.17 60)', background: 'oklch(0.96 0.05 60)',
        display: 'flex', alignItems: 'center', gap: 16,
      }}>
        <div className="flex-1">
          <div style={{ fontWeight: 600, color: 'oklch(0.4 0.14 60)', fontSize: 14 }}>WiFi verification timed out</div>
          <div className="text-xs" style={{ marginTop: 2, color: 'oklch(0.4 0.1 60)' }}>
            No status heartbeat received after {since}s. Device may still be rebooting or unreachable. Try Ping once it reappears.
          </div>
        </div>
        <button className="btn btn-sm btn-ghost" onClick={onDismiss}>Dismiss</button>
      </div>
    );
  }

  return null;
}

window.DeviceScreen = DeviceScreen;
