// Endpoint detail drawer
function NodeDetail({ node, onClose, onReboot, onMaint }) {
  // Local state must be declared unconditionally (Rules of Hooks).
  const [shotBust, setShotBust] = React.useState(0);
  const [shotBusy, setShotBusy] = React.useState(false);
  const [shotErr, setShotErr] = React.useState(null);

  if (!node) return <div className="drawer" />;
  const statusLabel = { ok: 'Up', warn: 'Warning', crit: 'Down', off: 'Offline', maint: 'Maintenance', unknown: 'Pending' }[node.status] || node.status;

  const shot = node.screenshot || { exists: false, capturedAt: 0 };
  const shotSrc = shot.exists
    ? `/api/screenshots/${node.id}.jpg?v=${shotBust || shot.capturedAt}`
    : null;
  const shotAge = shot.capturedAt ? window.fmtRel(shot.capturedAt) : null;

  async function recaptureShot() {
    setShotBusy(true); setShotErr(null);
    try {
      const meta = await window.adminFetch(`/api/admin/screenshots/${node.id}`, { method: 'POST' });
      setShotBust(meta.capturedAt || Date.now());
      if (meta.error) setShotErr(meta.error);
    } catch (e) {
      setShotErr(e.message || 'capture failed');
    } finally { setShotBusy(false); }
  }

  return (
    <div className={`drawer ${node ? 'open' : ''}`}>
      <div className="drawer-head">
        <div style={{flex: 1, minWidth: 0}}>
          <div style={{display:'flex', alignItems:'center', gap:8}}>
            <span className={`dot ${node.status}`} />
            <div className="drawer-title" style={{overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>{node.displayName}</div>
            <span className={`chip ${node.status}`}>{statusLabel}</span>
          </div>
          <div className="drawer-sub" style={{overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>
            <a href={node.url} target="_blank" rel="noreferrer" style={{color:'var(--accent)', textDecoration:'none'}}>{node.url}</a>
          </div>
          <div className="drawer-sub">{node.group} · {node.protocol}:{node.port}</div>
        </div>
        <button className="close" onClick={onClose}>×</button>
      </div>
      <div className="drawer-body">
        <div>
          <div style={{fontSize: 10, letterSpacing:'0.1em', color:'var(--text-faint)', textTransform:'uppercase', marginBottom: 6, display:'flex', alignItems:'center', gap: 8}}>
            <span>Screenshot</span>
            <span style={{color:'var(--text-mute)', textTransform:'none', letterSpacing:0, fontSize: 10}}>
              {shot.exists
                ? `captured ${shotAge}`
                : (shotBusy ? 'capturing…' : 'not yet captured')}
            </span>
            <span className="spacer" style={{flex: 1}} />
            <button className="btn" style={{fontSize: 10, padding:'2px 8px'}} onClick={recaptureShot} disabled={shotBusy}>
              {shotBusy ? '…' : 'recapture'}
            </button>
          </div>
          <div style={{
            border: '1px solid var(--border)', background: 'var(--surface)',
            borderRadius: 2, overflow: 'hidden', aspectRatio: '1.6',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            position: 'relative',
          }}>
            {shotSrc ? (
              <a href={node.url} target="_blank" rel="noreferrer" style={{display:'block', width:'100%', height:'100%'}}>
                <img src={shotSrc} alt="" style={{display:'block', width:'100%', height:'100%', objectFit:'cover', opacity: shotBusy ? 0.5 : 1}} />
              </a>
            ) : (
              <div style={{color:'var(--text-mute)', fontSize: 11, padding: 12, textAlign:'center'}}>
                {shotBusy ? 'Capturing first thumbnail…' : 'No screenshot yet · weekly capture runs in background'}
              </div>
            )}
            {shot.error && !shotBusy && (
              <div style={{position:'absolute', bottom:0, left:0, right:0, background:'rgba(10,14,20,0.85)', color:'var(--crit)', fontSize: 10, padding:'3px 8px'}}>
                last capture failed: {shot.error}
              </div>
            )}
          </div>
          {shotErr && <div style={{color:'var(--crit)', fontSize: 10, marginTop: 4}}>recapture: {shotErr}</div>}
        </div>

        <div style={{display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap: 8}}>
          {[
            { label:'response', val: node.status === 'off' ? '—' : `${node.latency.toFixed(0)}`, unit:'ms', color: node.latency > 800 ? 'var(--crit)' : 'var(--text)' },
            { label:'http', val: node.httpCode === 0 ? '—' : node.httpCode, color: node.httpCode >= 500 ? 'var(--crit)' : node.httpCode >= 400 ? 'var(--warn)' : node.httpCode > 0 ? 'var(--ok)' : 'var(--text-mute)' },
            { label:'tls', val: node.sslDaysLeft, unit:'d', color: node.sslDaysLeft < 14 ? 'var(--crit)' : node.sslDaysLeft < 30 ? 'var(--warn)' : 'var(--text)' },
          ].map(k => (
            <div key={k.label} style={{padding: 8, border:'1px solid var(--border)', borderRadius: 2, background:'var(--surface)'}}>
              <div style={{fontSize: 9, letterSpacing:'0.1em', color:'var(--text-faint)', textTransform:'uppercase'}}>{k.label}</div>
              <div style={{fontSize: 18, fontWeight: 500, marginTop: 2, color: k.color || 'var(--text)'}}>{k.val}<span style={{fontSize: 10, color: 'var(--text-faint)'}}> {k.unit || ''}</span></div>
            </div>
          ))}
        </div>

        <div>
          <div style={{fontSize: 10, letterSpacing:'0.1em', color:'var(--text-faint)', textTransform:'uppercase', marginBottom: 6}}>Response time · last 60 checks</div>
          <div style={{border:'1px solid var(--border)', background:'var(--surface)', padding: 8, borderRadius: 2}}>
            <window.Sparkline values={node.latencyHist} width={380} height={60} color={node.latency > 800 ? 'var(--crit)' : 'var(--accent)'} />
          </div>
        </div>

        <div>
          <div style={{fontSize: 10, letterSpacing:'0.1em', color:'var(--text-faint)', textTransform:'uppercase', marginBottom: 6}}>Network throughput</div>
          <div style={{border:'1px solid var(--border)', background:'var(--surface)', padding: 8, borderRadius: 2}}>
            <window.Sparkline values={node.netHist} width={380} height={60} color="var(--ok)" />
          </div>
        </div>

        <div>
          <div style={{fontSize: 10, letterSpacing:'0.1em', color:'var(--text-faint)', textTransform:'uppercase', marginBottom: 6}}>Details</div>
          <dl className="kv" style={{border:'1px solid var(--border)', padding: 10, borderRadius: 2, background:'var(--surface)'}}>
            <dt>url</dt><dd style={{wordBreak:'break-all'}}>{node.url}</dd>
            <dt>hostname</dt><dd>{node.hostname}</dd>
            <dt>path</dt><dd>{node.path}</dd>
            <dt>protocol</dt><dd>{node.protocol}</dd>
            <dt>port</dt><dd>{node.port}</dd>
            <dt>group</dt><dd>{node.group}</dd>
            <dt>uptime</dt><dd>{node.status === 'off' ? '—' : window.fmtUptime(node.uptime)}</dd>
            <dt>tls expires</dt><dd style={{color: node.sslDaysLeft < 14 ? 'var(--crit)' : node.sslDaysLeft < 30 ? 'var(--warn)' : 'var(--text)'}}>in {node.sslDaysLeft} days</dd>
            <dt>agent</dt><dd>{node.status === 'off' ? <span style={{color:'var(--crit)'}}>no response</span> : <span style={{color:'var(--ok)'}}>responsive</span>}</dd>
            <dt>probe</dt><dd>every 30s · HEAD</dd>
          </dl>
        </div>

        <div>
          <div style={{fontSize: 10, letterSpacing:'0.1em', color:'var(--text-faint)', textTransform:'uppercase', marginBottom: 6}}>Recent probe log</div>
          <div style={{border:'1px solid var(--border)', background:'var(--surface)', borderRadius: 2, fontSize: 11}}>
            {[
              {ts: '-00:15', code: node.httpCode, ms: node.latency, ok: node.status === 'ok'},
              {ts: '-00:45', code: node.httpCode, ms: node.latency * 0.96, ok: node.status === 'ok'},
              {ts: '-01:15', code: node.httpCode, ms: node.latency * 1.02, ok: node.status === 'ok'},
              {ts: '-01:45', code: node.httpCode, ms: node.latency * 0.93, ok: node.status === 'ok'},
            ].map((p, i) => (
              <div key={i} style={{display:'grid', gridTemplateColumns:'70px 60px 80px 1fr', gap: 8, padding:'5px 10px', borderBottom: '1px solid var(--border)', fontFamily:'var(--mono)'}}>
                <span style={{color:'var(--text-faint)'}}>{p.ts}</span>
                <span style={{color: p.code >= 500 ? 'var(--crit)' : p.code >= 400 ? 'var(--warn)' : p.code > 0 ? 'var(--ok)' : 'var(--text-mute)'}}>{p.code || '—'}</span>
                <span style={{color:'var(--text-dim)'}}>{node.status === 'off' ? '—' : `${p.ms.toFixed(0)}ms`}</span>
                <span style={{color: p.ok ? 'var(--ok)' : 'var(--crit)'}}>{p.ok ? '● ok' : '● fail'}</span>
              </div>
            ))}
          </div>
        </div>
      </div>
      <div className="drawer-actions">
        <button className="action-btn" onClick={() => onMaint(node)}>{node.paused ? 'resume' : 'pause'}</button>
        <button className="action-btn" onClick={() => window.open(node.url, '_blank')}>visit</button>
        <button className="action-btn" onClick={() => alert('Viewing logs for ' + node.hostname)}>logs</button>
        <button className="action-btn danger" onClick={() => onReboot(node)}>recheck</button>
      </div>
    </div>
  );
}

Object.assign(window, { NodeDetail });
