// Devices screen + Add Device wizard + DeviceInfo sub-screen
const Devices = ({ tanks, setTanks, navigate, refreshTanks, basePath = '/device', onBack }) => {
  const [wizardOpen, setWizardOpen] = useState(false);

  return (
    <div style={{padding: onBack ? '0 0 100px' : '8px 16px 100px'}}>
      {/* Sub-screen header (when opened from Settings) */}
      {onBack ? (
        <div style={{
          position: 'sticky', top: 56, zIndex: 10,
          background: 'rgba(10,14,39,0.86)', backdropFilter: 'blur(14px)',
          borderBottom: '1px solid var(--border)',
          padding: '12px 14px', display: 'flex', alignItems: 'center', gap: 10,
          marginBottom: 12,
        }}>
          <button onClick={onBack} style={{
            background: 'rgba(255,255,255,0.06)', border: '1px solid var(--border)',
            borderRadius: 10, width: 34, height: 34,
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: '#fff', cursor: 'pointer',
          }}>
            <Ic name="chevronLeft" size={18}/>
          </button>
          <div style={{flex: 1}}>
            <div style={{fontSize: 15, fontWeight: 600}}>Devices</div>
            <div style={{fontSize: 11, color: 'var(--text-3)'}}>{tanks.length} registered · {tanks.filter(t=>t.online).length} online</div>
          </div>
          <Btn icon="plus" size="sm" onClick={()=> setWizardOpen(true)}>Add</Btn>
        </div>
      ) : (
        <div style={{padding: '6px 16px 14px', display: 'flex', justifyContent: 'space-between', alignItems: 'center'}}>
          <div>
            <div style={{fontSize: 22, fontWeight: 600}}>Devices</div>
            <div style={{fontSize: 13, color: 'var(--text-2)', marginTop: 2}}>{tanks.length} registered · {tanks.filter(t=>t.online).length} online</div>
          </div>
          <Btn icon="plus" onClick={()=> setWizardOpen(true)}>Add</Btn>
        </div>
      )}

      <div style={{display: 'flex', flexDirection: 'column', gap: 10, padding: onBack ? '0 16px' : '0'}}>
        {tanks.map(t => <DeviceRow key={t.id} tank={t} onClick={() => navigate && navigate(`${basePath}/${t.id}`)}/>)}
        {tanks.length === 0 && (
          <Card style={{padding: 32, textAlign: 'center'}}>
            <Ic name="grid" size={36} color="var(--text-3)"/>
            <div style={{marginTop: 10, fontSize: 14, fontWeight: 500}}>No devices yet</div>
            <div style={{marginTop: 4, fontSize: 12, color: 'var(--text-3)'}}>Tap "Add" to register your first Velonics Hub device.</div>
            <div style={{marginTop: 14}}><Btn icon="plus" onClick={()=> setWizardOpen(true)}>Add Device</Btn></div>
          </Card>
        )}
      </div>

      {wizardOpen && (
        <AddDeviceWizard
          onClose={()=> setWizardOpen(false)}
          onFinish={(newTank)=>{
            setTanks(prev => {
              if (prev.some(t => t.id === newTank.id)) return prev;
              return [...prev, { ...newTank, mqttReceived: false, modePending: false }];
            });
            // Refresh from backend so the tank list is authoritative
            if (refreshTanks) refreshTanks().catch(() => {});
          }}
        />
      )}
    </div>
  );
};

const DeviceRow = ({ tank, onClick }) => (
  <Card style={{padding: 14, cursor: 'pointer'}} accent={tank.online ? 'cyan' : 'red'} onClick={onClick}>
    <div style={{display: 'flex', alignItems: 'center', gap: 12}}>
      <div style={{width: 44, height: 44, borderRadius: 12, background: 'rgba(0,212,255,0.10)', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
        <Ic name={tank.type === 'Underground' ? 'site' : tank.type === 'Irrigation' ? 'sprout' : tank.type === 'Agri Pump' ? 'zap' : 'home'} size={20} color="var(--cyan)"/>
      </div>
      <div style={{flex: 1, minWidth: 0}}>
        <div style={{fontWeight: 600, fontSize: 14, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis'}}>{tank.name}</div>
        <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 2, display: 'flex', alignItems: 'center', gap: 8}}>
          <span>{tank.type}</span>
          <span>·</span>
          <span>FW {tank.fw}</span>
          <span>·</span>
          <span>{tank.lastSeen}</span>
        </div>
      </div>
      <div style={{display: 'flex', alignItems: 'center', gap: 8}}>
        <SignalBars strength={tank.signal}/>
        <Ic name="chevronRight" size={16} color="var(--text-3)"/>
      </div>
    </div>
  </Card>
);

/* ============================================================
   DEVICE INFO SUB-SCREEN
   ============================================================ */

const DeviceInfo = ({ tank, onBack, onRemove, onReset, onUpdate, deviceAppearance, onAppearanceChange }) => {
  const toast = useToast();
  const [editingName,       setEditingName]       = useState(false);
  const [tempName,          setTempName]          = useState(tank.name);
  const [confirmRemove,     setConfirmRemove]     = useState(false);
  const [confirmReset,      setConfirmReset]      = useState(false);
  const [confirmChangeWifi, setConfirmChangeWifi] = useState(false);
  const [updating,          setUpdating]          = useState(false);
  const currentAppearance = (() => {
    const val = deviceAppearance?.[String(tank.id)];
    if (!val) return null;
    return typeof val === 'string' ? { color: val, style: 'border' } : val;
  })();
  const [allGroups,         setAllGroups]         = useState(() => {
    try { return JSON.parse(localStorage.getItem('velonics_groups') || '[]'); } catch { return []; }
  });
  const [linkedGroups,      setLinkedGroups]      = useState(() => {
    try {
      const dg = JSON.parse(localStorage.getItem('velonics_device_groups') || '{}');
      return dg[String(tank.id)] || [];
    } catch { return []; }
  });

  const toggleGroup = (groupId) => {
    setLinkedGroups(prev => {
      const next = prev.includes(groupId) ? prev.filter(id => id !== groupId) : [...prev, groupId];
      try {
        const dg = JSON.parse(localStorage.getItem('velonics_device_groups') || '{}');
        dg[String(tank.id)] = next;
        localStorage.setItem('velonics_device_groups', JSON.stringify(dg));
        if (window.API) {
          API.patch('/api/user/preferences', { deviceGroups: dg }).catch(() => {});
        }
      } catch {}
      return next;
    });
  };

  const mac       = `AC:${String(tank.id).padStart(2,'0').toUpperCase()}:${(tank.fw || '0.0.0').replace(/\./g,'').padStart(4,'0')}:42`;
  const fwLatest  = '2.3.1';
  const fwOutdated = tank.fw && tank.fw !== fwLatest;

  const doUpdate = () => {
    setUpdating(true);
    toast && toast('Firmware update started', { kind: 'info', icon: 'download' });
    setTimeout(() => {
      setUpdating(false);
      toast && toast(`Updated to v${fwLatest}`, { kind: 'success' });
    }, 2200);
  };

  return (
    <div>
      {/* Header */}
      <div style={{
        position: 'sticky', top: 56, zIndex: 10,
        background: 'rgba(10,14,39,0.86)', backdropFilter: 'blur(14px)',
        borderBottom: '1px solid var(--border)',
        padding: '12px 14px', display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <button onClick={onBack} style={{background:'rgba(255,255,255,0.06)', border:'1px solid var(--border)', borderRadius:10, width:34, height:34, display:'flex', alignItems:'center', justifyContent:'center', color:'#fff', cursor:'pointer'}}>
          <Ic name="chevronLeft" size={18}/>
        </button>
        <div style={{flex:1, minWidth:0}}>
          {editingName ? (
            <input value={tempName} onChange={e => setTempName(e.target.value)}
              onBlur={() => {
                if (tempName.trim() && tempName !== tank.name) {
                  onUpdate?.(tank.id, { name: tempName.trim() });
                  if (window.API) API.patch(`/api/tanks/${tank.id}`, { name: tempName.trim() }).catch(() => {});
                }
                setEditingName(false);
              }}
              onKeyDown={e => { if (e.key === 'Enter') e.target.blur(); if (e.key === 'Escape') { setTempName(tank.name); setEditingName(false); } }}
              autoFocus
              style={{ background:'transparent', border:'1px solid var(--cyan)', borderRadius:8, padding:'4px 8px', color:'#fff', fontSize:15, fontWeight:600, width:'100%', fontFamily:'inherit' }}/>
          ) : (
            <div style={{fontSize: 15, fontWeight: 600, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis'}}>{tank.name}</div>
          )}
          <div style={{fontSize: 11, color: 'var(--text-3)'}}>Device info &amp; maintenance</div>
        </div>
        <button onClick={() => { setTempName(tank.name); setEditingName(true); }} style={{ background:'rgba(255,255,255,0.06)', border:'1px solid var(--border)', borderRadius:10, width:34, height:34, display:'flex', alignItems:'center', justifyContent:'center', color:'var(--text-2)', cursor:'pointer', flexShrink:0 }}>
          <Ic name="edit" size={15}/>
        </button>
        <Badge color={tank.online ? 'green' : 'gray'} size="sm">
          <StatusDot kind={tank.online ? 'green' : 'gray'} size={6} pulse={tank.online}/>
          {tank.online ? 'Online' : 'Offline'}
        </Badge>
      </div>

      <div style={{padding: '14px 16px 100px'}}>
        {/* Hero card */}
        <Card style={{padding: 18, marginBottom: 14, display: 'flex', alignItems: 'center', gap: 14}}>
          <div style={{
            width: 60, height: 60, borderRadius: 16,
            background: 'linear-gradient(135deg, rgba(0,212,255,0.18), rgba(0,184,148,0.10))',
            border: '1px solid rgba(0,212,255,0.3)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}>
            <Ic name="grid" size={28} color="var(--cyan)"/>
          </div>
          <div style={{flex:1, minWidth:0}}>
            <div style={{fontSize: 16, fontWeight: 600}}>Velonics Hub</div>
            <div style={{fontSize: 12, color: 'var(--text-2)', marginTop: 2}}>{tank.type} · {tank.capacity}L</div>
            <div style={{fontSize: 11, color: 'var(--text-3)', fontFamily:'JetBrains Mono, monospace', marginTop: 4}}>{mac}</div>
          </div>
        </Card>

        {/* Appearance */}
        <SectionTitle>Appearance</SectionTitle>
        <Card style={{ padding: 16, marginBottom: 14 }}>
          {/* Style selector */}
          <div style={{ fontSize: 10, fontWeight: 600, letterSpacing: 1, color: 'var(--text-3)', marginBottom: 10 }}>STYLE</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8, marginBottom: 16 }}>
            {(['border', 'bold', 'tinted', 'glow']).map(styleKey => {
              const sel = (currentAppearance?.style || 'border') === styleKey && !!currentAppearance;
              const colorHex = (window.DEVICE_COLORS || []).find(c => c.key === currentAppearance?.color)?.hex || null;
              const label = { border: 'Border', bold: 'Bold', tinted: 'Tinted', glow: 'Glow' }[styleKey];
              return (
                <button key={styleKey} onClick={() => {
                  const colorKey = currentAppearance?.color || 'cyan';
                  const next = { ...deviceAppearance, [String(tank.id)]: { color: colorKey, style: styleKey } };
                  onAppearanceChange?.(next);
                }} style={{
                  background: sel ? 'rgba(255,255,255,0.07)' : 'rgba(255,255,255,0.03)',
                  border: `1.5px solid ${sel ? (colorHex || 'var(--cyan)') : 'var(--border)'}`,
                  borderRadius: 12, padding: '8px 4px 6px', cursor: 'pointer',
                  display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 5,
                  transition: 'all 150ms ease',
                }}>
                  {/* Mini preview */}
                  <div style={{
                    width: '100%', height: 34, borderRadius: 7, position: 'relative', overflow: 'hidden',
                    background: styleKey === 'tinted' ? `rgba(${colorHex ? colorHex.slice(1).match(/../g).map(h=>parseInt(h,16)).join(',') : '0,212,255'},0.12)` :
                               styleKey === 'glow'   ? `rgba(${colorHex ? colorHex.slice(1).match(/../g).map(h=>parseInt(h,16)).join(',') : '0,212,255'},0.16)` :
                               'rgba(255,255,255,0.05)',
                    border: styleKey === 'tinted' || styleKey === 'glow' ?
                      `1px solid rgba(${colorHex ? colorHex.slice(1).match(/../g).map(h=>parseInt(h,16)).join(',') : '0,212,255'},0.30)` : '1px solid transparent',
                  }}>
                    <div style={{
                      position: 'absolute', left: 0, top: 0, bottom: 0,
                      width: styleKey === 'bold' ? 4 : 2.5,
                      background: `linear-gradient(180deg, ${colorHex || '#00d4ff'}, transparent)`,
                    }}/>
                    <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', paddingLeft: (styleKey === 'bold' ? 4 : 2.5) + 6, gap: 5 }}>
                      <div style={{ width: 6, height: 6, borderRadius: '50%', background: colorHex || '#00d4ff', opacity: 0.9 }}/>
                      <div style={{ height: 3, width: 24, borderRadius: 99, background: 'rgba(255,255,255,0.18)' }}/>
                    </div>
                  </div>
                  <span style={{ fontSize: 10, color: sel ? 'var(--text)' : 'var(--text-3)', fontWeight: sel ? 600 : 400 }}>{label}</span>
                </button>
              );
            })}
          </div>

          {/* Colour picker */}
          <div style={{ fontSize: 10, fontWeight: 600, letterSpacing: 1, color: 'var(--text-3)', marginBottom: 10 }}>COLOUR</div>
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center' }}>
            {(window.DEVICE_COLORS || []).map(c => {
              const selected = currentAppearance?.color === c.key;
              return (
                <button key={c.key} title={c.label} onClick={() => {
                  const styleKey = currentAppearance?.style || 'border';
                  const next = { ...deviceAppearance, [String(tank.id)]: { color: c.key, style: styleKey } };
                  onAppearanceChange?.(next);
                }} style={{
                  width: 36, height: 36, borderRadius: 10, background: c.hex,
                  border: selected ? '3px solid #fff' : '3px solid transparent',
                  boxShadow: selected ? `0 0 14px ${c.hex}` : 'none',
                  cursor: 'pointer', transition: 'all 150ms ease', flexShrink: 0,
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                }}>
                  {selected && <Ic name="check" size={15} color="#0a0e27" strokeWidth={2.5}/>}
                </button>
              );
            })}
          </div>
          <div style={{ marginTop: 10, fontSize: 11, color: 'var(--text-3)' }}>
            {currentAppearance
              ? `${(window.DEVICE_COLORS || []).find(c => c.key === currentAppearance.color)?.label || ''} · ${currentAppearance.style} — long-press the tile to change quickly`
              : 'No appearance set — long-press the tile on the dashboard to pick one quickly'}
          </div>
          {currentAppearance && (
            <button onClick={() => {
              const next = Object.fromEntries(Object.entries(deviceAppearance || {}).filter(([k]) => k !== String(tank.id)));
              onAppearanceChange?.(next);
            }} style={{
              marginTop: 10, background: 'transparent', border: 'none',
              color: 'var(--text-3)', fontSize: 12, cursor: 'pointer', padding: 0,
            }}>
              Remove custom appearance
            </button>
          )}
        </Card>

        {/* Connectivity */}
        <SectionTitle>Connectivity</SectionTitle>
        <Card style={{padding: 14, marginBottom: 14}}>
          <KVRow label="Status" right={<Badge color={tank.online ? 'green' : 'gray'} size="sm">{tank.online ? 'Connected' : 'Disconnected'}</Badge>}/>
          <KVRow label="Device ID" value={tank.deviceId || '—'} mono/>
          <KVRow label="Network (SSID)" value={tank.ssid || '—'} mono/>
          <KVRow label="IP Address" value={tank.ip || '—'} mono/>
          <KVRow label="Signal strength" right={<div style={{display:'flex',alignItems:'center',gap:6}}><SignalBars strength={tank.signal}/><span className="num" style={{fontSize:12}}>{tank.signal*25}%</span></div>}/>
          <KVRow label="Last seen" value={tank.lastSeen || '—'}/>
          <KVRow label="Cloud sync" right={<Badge color={tank.online ? 'green' : 'gray'} size="sm"><StatusDot kind={tank.online ? 'green' : 'gray'} size={6} pulse={tank.online}/> {tank.online ? 'Active' : 'Offline'}</Badge>} last/>
        </Card>

        {/* Link Groups */}
        <SectionTitle>Link Groups</SectionTitle>
        <Card style={{padding: allGroups.length > 0 ? 4 : 14, marginBottom: 14}}>
          {allGroups.length === 0 ? (
            <div style={{fontSize: 13, color: 'var(--text-3)'}}>No groups created yet. Go to Settings → Manage Groups to create groups.</div>
          ) : allGroups.map((g, i) => (
            <div key={g.id} style={{
              display: 'flex', alignItems: 'center', gap: 12,
              padding: '10px 12px',
              borderBottom: i < allGroups.length - 1 ? '1px solid var(--border)' : 'none',
            }}>
              <div style={{width: 28, height: 28, borderRadius: 8, background: linkedGroups.includes(g.id) ? 'rgba(0,212,255,0.15)' : 'rgba(255,255,255,0.04)', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
                <Ic name="tag" size={13} color={linkedGroups.includes(g.id) ? 'var(--cyan)' : 'var(--text-3)'}/>
              </div>
              <div style={{flex: 1, fontSize: 14, fontWeight: 500}}>{g.name}</div>
              <Toggle on={linkedGroups.includes(g.id)} onChange={() => toggleGroup(g.id)} size="sm"/>
            </div>
          ))}
        </Card>

        {/* Sharing */}
        <SectionTitle>Sharing</SectionTitle>
        <_SharingSection tank={tank}/>

        {/* Firmware */}
        <SectionTitle>Firmware</SectionTitle>
        <Card style={{padding: 14, marginBottom: 14}}>
          <KVRow label="Current version" right={<span className="num" style={{fontFamily:'JetBrains Mono, monospace', fontSize:13}}>v{tank.fw || '—'}</span>}/>
          <KVRow label="Latest version" right={
            <span style={{display:'inline-flex', alignItems:'center', gap:6}}>
              <span className="num" style={{fontFamily:'JetBrains Mono, monospace', fontSize:13}}>v{fwLatest}</span>
              {fwOutdated && <Badge color="amber" size="sm">Update</Badge>}
            </span>
          } last/>
          {fwOutdated && (
            <div style={{marginTop: 12, paddingTop: 12, borderTop: '1px solid var(--border)'}}>
              <Btn full icon={updating ? undefined : 'download'} onClick={doUpdate} disabled={updating || !tank.online}>
                {updating ? 'Installing…' : 'Install update'}
              </Btn>
            </div>
          )}
        </Card>

        {/* Hardware */}
        <SectionTitle>Hardware</SectionTitle>
        <Card style={{padding: 14, marginBottom: 14}}>
          <KVRow label="Model" value="Velonics Hub v2"/>
          <KVRow label="Serial" value={`SN-${String(tank.id).padStart(4,'0')}`} mono/>
          <KVRow label="MAC address" value={mac} mono/>
          <KVRow label="Location" value={tank.location || '—'} last/>
        </Card>

        {/* Maintenance */}
        <SectionTitle>Maintenance</SectionTitle>
        <Card style={{padding: 4, marginBottom: 14}}>
          <ActionRow icon="refresh" label="Reboot device" hint="Restarts firmware · ~30s offline"
            onClick={() => {
              if (window.MQ && tank.deviceId) MQ.publishCmd(tank.deviceId, 'reboot', true);
              toast && toast('Reboot command sent', { kind: 'info', icon: 'refresh' });
            }}/>
          <ActionRow icon="wifi" label="Change WiFi network" hint="Re-enter provisioning mode"
            onClick={() => setConfirmChangeWifi(true)}/>
          <ActionRow icon="tool" label="Calibrate sensors" hint="Run guided calibration"
            onClick={() => toast && toast('Sensor calibration coming soon', { kind: 'info' })}/>
        </Card>

        {/* Danger zone */}
        <SectionTitle>Danger Zone</SectionTitle>
        <Card style={{padding: 4, border: '1px solid rgba(255,82,82,0.25)'}}>
          <ActionRow icon="alert" label="Factory reset" hint="Wipes all settings · keeps device" onClick={() => setConfirmReset(true)} danger/>
          <ActionRow icon="trash" label="Remove device" hint="Unlinks from your account" onClick={() => setConfirmRemove(true)} danger/>
        </Card>
      </div>

      <Confirm open={confirmRemove}
        onCancel={() => setConfirmRemove(false)}
        onConfirm={() => { setConfirmRemove(false); onRemove && onRemove(); toast && toast(`${tank.name} removed`, { kind: 'success' }); }}
        title="Remove this device?"
        body={`"${tank.name}" will be unlinked from your account. Historical data is retained for 30 days.`}
        confirmLabel="Remove" danger/>

      <Confirm open={confirmReset}
        onCancel={() => setConfirmReset(false)}
        onConfirm={() => {
          setConfirmReset(false);
          if (window.MQ && tank.deviceId) MQ.publishCmd(tank.deviceId, 'factory_reset', true);
          onReset && onReset();
          toast && toast('Factory reset command sent', { kind: 'info', icon: 'alert' });
        }}
        title="Factory reset device?"
        body="All settings and calibration data will be wiped. The device will restart and enter provisioning mode."
        confirmLabel="Factory reset" danger/>

      <Confirm open={confirmChangeWifi}
        onCancel={() => setConfirmChangeWifi(false)}
        onConfirm={() => {
          setConfirmChangeWifi(false);
          if (window.MQ && tank.deviceId) MQ.publishCmd(tank.deviceId, 'factory_reset', true);
          toast && toast('Device will restart into provisioning mode', { kind: 'info', icon: 'wifi' });
        }}
        title="Change WiFi network?"
        body="The device will restart and enter provisioning mode (blinking LED). You will need to reconfigure it via the setup page at 192.168.4.1."
        confirmLabel="Re-provision"/>
    </div>
  );
};

// ── Device Sharing Section ──────────────────────────────────────────────────
const _SharingSection = ({ tank }) => {
  const isOwner = !tank.myRole || tank.myRole === 'owner';
  const [shares,    setShares]    = useState([]);
  const [showSheet, setShowSheet] = useState(false);
  const [email,     setEmail]     = useState('');
  const [role,      setRole]      = useState('viewer');
  const [sharing,   setSharing]   = useState(false);
  const [shareErr,  setShareErr]  = useState('');

  useEffect(() => {
    if (!isOwner || !window.API) return;
    API.get(`/api/tanks/${tank.id}/shares`).then(setShares).catch(() => {});
  }, [tank.id, isOwner]);

  const doShare = async () => {
    if (!email.trim()) return;
    setSharing(true); setShareErr('');
    try {
      const r = await API.post(`/api/tanks/${tank.id}/shares`, { email: email.trim(), role });
      const newShare = { id: r.shareId, email: email.trim(), name: null, role, pending: r.pending };
      setShares(prev => [...prev, newShare]);
      setShowSheet(false); setEmail(''); setRole('viewer');
      window.__toast?.(r.pending
        ? `Invite sent — ${email.trim()} will get access when they register`
        : 'Device shared successfully',
        { kind: r.pending ? 'info' : 'success' });
    } catch (e) {
      const msg = e.message || '';
      setShareErr(msg.includes('409') ? 'Already shared with this user'
                : msg.includes('yourself') ? 'Cannot share with yourself'
                : 'Something went wrong — please try again');
    }
    setSharing(false);
  };

  const doRevoke = async (shareId) => {
    try {
      await API.del(`/api/tanks/${tank.id}/shares/${shareId}`);
      setShares(prev => prev.filter(s => s.id !== shareId));
      window.__toast?.('Access revoked', { kind: 'info' });
    } catch { window.__toast?.('Failed to revoke — please try again', { kind: 'error' }); }
  };

  const doRoleChange = async (shareId, newRole) => {
    try {
      await API.put(`/api/tanks/${tank.id}/shares/${shareId}`, { role: newRole });
      setShares(prev => prev.map(s => s.id === shareId ? { ...s, role: newRole } : s));
    } catch { window.__toast?.('Failed to update role', { kind: 'error' }); }
  };

  const ROLE_DESC = {
    viewer:   'View live data and history only',
    operator: 'Also control motor, valves, flush',
    admin:    'Also change setpoints and rename',
  };

  return (
    <div style={{ marginBottom: 14 }}>
      <div style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        padding: '14px 16px 8px',
      }}>
        <span style={{ fontWeight: 700, fontSize: 13, color: 'var(--text-2)', letterSpacing: 0.5 }}>SHARING</span>
        {isOwner && (
          <button onClick={() => setShowSheet(true)} style={{
            fontSize: 12, fontWeight: 600, color: 'var(--cyan)', background: 'none',
            border: 'none', cursor: 'pointer', padding: '4px 8px',
          }}>+ Share</button>
        )}
      </div>

      <div style={{ background: 'var(--bg-2, #1a1f3a)', border: '1px solid var(--border)', borderRadius: 16, overflow: 'hidden' }}>
        {!isOwner && (
          <div style={{ padding: '12px 16px', fontSize: 13, color: 'var(--text-3)' }}>
            Shared with you by <strong style={{ color: 'var(--text)' }}>{tank.sharedBy?.name || tank.sharedBy?.email || 'owner'}</strong>
            {' '}· Role: <strong style={{ color: 'var(--cyan)', textTransform: 'capitalize' }}>{tank.myRole}</strong>
          </div>
        )}

        {isOwner && shares.length === 0 && (
          <div style={{ padding: '12px 16px', fontSize: 13, color: 'var(--text-3)' }}>Not shared with anyone yet.</div>
        )}

        {isOwner && shares.map((s, i) => (
          <div key={s.id} style={{
            display: 'flex', alignItems: 'center', gap: 12,
            padding: '10px 16px',
            borderTop: i > 0 ? '1px solid rgba(255,255,255,0.05)' : 'none',
          }}>
            <div style={{
              width: 34, height: 34, borderRadius: '50%', flexShrink: 0,
              background: 'rgba(0,188,212,0.15)',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              fontWeight: 700, fontSize: 14, color: 'var(--cyan)',
            }}>
              {(s.name || s.email || '?')[0].toUpperCase()}
            </div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontWeight: 600, fontSize: 13, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                {s.name || s.email}
              </div>
              {s.name && <div style={{ fontSize: 11, color: 'var(--text-3)' }}>{s.email}</div>}
              {s.pending && <div style={{ fontSize: 11, color: 'var(--amber)' }}>Invite pending</div>}
            </div>
            <select value={s.role} onChange={e => doRoleChange(s.id, e.target.value)}
              style={{
                background: 'rgba(255,255,255,0.06)', border: '1px solid var(--border)',
                borderRadius: 8, color: 'var(--text)', fontSize: 12, padding: '4px 8px', cursor: 'pointer',
              }}>
              <option value="viewer">Viewer</option>
              <option value="operator">Operator</option>
              <option value="admin">Admin</option>
            </select>
            <button onClick={() => doRevoke(s.id)} style={{
              background: 'rgba(255,60,60,0.08)', border: '1px solid rgba(255,60,60,0.2)',
              borderRadius: 8, color: 'var(--red)', fontSize: 12, fontWeight: 600,
              padding: '5px 10px', cursor: 'pointer',
            }}>Revoke</button>
          </div>
        ))}
      </div>

      {/* Share bottom sheet */}
      {showSheet && ReactDOM.createPortal(
        <div
          style={{ position: 'fixed', inset: 0, zIndex: 1000, display: 'flex', flexDirection: 'column', justifyContent: 'flex-end', background: 'rgba(0,0,0,0.6)' }}
          onClick={e => { if (e.target === e.currentTarget) setShowSheet(false); }}>
          <div style={{ background: 'var(--bg-2, #1a1f3a)', borderRadius: '20px 20px 0 0', padding: '20px 16px 32px', borderTop: '1px solid var(--border)' }}>
            <div style={{ fontWeight: 700, fontSize: 17, marginBottom: 16 }}>Share Device</div>

            <label style={{ fontSize: 13, color: 'var(--text-2)', display: 'block', marginBottom: 6 }}>Email address</label>
            <input
              type="email" value={email}
              onChange={e => { setEmail(e.target.value); setShareErr(''); }}
              placeholder="user@example.com"
              style={{
                width: '100%', boxSizing: 'border-box', padding: '11px 14px', borderRadius: 12,
                background: 'rgba(255,255,255,0.06)',
                border: `1px solid ${shareErr ? 'var(--red)' : 'var(--border)'}`,
                color: 'var(--text)', fontSize: 14, outline: 'none', marginBottom: 4,
              }}/>
            {shareErr && <div style={{ fontSize: 12, color: 'var(--red)', marginBottom: 8 }}>{shareErr}</div>}

            <div style={{ fontSize: 13, color: 'var(--text-2)', marginBottom: 8, marginTop: 14 }}>Role</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 20 }}>
              {['viewer', 'operator', 'admin'].map(r => (
                <button key={r} onClick={() => setRole(r)} style={{
                  display: 'flex', alignItems: 'center', gap: 12, padding: '12px 14px',
                  borderRadius: 12, textAlign: 'left',
                  background: role === r ? 'rgba(0,188,212,0.12)' : 'rgba(255,255,255,0.04)',
                  border: `1px solid ${role === r ? 'var(--cyan)' : 'var(--border)'}`,
                  color: 'var(--text)', cursor: 'pointer', transition: 'all 150ms',
                }}>
                  <div style={{ flex: 1 }}>
                    <div style={{ fontWeight: 600, fontSize: 13, textTransform: 'capitalize' }}>{r}</div>
                    <div style={{ fontSize: 11, color: 'var(--text-3)', marginTop: 2 }}>{ROLE_DESC[r]}</div>
                  </div>
                  {role === r && <Ic name="check" size={16} color="var(--cyan)"/>}
                </button>
              ))}
            </div>

            <button
              onClick={doShare} disabled={sharing || !email.trim()}
              style={{
                width: '100%', padding: '14px 0', borderRadius: 14,
                background: (!sharing && email.trim()) ? 'linear-gradient(90deg, var(--cyan), var(--teal))' : 'rgba(255,255,255,0.06)',
                border: 'none',
                color: (!sharing && email.trim()) ? '#0a0e27' : 'var(--text-3)',
                fontWeight: 700, fontSize: 15,
                cursor: (sharing || !email.trim()) ? 'not-allowed' : 'pointer',
              }}>
              {sharing ? 'Sharing…' : 'Share Device'}
            </button>
          </div>
        </div>,
        document.getElementById('modal-root')
      )}
    </div>
  );
};

const KVRow = ({ label, value, right, mono, last }) => (
  <div style={{
    display: 'flex', alignItems: 'center', justifyContent: 'space-between',
    padding: '10px 0',
    borderBottom: last ? 'none' : '1px solid var(--border)',
  }}>
    <span style={{fontSize: 13, color: 'var(--text-2)'}}>{label}</span>
    {right || <span className="num" style={{fontSize: 13, fontWeight: 500, fontFamily: mono ? 'JetBrains Mono, monospace' : undefined}}>{value}</span>}
  </div>
);

const ActionRow = ({ icon, label, hint, onClick, danger }) => (
  <button onClick={onClick} style={{
    display: 'flex', alignItems: 'center', gap: 12, width: '100%',
    padding: '12px', borderRadius: 10,
    background: 'transparent', border: 'none',
    color: '#fff', textAlign: 'left', cursor: 'pointer',
  }}>
    <div style={{
      width: 36, height: 36, borderRadius: 10,
      background: danger ? 'rgba(255,82,82,0.10)' : 'rgba(255,255,255,0.04)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      <Ic name={icon} size={16} color={danger ? 'var(--red)' : 'var(--text-2)'}/>
    </div>
    <div style={{flex: 1, minWidth: 0}}>
      <div style={{fontSize: 14, fontWeight: 500, color: danger ? 'var(--red)' : '#fff'}}>{label}</div>
      {hint && <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 2}}>{hint}</div>}
    </div>
    <Ic name="chevronRight" size={16} color="var(--text-3)"/>
  </button>
);

const SignalBars = ({ strength = 0 }) => (
  <div style={{display: 'flex', alignItems: 'flex-end', gap: 2, height: 14}}>
    {[1,2,3,4].map(i => (
      <div key={i} style={{
        width: 3, height: i*3 + 2,
        borderRadius: 1,
        background: i <= strength ? 'var(--cyan)' : 'rgba(255,255,255,0.12)',
      }}/>
    ))}
  </div>
);

// ── Provisioning HTTP client ──────────────────────────────────────────────────
// The device always serves at 192.168.4.1 while in SoftAP mode.
const AP_URL = 'http://192.168.4.1';

async function apFetch(path, opts = {}) {
  const res = await fetch(AP_URL + path, {
    ...opts,
    signal: AbortSignal.timeout(6000),
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

function rssiToStrength(rssi) {
  return rssi > -50 ? 4 : rssi > -60 ? 3 : rssi > -70 ? 2 : rssi > -80 ? 1 : 0;
}

// ── WIZARD ────────────────────────────────────────────────────────────────────
const AddDeviceWizard = ({ onClose, onFinish }) => {
  const [step,           setStep]          = useState(1);
  const [deviceType,     setDeviceType]    = useState(null);
  const [isVirtual,      setIsVirtual]     = useState(false);  // software simulator — no hardware needed
  const [confirmedBlink, setConfirmedBlink]= useState(false);
  const [configured,     setConfigured]    = useState(false);  // step 3 checkbox
  const [apSsid,         setApSsid]        = useState('');     // SSID entered in step 3
  const [deviceId,       setDeviceId]      = useState('');     // auto-filled in step 4
  const [form,           setForm]          = useState({ name: '', capacity: 1000, type: 'Overhead', location: '', site: 'Home', appliance: '' });
  const [progress,       setProgress]      = useState(0);
  const [progressDone,   setProgressDone]  = useState(false);
  const [progressMsg,    setProgressMsg]   = useState('');
  const [saving,         setSaving]        = useState(false);
  const [saveErr,        setSaveErr]       = useState('');

  // Sync Step 1 tile selection → form.type so the backend receives the correct type
  const DEVICE_TYPE_TO_FORM = { 'overhead': 'Overhead', 'underground': 'Underground', 'agri-pump': 'Agri Pump', 'em': 'Energy Meter', 'smart-plug': 'Smart Plug', 'smart-ro': 'Smart RO', 'occupancy-sensor': 'Occupancy Sensor', 'smart-ac': 'Smart AC' };
  useEffect(() => {
    if (deviceType && DEVICE_TYPE_TO_FORM[deviceType]) {
      setForm(f => ({ ...f, type: DEVICE_TYPE_TO_FORM[deviceType] }));
    }
  }, [deviceType]);

  // Step 5: poll backend until the device appears online, timeout after 45 s
  useEffect(() => {
    if (step !== 5 || progressDone || !deviceId) return;
    setProgress(1);
    const started = Date.now();
    const id = setInterval(async () => {
      try {
        const tanks = await API.get('/api/tanks');
        const t = tanks.find(t => t.deviceId === deviceId && t.online);
        if (t) {
          setProgress(3);
          setProgressDone(true);
          clearInterval(id);
        } else if (Date.now() - started > 45000) {
          clearInterval(id);
          setProgressMsg('Taking longer than expected — check your device LED. You can close and check the dashboard.');
        } else {
          setProgress(p => Math.min(p + 0.05, 2));
        }
      } catch {}
    }, 2500);
    return () => clearInterval(id);
  }, [step, progressDone, deviceId]);

  const goToStep5 = async () => {
    const isPlug = form.type === 'Smart Plug';
    const isRO   = form.type === 'Smart RO';
    const isOs   = form.type === 'Occupancy Sensor';
    const isAC   = form.type === 'Smart AC';
    // Virtual device: generate a SIM device ID using the correct prefix
    const _PREFIX = { 'overhead': 'AC100', 'underground': 'AC100', 'agri-pump': 'AP200', 'em': 'EM300', 'smart-plug': 'SP400', 'smart-ro': 'RO500', 'occupancy-sensor': 'OS500', 'smart-ac': 'AC500' };
    const _simId  = isVirtual ? `${_PREFIX[deviceType] || 'AC100'}_SIM_${Math.random().toString(16).slice(2, 10).toUpperCase()}` : null;
    // Set deviceId state now so the step-5 polling useEffect can use it
    if (isVirtual && _simId) setDeviceId(_simId);
    const newTank = {
      id:       (isPlug ? 'p' : isRO ? 'ro' : isOs ? 'os' : isAC ? 'ac' : 't') + Math.random().toString(36).slice(2, 7),
      deviceId: isVirtual ? _simId : (deviceId.trim() || null),
      virtual:  isVirtual,
      name:     form.name || (isPlug ? 'New Smart Plug' : isRO ? 'New RO Monitor' : isOs ? 'New Occupancy Sensor' : 'New Tank'),
      type:     form.type, location: form.location || 'Home', capacity: +form.capacity,
      site:     form.site || 'Home',
      level: 0, motor: false, motorMode: 'auto',
      valveIn: false, valveOut: false, online: false,
      runtime: 0, flow: 0, voltage: 0, current: 0,
      energyToday: 0, consumedToday: 0, cycles: 0,
      temp: 0, tds: 0, lastFill: 0,
      autoStart: 25, autoStop: 90, lowAlarm: 15, highAlarm: 95,
      maxRuntime: 60, vLow: 180, vHigh: 260, iMax: 8,
      dryRun: true, overflow: true, fw: '—', signal: 0, lastSeen: '—',
      ...(isPlug ? {
        on: false, appliance: form.appliance || '',
        schedules: [], timer: null,
        overload: 16, overloadAlert: true, childLock: false, ledIndicator: true,
        switchType: 'round', energyTotal: 0, runtimeToday: 0, power: 0,
      } : isRO ? {
        inletTDS: 0, outletTDS: 0, inletFlow: 0, outletFlow: 0,
        saltRejection: 0, recoveryRate: 0, purifiedToday: 0, inletVolTotal: 0,
        roMaxInletTDS: 1000, roMinRejection: 90, roMinRecovery: 20,
        roStaleHours: 8, roMaxTempRisk: 30, roPumpMaxCurrent: 2,
        roFlushDuration: 180, roMembraneCap: 5000, roPrefilterCap: 2000, roPostfilterCap: 3000,
        kind: 'ro',
      } : isOs ? {
        occupied: false, countToday: 0, duration: 0, relayOn: false,
        relayMode: 'auto', sensitivity: 5, runtimeToday: 0,
        osVacancyTimeout: 300, osHoldTime: 60, osSensitivity: 5,
        osRelayMode: 'auto', osZone: form.location || 'Room',
        osNightModeStart: '', osNightModeEnd: '', osNightSensitivity: 3,
        kind: 'occupancy',
      } : form.type === 'Agri Pump' ? {
        motorStatus: 'stopped_undervolt',
        phaseVoltageRY: 0, phaseVoltageYB: 0, phaseVoltageBR: 0,
        currentR: 0, currentY: 0, currentB: 0,
        phaseSequence: 'RYB', schedulerMode: 'off',
        runtimeSet: 30, runtimeCurrent: 0, runtimeRemaining: 0,
        offtimeSet: 30, offtimeRemaining: 0, currentCycle: 'on',
        lastStart: '—', lastStop: '—',
        todayRunHours: 0, todayCycles: 0, totalRunHours: 0, totalCycles: 0,
        phaseAllowed: '2&3', autoStartEnabled: false, autoDelay: 3,
        highVoltage2P: 260, lowVoltage2P: 180, voltageImbalance2P: 10, overload2P: 12, dryRun2P: 5,
        availablePhase3P: 'RYB', highVoltage3P: 460, lowVoltage3P: 380,
        voltageImbalance3P: 5, overload3P: 15, dryRun3P: 5,
      } : isAC ? {
        on: false, kind: 'smart_ac',
        temp: 24, mode: 'cool', fanSpeed: 'auto',
        brand: null, model: null, irLearned: false,
        schedules: [], timer: null, sleepCurve: null, wakeTimer: null,
        presets: [
          { id: 'pr1', name: 'Sleep', temp: 26, mode: 'cool', fanSpeed: 'low'  },
          { id: 'pr2', name: 'Work',  temp: 24, mode: 'cool', fanSpeed: 'auto' },
          { id: 'pr3', name: 'Turbo', temp: 18, mode: 'cool', fanSpeed: 'high' },
        ],
        switchType: 'round', power: 0, runtimeToday: 0, energyToday: 0,
        vLow: 180, vHigh: 260, iMax: 10, powerMax: 2500,
        appliance: form.appliance || 'Split AC',
      } : {}),
    };
    setSaving(true);
    setSaveErr('');
    try {
      await API.post('/api/tanks', newTank);
      onFinish(newTank);
      setStep(5);
    } catch (e) {
      // Issue 7 — duplicate tank name: send user back to step 4 to rename
      if (e.message && e.message.includes('HTTP 409')) {
        setSaveErr('A tank with this name already exists in your account. Please choose a different name.');
        setStep(4);
      } else {
        setSaveErr('Could not save to cloud: ' + e.message + '. Check your connection and try again.');
      }
    } finally {
      setSaving(false);
    }
  };

  const finish = () => onClose();

  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 90,
      background: 'rgba(5,8,20,0.85)', backdropFilter: 'blur(10px)',
      display: 'flex', alignItems: 'flex-end', justifyContent: 'center',
      animation: 'pop-in 200ms ease-out',
    }}>
      <div style={{
        width: '100%', maxWidth: 460,
        background: 'linear-gradient(180deg, rgba(20,26,55,0.98), rgba(15,20,48,1))',
        border: '1px solid var(--border-strong)',
        borderTopLeftRadius: 24, borderTopRightRadius: 24,
        maxHeight: '92vh', overflowY: 'auto',
        animation: 'slide-up 280ms ease-out',
      }}>
        {/* Wizard header */}
        <div style={{
          position: 'sticky', top: 0, padding: '14px 18px 10px',
          background: 'rgba(15,20,48,0.95)', backdropFilter: 'blur(12px)',
          borderBottom: '1px solid var(--border)', zIndex: 2,
        }}>
          <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10}}>
            <div style={{display: 'flex', alignItems: 'center', gap: 8}}>
              {step > 1 && step < 5 && (
                <button onClick={()=> isVirtual && step === 4 ? setStep(1) : setStep(s=>s-1)} style={{background: 'transparent', border: 'none', color: 'var(--text-2)', display: 'inline-flex', alignItems: 'center'}}>
                  <Ic name="chevronLeft" size={18}/>
                </button>
              )}
              <div style={{fontSize: 16, fontWeight: 600}}>Add Device</div>
            </div>
            <button onClick={onClose} style={{background: 'rgba(255,255,255,0.06)', border: '1px solid var(--border)', borderRadius: 8, width: 30, height: 30, display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff'}}>
              <Ic name="x" size={14}/>
            </button>
          </div>
          {/* Step dots */}
          <div style={{display: 'flex', gap: 4}}>
            {[1,2,3,4,5].map(i => (
              <div key={i} style={{
                flex: 1, height: 4, borderRadius: 2,
                background: i <= step ? 'linear-gradient(90deg, var(--cyan), var(--teal))' : 'rgba(255,255,255,0.08)',
                transition: 'background 250ms ease',
              }}/>
            ))}
          </div>
          <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 8, letterSpacing: 0.5}}>
            {isVirtual && step === 4 ? 'STEP 2 OF 3 · VIRTUAL' : isVirtual && step === 5 ? 'STEP 3 OF 3 · VIRTUAL' : `STEP ${step} OF 5`}
          </div>
        </div>

        <div style={{padding: '20px 18px 24px'}}>
          {step === 1 && <Step1 deviceType={deviceType} setDeviceType={setDeviceType} isVirtual={isVirtual} setIsVirtual={setIsVirtual}/>}
          {step === 2 && <Step2 confirmed={confirmedBlink} setConfirmed={setConfirmedBlink}/>}
          {step === 3 && <Step3 configured={configured} setConfigured={setConfigured} apSsid={apSsid} setApSsid={setApSsid} deviceType={deviceType}/>}
          {step === 4 && <Step4 deviceId={deviceId} setDeviceId={setDeviceId} form={form} setForm={setForm} deviceType={deviceType} isVirtual={isVirtual}/>}
          {step === 5 && <Step5 progress={progress} done={progressDone} msg={progressMsg}/>}

          <div style={{marginTop: 22}}>
            {step === 1 && <Btn full disabled={!deviceType} onClick={()=> isVirtual ? setStep(4) : setStep(2)} icon="arrowRight">Next</Btn>}
            {step === 2 && <Btn full disabled={!confirmedBlink} onClick={()=> setStep(3)} icon="arrowRight">Next</Btn>}
            {step === 3 && <Btn full disabled={!configured || !apSsid.trim()} onClick={()=>{ setDeviceId(apSsid.trim()); setStep(4); }} icon="arrowRight">Continue</Btn>}
            {step === 4 && (
              <>
                {saveErr && (
                  <div style={{marginBottom: 10, padding: '10px 12px', borderRadius: 10, background: 'rgba(255,82,82,0.08)', border: '1px solid rgba(255,82,82,0.25)', fontSize: 12, color: 'var(--red)', lineHeight: 1.5}}>
                    {saveErr}
                  </div>
                )}
                <Btn full disabled={!form.name || saving} onClick={goToStep5} icon={saving ? undefined : 'check'}>
                  {saving ? 'Saving…' : 'Finish Setup'}
                </Btn>
              </>
            )}
            {step === 5 && <Btn full onClick={finish} icon={progressDone ? 'check' : 'arrowRight'}>{progressDone ? 'Go to Dashboard' : 'Close'}</Btn>}
          </div>
        </div>
      </div>
    </div>
  );
};

const Step1 = ({ deviceType, setDeviceType, isVirtual, setIsVirtual }) => {
  const types = [
    { id: 'overhead',    label: 'Overhead Tank',    desc: 'Rooftop / elevated',              icon: 'home'    },
    { id: 'underground', label: 'Underground Sump', desc: 'Buried / basement',               icon: 'site'    },
    { id: 'agri-pump',  label: 'Agri Pump',         desc: '2 & 3 phase motor pump',          icon: 'zap'     },
    { id: 'em',          label: 'Energy Meter',     desc: 'Single/3-phase power monitor',    icon: 'bolt'    },
    { id: 'smart-plug',  label: 'Smart Plug',       desc: 'Switchable outlet + energy meter', icon: 'plug'   },
    { id: 'smart-ro',    label: 'Smart RO',         desc: 'RO water purifier monitor',       icon: 'droplets'},
    { id: 'occupancy-sensor', label: 'Occupancy Sensor', desc: 'PIR motion + relay output',    icon: 'userX'      },
    { id: 'smart-ac',         label: 'Smart AC',         desc: 'Universal IR AC controller',   icon: 'thermometer' },
  ];
  return (
    <div>
      <h3 style={{margin: '0 0 6px', fontSize: 18, fontWeight: 600}}>Select device type</h3>
      <p style={{margin: '0 0 16px', fontSize: 13, color: 'var(--text-2)'}}>What kind of Velonics Hub device are you adding?</p>
      <div style={{display: 'grid', gridTemplateColumns: 'repeat(2,1fr)', gap: 10}}>
        {types.map(t => (
          <button key={t.id} onClick={()=> setDeviceType(t.id)}
            style={{
              padding: 14, textAlign: 'left',
              background: deviceType === t.id ? 'rgba(0,212,255,0.1)' : 'rgba(255,255,255,0.03)',
              border: `1px solid ${deviceType === t.id ? 'var(--cyan)' : 'var(--border)'}`,
              borderRadius: 14, color: '#fff', transition: 'all 200ms ease',
            }}>
            <div style={{
              width: 36, height: 36, borderRadius: 10,
              background: deviceType === t.id ? 'rgba(0,212,255,0.18)' : 'rgba(255,255,255,0.05)',
              display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 10,
            }}>
              <Ic name={t.icon} size={18} color={deviceType === t.id ? 'var(--cyan)' : 'var(--text-2)'}/>
            </div>
            <div style={{fontSize: 13, fontWeight: 600}}>{t.label}</div>
            <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 2}}>{t.desc}</div>
          </button>
        ))}
      </div>

      {/* Virtual device toggle */}
      <div
        onClick={() => setIsVirtual(v => !v)}
        style={{
          marginTop: 14, padding: '12px 14px', borderRadius: 12, cursor: 'pointer',
          display: 'flex', alignItems: 'center', gap: 12,
          background: isVirtual ? 'rgba(0,212,255,0.08)' : 'rgba(255,255,255,0.03)',
          border: `1px solid ${isVirtual ? 'var(--cyan)' : 'var(--border)'}`,
          transition: 'all 200ms ease',
        }}>
        <div style={{
          width: 38, height: 22, borderRadius: 11, position: 'relative',
          background: isVirtual ? 'var(--cyan)' : 'rgba(255,255,255,0.12)',
          transition: 'background 200ms ease', flexShrink: 0,
        }}>
          <div style={{
            position: 'absolute', top: 3, left: isVirtual ? 19 : 3,
            width: 16, height: 16, borderRadius: 8, background: '#fff',
            transition: 'left 200ms ease',
          }}/>
        </div>
        <div>
          <div style={{fontSize: 13, fontWeight: 600}}>Virtual Device (No Hardware)</div>
          <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 1}}>Backend simulates telemetry — no ESP32 needed</div>
        </div>
      </div>

      {isVirtual && (
        <div style={{marginTop: 10, padding: '10px 12px', borderRadius: 10, background: 'rgba(0,212,255,0.06)', border: '1px solid rgba(0,212,255,0.2)', fontSize: 12, color: 'var(--cyan)', lineHeight: 1.5}}>
          Steps 2–3 (LED blink, WiFi provisioning) will be skipped. You'll name the device next, then the backend simulates live data automatically.
        </div>
      )}
    </div>
  );
};

const Step2 = ({ confirmed, setConfirmed }) => (
  <div>
    <h3 style={{margin: '0 0 6px', fontSize: 18, fontWeight: 600}}>Power on your device</h3>
    <p style={{margin: '0 0 16px', fontSize: 13, color: 'var(--text-2)'}}>The status LED should blink rapidly (about 4 times per second) indicating provisioning mode.</p>
    <div style={{
      padding: 28, background: 'rgba(255,255,255,0.03)', border: '1px solid var(--border)',
      borderRadius: 16, display: 'flex', justifyContent: 'center', alignItems: 'center',
    }}>
      <svg width="180" height="120" viewBox="0 0 180 120">
        <rect x="20" y="30" width="140" height="60" rx="10" fill="rgba(255,255,255,0.05)" stroke="rgba(255,255,255,0.18)"/>
        <rect x="30" y="40" width="120" height="14" rx="3" fill="rgba(0,212,255,0.08)" stroke="rgba(0,212,255,0.3)"/>
        <text x="90" y="51" fill="var(--cyan)" fontSize="9" textAnchor="middle" fontFamily="JetBrains Mono">VELONICS ONE · v2.3</text>
        <circle cx="40" cy="74" r="4" fill="#00e676" style={{animation:'blink 0.5s steps(2) infinite'}}/>
        <text x="50" y="78" fill="var(--text-2)" fontSize="9">PWR</text>
        <circle cx="80" cy="74" r="4" fill="#00d4ff" style={{animation:'blink 0.5s steps(2) infinite'}}/>
        <text x="90" y="78" fill="var(--text-2)" fontSize="9">WIFI</text>
        <circle cx="125" cy="74" r="4" fill="#ffab40"/>
        <text x="135" y="78" fill="var(--text-2)" fontSize="9">RUN</text>
      </svg>
    </div>
    <label style={{display: 'flex', alignItems: 'center', gap: 10, marginTop: 16, padding: 12, background: 'rgba(255,255,255,0.03)', border: '1px solid var(--border)', borderRadius: 12, cursor: 'pointer'}}>
      <div onClick={()=> setConfirmed(!confirmed)} style={{
        width: 22, height: 22, borderRadius: 6,
        background: confirmed ? 'var(--cyan)' : 'transparent',
        border: `1.5px solid ${confirmed ? 'var(--cyan)' : 'var(--text-3)'}`,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
      }}>
        {confirmed && <Ic name="check" size={14} color="#0a0e27" strokeWidth={3}/>}
      </div>
      <span style={{fontSize: 13}}>I confirm the LED is blinking rapidly</span>
    </label>
  </div>
);

const _DEVICE_PREFIX = {
  'overhead': 'AC100', 'underground': 'AC100', 'garden': 'AC100', 'industrial': 'AC100',
  'agri-pump': 'AP200', 'em': 'EM300', 'smart-plug': 'SP400', 'smart-ro': 'RO500', 'occupancy-sensor': 'OS500',
};

const Step3 = ({ configured, setConfigured, apSsid, setApSsid, deviceType }) => {
  const exampleSsid = (_DEVICE_PREFIX[deviceType] || 'AC100') + '_XXXXXXXXXXXX';
  const [detecting, setDetecting] = useState(true);
  const [pin] = useState(() => Math.floor(1000 + Math.random() * 9000).toString());

  useEffect(() => {
    if (apSsid) {
      setDetecting(false);
      return;
    }

    let isCancelled = false;
    const checkStatus = async () => {
      try {
        // 1. Try polling the SoftAP (works if still connected & using HTTP mock)
        apFetch('/api/status', { signal: AbortSignal.timeout(1000) })
          .then(res => {
            if (!isCancelled && res && res.apSsid) {
              setApSsid(res.apSsid);
              setDetecting(false);
            }
          }).catch(() => {});

        // 2. Try polling the cloud backend for newly provisioned devices
        // (works after user switches back to home WiFi and device connects to MQTT)
        const unRes = await API.get(`/api/devices/unassigned?pin=${pin}`);
        if (!isCancelled && unRes && unRes.unassigned && unRes.unassigned.length > 0) {
          setApSsid(unRes.unassigned[0]);
          setDetecting(false);
        }
      } catch (e) {
        // silent fail, keep polling
      }
    };

    const timer = setInterval(checkStatus, 2500);
    checkStatus();

    return () => {
      isCancelled = true;
      clearInterval(timer);
    };
  }, [apSsid, setApSsid]);

  return (
    <div>
      <h3 style={{margin: '0 0 6px', fontSize: 18, fontWeight: 600}}>Configure device WiFi</h3>
      <p style={{margin: '0 0 16px', fontSize: 13, color: 'var(--text-2)'}}>Join the device's network, configure home WiFi on the setup page, then come back here.</p>

      {/* Step A — join AP */}
      <div style={{display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10}}>
        <div style={{width: 22, height: 22, borderRadius: '50%', background: 'rgba(0,212,255,0.18)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0}}>
          <span style={{fontSize: 11, fontWeight: 700, color: 'var(--cyan)'}}>1</span>
        </div>
        <div style={{fontSize: 13}}>Go to <strong>WiFi settings</strong> and connect to the device network (e.g. <strong style={{color:'var(--cyan)', fontFamily:'JetBrains Mono,monospace'}}>{exampleSsid}</strong>)</div>
      </div>

      {/* Step B — open setup page */}
      <div style={{display: 'flex', alignItems: 'flex-start', gap: 10, marginBottom: 14}}>
        <div style={{width: 22, height: 22, borderRadius: '50%', background: 'rgba(0,212,255,0.18)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, marginTop: 2}}>
          <span style={{fontSize: 11, fontWeight: 700, color: 'var(--cyan)'}}>2</span>
        </div>
        <div style={{flex: 1}}>
          <div style={{fontSize: 13, marginBottom: 8}}>Open the setup page. Enter your home WiFi password and this secure Claim PIN: <strong style={{color:'var(--green)', fontSize: 16, letterSpacing: 2, background: 'rgba(0,255,0,0.1)', padding: '2px 6px', borderRadius: 4, fontFamily: 'monospace'}}>{pin}</strong></div>
          <a href="http://192.168.4.1" target="_blank" rel="noopener noreferrer" style={{
            display: 'inline-flex', alignItems: 'center', gap: 8, padding: '10px 14px',
            background: 'linear-gradient(90deg, var(--cyan), var(--teal))',
            borderRadius: 10, color: '#0a0e27', fontWeight: 700, fontSize: 13,
            textDecoration: 'none',
          }}>
            <Ic name="globe" size={15} color="#0a0e27"/> Open Setup Page →
          </a>
        </div>
      </div>

      {/* Step C — reconnect */}
      <div style={{display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14}}>
        <div style={{width: 22, height: 22, borderRadius: '50%', background: 'rgba(0,212,255,0.18)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0}}>
          <span style={{fontSize: 11, fontWeight: 700, color: 'var(--cyan)'}}>3</span>
        </div>
        <div style={{fontSize: 13}}>After tapping "Connect", <strong>switch your phone back to your home WiFi</strong> and return here.</div>
      </div>

      {/* SSID input — becomes the Device ID */}
      <div style={{marginBottom: 14}}>
        <div style={{display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6}}>
          <div style={{fontSize: 11, color: 'var(--text-2)', textTransform: 'uppercase', letterSpacing: 0.5}}>WiFi network name you connected to</div>
          {detecting && <div style={{fontSize: 11, color: 'var(--cyan)', display: 'flex', alignItems: 'center', gap: 4}}><div style={{width: 10, height: 10, borderRadius: '50%', border: '2px solid rgba(0,212,255,0.3)', borderTopColor: 'var(--cyan)', animation: 'spin 1s linear infinite'}}/> Auto-detecting...</div>}
          {!detecting && apSsid && <div style={{fontSize: 11, color: 'var(--green)', display: 'flex', alignItems: 'center', gap: 4}}><Ic name="check" size={12} color="var(--green)"/> Auto-detected</div>}
        </div>
        <div style={{display: 'flex', alignItems: 'center', gap: 8, background: 'rgba(255,255,255,0.04)', border: `1px solid ${apSsid ? 'var(--cyan)' : 'var(--border)'}`, borderRadius: 12, padding: '10px 12px'}}>
          <Ic name="wifi" size={16} color="var(--text-2)"/>
          <input type="text" value={apSsid} readOnly={detecting} onChange={e => setApSsid(e.target.value)}
            placeholder="Auto-detected Device ID"
            style={{background: 'transparent', border: 'none', outline: 'none', color: '#fff', fontSize: 14, flex: 1, fontFamily: 'JetBrains Mono, monospace'}}/>
        </div>
        <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 5}}>Once you complete setup, this will populate automatically.</div>
      </div>

      <label style={{display: 'flex', alignItems: 'center', gap: 10, padding: 12, background: 'rgba(255,255,255,0.03)', border: '1px solid var(--border)', borderRadius: 12, cursor: 'pointer'}}>
        <div onClick={()=> setConfigured(!configured)} style={{
          width: 22, height: 22, borderRadius: 6, flexShrink: 0,
          background: configured ? 'var(--cyan)' : 'transparent',
          border: `1.5px solid ${configured ? 'var(--cyan)' : 'var(--text-3)'}`,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          {configured && <Ic name="check" size={14} color="#0a0e27" strokeWidth={3}/>}
        </div>
        <span style={{fontSize: 13}}>Done — WiFi configured, phone reconnected to home network</span>
      </label>
    </div>
  );
};

const Step4 = ({ deviceId, setDeviceId, form, setForm, deviceType, isVirtual }) => {
  const [knownDevices, setKnownDevices] = useState([]);
  useEffect(() => {
    if (window.API) API.get('/api/devices').then(setKnownDevices).catch(() => {});
  }, []);

  return (
  <div>
    <h3 style={{margin: '0 0 6px', fontSize: 18, fontWeight: 600}}>Name your device</h3>
    <p style={{margin: '0 0 16px', fontSize: 13, color: 'var(--text-2)'}}>
      {isVirtual ? 'Give this virtual device a name and location.' : 'Device ID was captured in the previous step. Give this device a name.'}
    </p>

    {isVirtual ? (
      <div style={{display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px', background: 'rgba(0,212,255,0.06)', border: '1px solid rgba(0,212,255,0.25)', borderRadius: 12, marginBottom: 14}}>
        <Ic name="cpu" size={16} color="var(--cyan)"/>
        <span style={{fontSize: 12, color: 'var(--cyan)'}}>A simulated device ID will be auto-assigned by the backend</span>
      </div>
    ) : (
      <Field label="Device ID">
        <div style={{display: 'flex', alignItems: 'center', gap: 8, background: 'rgba(0,212,255,0.05)', border: '1px solid rgba(0,212,255,0.3)', borderRadius: 12, padding: '10px 12px'}}>
          <Ic name="radio" size={16} color="var(--cyan)"/>
          <span style={{fontSize: 14, flex: 1, fontFamily: 'JetBrains Mono, monospace', color: 'var(--cyan)'}}>{deviceId || '—'}</span>
          <Ic name="check" size={14} color="var(--green)"/>
        </div>
        <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 5}}>Captured from WiFi network name in step 3</div>
      </Field>
    )}

    <div style={{marginTop: isVirtual ? 0 : 14, display: 'flex', flexDirection: 'column', gap: 10}}>
      <Field label="Device name *">
        <TextInput icon="grid" value={form.name} onChange={(v)=> setForm({...form, name: v})} placeholder={deviceType === 'smart-plug' ? 'e.g. Geyser Plug, Bedroom AC' : 'e.g. Main Panel EM, Rooftop Tank'}/>
      </Field>
      {deviceType === 'smart-plug' && (
        <Field label="Connected appliance">
          <TextInput icon="plug" value={form.appliance || ''} onChange={(v)=> setForm({...form, appliance: v})} placeholder="e.g. Geyser, TV, Air Cooler"/>
        </Field>
      )}
      {isVirtual && (
        <Field label="Location">
          <TextInput icon="site" value={form.location || ''} onChange={(v)=> setForm({...form, location: v})} placeholder="e.g. Server Room, Rooftop, Office"/>
        </Field>
      )}
    </div>
  </div>
  );
};

const Step5 = ({ progress, done, msg }) => {
  const clampedProgress = Math.min(Math.floor(progress), 2);
  const statusItems = [
    { label: 'Tank saved to cloud',    icon: 'check',  done: true   },
    { label: 'Device connecting…',     icon: 'wifi',   done: done || progress >= 2 },
    { label: 'Device online!',         icon: 'checkCircle', done   },
  ];
  return (
    <div>
      {done ? (
        <div style={{textAlign: 'center', padding: '8px 0 18px'}}>
          <div style={{
            width: 64, height: 64, borderRadius: '50%',
            background: 'rgba(0,230,118,0.18)',
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            boxShadow: '0 0 24px rgba(0,230,118,0.3)',
          }}>
            <Ic name="check" size={32} color="var(--green)" strokeWidth={3}/>
          </div>
          <h3 style={{margin: '12px 0 4px', fontSize: 18, fontWeight: 600}}>Device is online!</h3>
          <p style={{margin: 0, fontSize: 13, color: 'var(--text-2)'}}>Your tank is now live and sending data.</p>
        </div>
      ) : (
        <>
          <h3 style={{margin: '0 0 6px', fontSize: 18, fontWeight: 600}}>Waiting for device…</h3>
          <p style={{margin: '0 0 16px', fontSize: 13, color: 'var(--text-2)'}}>The device should connect to the cloud within 30 seconds of joining your home WiFi.</p>
        </>
      )}

      <div style={{padding: 16, background: 'rgba(255,255,255,0.03)', border: '1px solid var(--border)', borderRadius: 14}}>
        {statusItems.map((s, i) => {
          const active = !done && i === clampedProgress;
          return (
            <div key={s.label} style={{display: 'flex', alignItems: 'center', gap: 12, padding: '8px 0'}}>
              <div style={{
                width: 28, height: 28, borderRadius: 8,
                background: s.done ? 'rgba(0,230,118,0.18)' : active ? 'rgba(0,212,255,0.18)' : 'rgba(255,255,255,0.04)',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                animation: active ? 'pulse-glow 1.4s ease-in-out infinite' : undefined,
              }}>
                {s.done
                  ? <Ic name="check" size={14} color="var(--green)" strokeWidth={3}/>
                  : active
                    ? <div style={{width:14, height:14, border:'2px solid rgba(255,255,255,0.2)', borderTopColor:'var(--cyan)', borderRadius:'50%', animation:'spin 0.7s linear infinite'}}/>
                    : <Ic name={s.icon} size={14} color="var(--text-3)"/>}
              </div>
              <span style={{fontSize: 13, color: s.done ? '#fff' : active ? '#fff' : 'var(--text-3)', fontWeight: active ? 600 : 400}}>
                {s.label}
              </span>
            </div>
          );
        })}
        <div style={{marginTop: 10, height: 4, borderRadius: 2, background: 'rgba(255,255,255,0.06)', overflow: 'hidden'}}>
          <div style={{
            width: done ? '100%' : `${(progress / 3) * 100}%`, height: '100%',
            background: 'linear-gradient(90deg, var(--cyan), var(--teal))',
            transition: 'width 800ms ease',
          }}/>
        </div>
      </div>

      {msg && (
        <div style={{marginTop: 12, padding: '10px 12px', borderRadius: 10, background: 'rgba(255,171,64,0.08)', border: '1px solid rgba(255,171,64,0.25)', fontSize: 12, color: 'var(--amber)', lineHeight: 1.5}}>
          {msg}
        </div>
      )}
    </div>
  );
};

const Field = ({ label, children }) => (
  <div>
    <div style={{fontSize: 11, color: 'var(--text-2)', textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 6}}>{label}</div>
    {children}
  </div>
);

const SelectInput = ({ options, value, onChange }) => (
  <div style={{
    display: 'flex', alignItems: 'center', gap: 6,
    background: 'rgba(255,255,255,0.04)', border: '1px solid var(--border)',
    borderRadius: 12, padding: '6px 10px',
  }}>
    <select value={value} onChange={e=> onChange(e.target.value)} style={{
      background: 'transparent', border: 'none', outline: 'none', color: '#fff',
      fontSize: 14, flex: 1, fontFamily: 'inherit', padding: '6px 0',
    }}>
      {options.map(o => <option key={o} value={o} style={{background: '#1a1f3a'}}>{o}</option>)}
    </select>
    <Ic name="chevronDown" size={14} color="var(--text-2)"/>
  </div>
);

window.Devices = Devices;
