/* global React */
// =======================================================================
// BlazeConnector Admin v3 — Operations pages
// Dashboard · Mensajería · Colas · Logs · Alertas
// =======================================================================
const { useState: _us, useEffect: _ue, useMemo: _um, useRef: _ur, useCallback: _uc } = React;

/* =========================================================================
   DASHBOARD
   ========================================================================= */
function PageDashboard({ tenant, sse, systemHealth }) {
  const [tick, setTick] = _us(0);
  _ue(() => { const id = setInterval(() => setTick(t => t + 1), 4000); return () => clearInterval(id); }, []);

  const isOutage = systemHealth === 'outage';
  const isDegraded = systemHealth === 'degraded';

  // KPIs adjusted by health
  const baseRate = isOutage ? 12.4 : isDegraded ? 3.1 : 0.6;
  const baseLat = isOutage ? 1840 : isDegraded ? 720 : 318;
  const baseFailed = isOutage ? 412 : isDegraded ? 84 : 18;

  const kpis = [
    { label: 'Mensajes / min',  value: 1242 + (tick % 5) * 4, unit: '',     delta: 3.2,  series: window.DASHBOARD_SERIES.msgsPerMin, color: 'orange', foot: 'últimos 60m · ↑ vs ayer' },
    { label: 'Error rate',      value: baseRate + '%', unit: '',            delta: isOutage ? 412 : isDegraded ? 84 : -12, deltaTone: isOutage || isDegraded ? 'down' : 'up', series: window.DASHBOARD_SERIES.errorsPerMin, color: isOutage ? 'danger' : isDegraded ? 'warn' : 'green', foot: baseFailed + ' fallos / 60m' },
    { label: 'Latencia p95',    value: baseLat,        unit: 'ms',          delta: isOutage ? 240 : isDegraded ? 64 : -8, deltaTone: isOutage || isDegraded ? 'down' : 'up', series: window.DASHBOARD_SERIES.latencyP95, color: isDegraded ? 'warn' : 'blue', foot: 'p99 ' + (baseLat * 2.1).toFixed(0) + 'ms' },
    { label: 'Tenants activos', value: 10, unit: '/ 12',                    delta: 0, series: [10,10,10,10,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10], color: 'violet', foot: '2 suspendidos · 0 nuevos hoy' },
    { label: 'Logs / min',      value: 2418, unit: '', delta: 8.4, series: window.DASHBOARD_SERIES.inbound, color: 'teal', foot: 'ingest p95 142ms' },
    { label: 'Workers activos', value: 48,   unit: '/ 56', delta: 0, series: window.DASHBOARD_SERIES.workerActive, color: 'green', foot: '8 idle · 0 caídos' }
  ];

  const queueDepth = window.QUEUES.reduce((a, q) => a + q.pending + q.active, 0);
  const recentActivity = _um(() => window.genMessages(8), [tick]);

  return (
    <div className="page">
      <div className="page-header">
        <div>
          <h1 className="page-title">Dashboard</h1>
          <p className="page-sub">Estado operacional · {tenant.id === '*' ? 'todos los tenants' : tenant.name} · actualizado hace {tick * 4}s</p>
        </div>
        <div className="page-actions">
          <button className="btn btn-ghost btn-sm"><window.Icon name="calendar" size={12} /> Últimas 24h <window.Icon name="chevron-down" size={11} /></button>
          <button className="btn btn-ghost btn-sm"><window.Icon name="refresh-cw" size={12} /> Refrescar</button>
          <button className="btn btn-secondary btn-sm"><window.Icon name="download" size={12} /> Export</button>
        </div>
      </div>

      {(isOutage || isDegraded) && (
        <div className="card" style={{ marginBottom: 12, borderColor: isOutage ? 'rgba(224,62,62,0.4)' : 'rgba(242,169,0,0.4)', background: isOutage ? 'var(--st-danger-bg)' : 'var(--st-warn-bg)' }}>
          <div className="card-body" style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <window.Icon name={isOutage ? 'octagon-alert' : 'triangle-alert'} size={18} style={{ color: isOutage ? 'var(--st-danger-fg)' : 'var(--st-warn-fg)' }} />
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, color: 'var(--app-fg1)' }}>{isOutage ? 'Outage parcial en pagos.cybersource' : 'Degradación en cola messaging — backlog elevado'}</div>
              <div style={{ fontSize: 12, color: 'var(--app-fg2)' }}>{isOutage ? 'CyberSource no responde desde 17:18. Affected: 1 tenant. Fallback activo: pendiente.' : 'Backlog 1,842 mensajes. p95 ingest +84%. Auto-scale de workers en curso.'}</div>
            </div>
            <button className="btn btn-secondary btn-sm">Ver runbook <window.Icon name="external-link" size={11} /></button>
            <button className="btn btn-ghost btn-sm">Reconocer</button>
          </div>
        </div>
      )}

      <div className="grid-6" style={{ marginBottom: 12 }}>
        {kpis.map((k) => <window.KpiCard key={k.label} {...k} />)}
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 12, marginBottom: 12 }}>
        <window.SectionCard title="Throughput de mensajería" icon="line-chart" sub="por minuto · últimas 60 min"
          actions={<>
            <button className="btn btn-ghost btn-sm" style={{ background: 'var(--app-row-active)', borderColor: 'rgba(255,90,31,0.35)' }}>1h</button>
            <button className="btn btn-ghost btn-sm">6h</button>
            <button className="btn btn-ghost btn-sm">24h</button>
            <button className="btn btn-ghost btn-sm">7d</button>
          </>}>
          <window.AreaChart data={window.DASHBOARD_SERIES.msgsPerMin} color="orange" height={200}
            xLabels={['60m', '50m', '40m', '30m', '20m', '10m', 'ahora']} />
        </window.SectionCard>

        <window.SectionCard title="Mensajes por canal" icon="pie-chart" sub="últimas 24h">
          <div style={{ display: 'flex', gap: 16, alignItems: 'center' }}>
            <window.Donut segments={window.CHANNEL_BREAKDOWN.map(c => ({ value: c.count, color: c.color }))} centerLabel="107k" centerSub="MENSAJES" size={130} />
            <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 8 }}>
              {window.CHANNEL_BREAKDOWN.map(c => (
                <div key={c.ch} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ width: 8, height: 8, borderRadius: 2, background: c.color }}></span>
                  <span style={{ fontSize: 12, fontWeight: 600, flex: 1 }}>{c.label}</span>
                  <span className="mono" style={{ fontSize: 11.5, color: 'var(--app-fg2)' }}>{c.count.toLocaleString()}</span>
                  <span className="mono" style={{ fontSize: 11, color: 'var(--app-fg3)', minWidth: 40, textAlign: 'right' }}>{c.pct}%</span>
                </div>
              ))}
            </div>
          </div>
        </window.SectionCard>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 12 }}>
        <window.SectionCard title="Profundidad de colas" icon="layers" sub={queueDepth.toLocaleString() + ' en cola · ' + window.QUEUES.reduce((a,q) => a + q.workers, 0) + ' workers'}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {window.QUEUES.map(q => {
              const total = q.pending + q.active + q.retry;
              const max = 2000;
              const isCritical = q.pending > 500;
              return (
                <div key={q.name} style={{ display: 'grid', gridTemplateColumns: '100px 1fr 60px 70px', gap: 10, alignItems: 'center' }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                    <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--app-fg1)' }}>{q.name}</span>
                    {isCritical && <span className="sb-dot" style={{ background: 'var(--st-warn-dot)' }}></span>}
                  </div>
                  <window.StackedBar segments={[
                    { value: q.active,  color: '#1E7BFF', label: 'active' },
                    { value: q.pending, color: '#F2A900', label: 'pending' },
                    { value: q.retry,   color: '#7A3CFF', label: 'retry' },
                    { value: Math.max(0, max - total), color: 'transparent', label: 'free' }
                  ]} height={10} />
                  <span className="mono" style={{ fontSize: 11.5, color: 'var(--app-fg2)', textAlign: 'right' }}>{total.toLocaleString()}</span>
                  <span className="mono" style={{ fontSize: 11, color: 'var(--app-fg3)', textAlign: 'right' }}>{q.throughputPerMin}/m</span>
                </div>
              );
            })}
          </div>
          <div style={{ display: 'flex', gap: 12, fontSize: 10.5, color: 'var(--app-fg3)', marginTop: 12, paddingTop: 10, borderTop: '1px solid var(--app-divider)' }}>
            <span><span style={{ display: 'inline-block', width: 8, height: 8, borderRadius: 2, background: '#1E7BFF', marginRight: 4 }}></span>active</span>
            <span><span style={{ display: 'inline-block', width: 8, height: 8, borderRadius: 2, background: '#F2A900', marginRight: 4 }}></span>pending</span>
            <span><span style={{ display: 'inline-block', width: 8, height: 8, borderRadius: 2, background: '#7A3CFF', marginRight: 4 }}></span>retry</span>
          </div>
        </window.SectionCard>

        <window.SectionCard title="Alertas activas" icon="bell-ring" sub={window.ALERTS.filter(a => !a.ack).length + ' sin reconocer'}
          actions={<button className="btn btn-ghost btn-sm">Ver todas <window.Icon name="arrow-right" size={11} /></button>}>
          <div style={{ display: 'flex', flexDirection: 'column' }}>
            {window.ALERTS.slice(0, 5).map(a => (
              <div key={a.id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 0', borderBottom: '1px solid var(--app-divider)' }}>
                <window.StatusBadge tone={a.severity === 'critical' ? 'danger' : a.severity === 'warning' ? 'warn' : 'info'} label={a.severity.toUpperCase()} square />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 12.5, color: 'var(--app-fg1)', fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{a.title}</div>
                  <div className="mono" style={{ fontSize: 10.5, color: 'var(--app-fg3)', marginTop: 2 }}>{a.source}{a.tenant ? ' · ' + a.tenant : ''} · hace {a.age}</div>
                </div>
                {a.ack ? <span className="sb neutral">ack</span> : <button className="btn btn-ghost btn-sm">Ack</button>}
              </div>
            ))}
          </div>
        </window.SectionCard>
      </div>

      <window.SectionCard title="Actividad reciente" icon="activity" sub="últimas 8 operaciones" flush
        actions={<button className="btn btn-ghost btn-sm">Ir a mensajería <window.Icon name="arrow-right" size={11} /></button>}>
        <window.DataTable density="compact" columns={[
          { label: 'Hora', width: 90, render: (r) => <span className="mono" style={{ color: 'var(--app-fg3)' }}>{window.fmtTime(r.ts)}</span> },
          { label: 'Tenant', render: (r) => <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}><window.TenantAvatar tenant={{ id: r.tenant, name: r.tenantName }} size={16} /> {r.tenantName}</span> },
          { label: 'Canal', width: 60, render: (r) => <window.ChannelChip name={r.channel} size="sm" /> },
          { label: 'Dirección', width: 80, render: (r) => <span className="sb neutral sb-square">{r.direction}</span> },
          { label: 'Estado', width: 100, render: (r) => <window.StatusBadge status={r.status} tone={r.tone} /> },
          { label: 'Destinatario', render: (r) => <span className="mono" style={{ color: 'var(--app-fg2)' }}>{r.to || r.from}</span>, faint: true },
          { label: 'Mensaje', render: (r) => <span style={{ color: 'var(--app-fg2)' }} className="truncate" title={r.preview}>{r.preview}</span> },
          { label: 'Latencia', width: 80, numeric: true, render: (r) => <span className="mono">{r.latencyMs}ms</span> }
        ]} rows={recentActivity} />
      </window.SectionCard>
    </div>
  );
}

/* =========================================================================
   MESSAGING
   ========================================================================= */
function PageMessaging({ tenant }) {
  const [messages] = _us(() => window.genMessages(120));
  const [selected, setSelected] = _us(null);
  const [search, setSearch] = _us('');
  const [statusF, setStatusF] = _us('all');
  const [channelF, setChannelF] = _us('all');
  const [directionF, setDirectionF] = _us('all');

  const filtered = _um(() => {
    const ql = search.toLowerCase();
    return messages.filter(m => {
      if (tenant.id !== '*' && m.tenant !== tenant.id) return false;
      if (statusF !== 'all' && m.status !== statusF) return false;
      if (channelF !== 'all' && m.channel !== channelF) return false;
      if (directionF !== 'all' && m.direction !== directionF) return false;
      if (ql) {
        const blob = (m.to + ' ' + m.from + ' ' + m.contactName + ' ' + m.preview + ' ' + m.id + ' ' + m.trace_id + ' ' + (m.template || '')).toLowerCase();
        if (!blob.includes(ql)) return false;
      }
      return true;
    });
  }, [messages, tenant, statusF, channelF, directionF, search]);

  const stats = _um(() => {
    const s = { delivered: 0, sent: 0, queued: 0, failed: 0, read: 0, expired: 0 };
    filtered.forEach(m => { s[m.status] = (s[m.status] || 0) + 1; });
    return s;
  }, [filtered]);

  return (
    <div className="page-wide" style={{ padding: '14px 0 0', height: 'calc(100vh - 52px)', display: 'flex', flexDirection: 'column' }}>
      <div className="page-header" style={{ padding: '0 22px' }}>
        <div>
          <h1 className="page-title">Mensajería</h1>
          <p className="page-sub">Explorador operacional · {filtered.length.toLocaleString()} mensajes · ventana 60m</p>
        </div>
        <div className="page-actions">
          <button className="btn btn-ghost btn-sm"><window.Icon name="calendar" size={12} /> Últimos 60m <window.Icon name="chevron-down" size={11} /></button>
          <button className="btn btn-ghost btn-sm"><window.Icon name="download" size={12} /> Export NDJSON</button>
          <button className="btn btn-secondary btn-sm"><window.Icon name="play" size={12} /> Live tail</button>
        </div>
      </div>

      <div style={{ padding: '0 22px 12px', display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)', gap: 8 }}>
        {[
          { lbl: 'Total', val: filtered.length, tone: 'neutral' },
          { lbl: 'Delivered', val: stats.delivered, tone: 'success' },
          { lbl: 'Sent', val: stats.sent, tone: 'info' },
          { lbl: 'Queued', val: stats.queued, tone: 'warn' },
          { lbl: 'Failed', val: stats.failed, tone: 'danger' },
          { lbl: 'Read', val: stats.read, tone: 'success' }
        ].map((s) => (
          <div key={s.lbl} style={{ padding: '8px 12px', background: 'var(--app-panel)', border: '1px solid var(--app-border)', borderRadius: 8, display: 'flex', flexDirection: 'column', gap: 2 }}>
            <span style={{ fontSize: 10, color: 'var(--app-fg3)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 700 }}>{s.lbl}</span>
            <span style={{ fontSize: 18, fontWeight: 800, color: 'var(--app-fg1)', fontFamily: 'var(--font-display)', fontVariantNumeric: 'tabular-nums' }}>{s.val.toLocaleString()}</span>
          </div>
        ))}
      </div>

      <div className="card" style={{ margin: '0 22px 0', flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
        <window.FilterBar>
          <window.FilterSearch value={search} onChange={setSearch} placeholder="Buscar por trace_id, msg_id, destinatario, plantilla…" />
          <window.FilterChip label="Estado" value={statusF === 'all' ? 'todos' : statusF} active={statusF !== 'all'} onClick={() => setStatusF(statusF === 'all' ? 'failed' : statusF === 'failed' ? 'queued' : statusF === 'queued' ? 'delivered' : 'all')} />
          <window.FilterChip label="Canal" value={channelF === 'all' ? 'todos' : channelF} active={channelF !== 'all'} onClick={() => setChannelF(channelF === 'all' ? 'whatsapp' : channelF === 'whatsapp' ? 'telegram' : channelF === 'telegram' ? 'chatwoot' : 'all')} />
          <window.FilterChip label="Dirección" value={directionF === 'all' ? 'todas' : directionF} active={directionF !== 'all'} onClick={() => setDirectionF(directionF === 'all' ? 'outbound' : directionF === 'outbound' ? 'inbound' : 'all')} />
          <window.FilterChip label="Provider" icon="plus" />
          <window.FilterChip label="Retries" icon="plus" />
          <span className="fb-spacer"></span>
          <button className="fb-time"><window.Icon name="clock" size={11} /> Últimos 60 min</button>
        </window.FilterBar>

        <div style={{ flex: 1, overflow: 'auto', minHeight: 0 }}>
          <window.DataTable density="compact" selectedId={selected && selected.id} onRowClick={setSelected}
            columns={[
              { label: 'Hora', width: 90, render: (r) => <span className="mono" style={{ color: 'var(--app-fg3)' }}>{window.fmtTime(r.ts)}</span> },
              { label: 'Tenant', width: 160, render: (r) => <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}><window.TenantAvatar tenant={{ id: r.tenant, name: r.tenantName }} size={16} /> <span className="truncate" style={{ maxWidth: 120 }}>{r.tenantName}</span></span> },
              { label: 'Canal', width: 56, render: (r) => <window.ChannelChip name={r.channel} size="sm" /> },
              { label: 'Dir', width: 56, render: (r) => <window.Icon name={r.direction === 'outbound' ? 'arrow-up-right' : 'arrow-down-left'} size={12} style={{ color: r.direction === 'outbound' ? 'var(--blaze-orange)' : 'var(--blaze-blue)' }} /> },
              { label: 'Estado', width: 110, render: (r) => <window.StatusBadge status={r.status} tone={r.tone} /> },
              { label: 'Plantilla', width: 180, render: (r) => r.template ? <span className="mono" style={{ fontSize: 11.5, color: 'var(--st-violet-fg)' }}>{r.template}</span> : <span style={{ color: 'var(--app-fg-faint)' }}>—</span> },
              { label: 'Destinatario', width: 130, render: (r) => <span className="mono" style={{ color: 'var(--app-fg2)' }}>{r.to || r.from}</span> },
              { label: 'Contenido', render: (r) => <span style={{ color: 'var(--app-fg2)' }} className="truncate" title={r.preview}>{r.preview}</span> },
              { label: 'Lat.', width: 60, numeric: true, render: (r) => <span className="mono" style={{ color: r.latencyMs > 500 ? 'var(--st-warn-fg)' : 'var(--app-fg2)' }}>{r.latencyMs}ms</span> },
              { label: 'Retries', width: 60, numeric: true, render: (r) => r.retries > 0 ? <span style={{ color: 'var(--st-warn-fg)', fontWeight: 700 }}>{r.retries}</span> : <span style={{ color: 'var(--app-fg-faint)' }}>0</span> },
              { label: 'msg_id', width: 130, render: (r) => <span className="mono" style={{ fontSize: 10.5, color: 'var(--app-fg3)' }}>{r.id}</span> }
            ]} rows={filtered} />
        </div>

        <div className="dt-foot" style={{ borderTop: '1px solid var(--app-border)', flex: '0 0 auto' }}>
          <span>{filtered.length.toLocaleString()} mensajes · página 1 / {Math.ceil(filtered.length / 50)}</span>
          <div className="dt-page">
            <button disabled><window.Icon name="chevrons-left" size={12} /></button>
            <button disabled><window.Icon name="chevron-left" size={12} /></button>
            <span style={{ padding: '0 8px', fontSize: 11 }}>1</span>
            <button><window.Icon name="chevron-right" size={12} /></button>
            <button><window.Icon name="chevrons-right" size={12} /></button>
          </div>
        </div>
      </div>

      {selected && <MessageDetailDrawer msg={selected} onClose={() => setSelected(null)} />}
    </div>
  );
}

function MessageDetailDrawer({ msg, onClose }) {
  const timeline = [
    { ts: msg.ts, label: 'Mensaje creado', meta: 'connector.dispatcher.v3', tone: 'info' },
    { ts: new Date(new Date(msg.ts).getTime() + 80).toISOString(), label: 'Encolado · messaging', meta: 'asynq · weight=4', tone: 'info' },
    { ts: new Date(new Date(msg.ts).getTime() + 142).toISOString(), label: 'Dispatch a Meta Cloud API', meta: 'wabacloud.proxy · POST /messages', tone: 'info' },
    { ts: new Date(new Date(msg.ts).getTime() + msg.latencyMs).toISOString(), label: msg.status === 'failed' ? 'FAILED · rate_limit_exceeded' : msg.status === 'queued' ? 'Esperando aceptación' : 'Aceptado · ' + msg.providerMessageId.slice(0, 16) + '…', meta: 'meta.graph status=' + (msg.status === 'failed' ? '429' : '202') + ' · ' + msg.latencyMs + 'ms', tone: msg.tone },
    ...(msg.status === 'delivered' || msg.status === 'read'
        ? [{ ts: new Date(new Date(msg.ts).getTime() + msg.latencyMs + 1200).toISOString(), label: 'Webhook: ' + msg.status, meta: 'msgr.webhook · message_status', tone: 'success' }]
        : []),
    ...(msg.status === 'read'
        ? [{ ts: new Date(new Date(msg.ts).getTime() + msg.latencyMs + 8400).toISOString(), label: 'Webhook: read', meta: 'msgr.webhook · message_status', tone: 'success' }]
        : []),
    ...(msg.retries > 0
        ? [{ ts: new Date(new Date(msg.ts).getTime() + 30000).toISOString(), label: 'Retry #' + msg.retries + ' encolado', meta: 'backoff exponential · jitter ±20%', tone: 'warn' }]
        : [])
  ];
  return (
    <window.Drawer
      title={msg.template || (msg.direction === 'inbound' ? 'Mensaje entrante' : 'Mensaje saliente')}
      sub={msg.id + ' · trace_id=' + msg.trace_id}
      onClose={onClose}
      actions={<>
        <button className="btn btn-ghost btn-sm"><window.Icon name="copy" size={11} /> Copiar trace</button>
        <button className="btn btn-ghost btn-sm"><window.Icon name="external-link" size={11} /> Ver en logs</button>
        {msg.status === 'failed' && <button className="btn btn-primary btn-sm"><window.Icon name="rotate-cw" size={11} /> Reintentar</button>}
      </>}>
      <div className="drawer-section">
        <div className="drawer-section-title">Resumen</div>
        <dl className="kv">
          <dt>Estado</dt><dd><window.StatusBadge status={msg.status} tone={msg.tone} /></dd>
          <dt>Tenant</dt><dd className="kv-text"><span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}><window.TenantAvatar tenant={{ id: msg.tenant, name: msg.tenantName }} size={16} /> {msg.tenantName}</span></dd>
          <dt>Canal</dt><dd className="kv-text"><span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}><window.ChannelChip name={msg.channel} size="sm" /> {window.CHANNEL_LABEL[msg.channel]}</span></dd>
          <dt>Dirección</dt><dd className="kv-text">{msg.direction}</dd>
          <dt>Provider</dt><dd>{msg.provider}</dd>
          <dt>Provider msg id</dt><dd>{msg.providerMessageId}</dd>
          <dt>{msg.direction === 'outbound' ? 'Destinatario' : 'Remitente'}</dt><dd>{msg.to || msg.from} <span style={{ color: 'var(--app-fg3)', marginLeft: 4 }}>({msg.contactName})</span></dd>
          <dt>Plantilla</dt><dd>{msg.template || <span style={{ color: 'var(--app-fg-faint)' }}>—</span>}</dd>
          <dt>Latencia</dt><dd>{msg.latencyMs}ms</dd>
          <dt>Retries</dt><dd>{msg.retries}</dd>
          <dt>trace_id</dt><dd>{msg.trace_id}</dd>
        </dl>
      </div>
      <div className="drawer-section">
        <div className="drawer-section-title">Timeline</div>
        <div className="tl">
          {timeline.map((t, i) => (
            <div className="tl-row" key={i}>
              <div className={'tl-marker ' + (t.tone || 'info')}>
                <window.Icon name={t.tone === 'success' ? 'check' : t.tone === 'danger' ? 'x' : t.tone === 'warn' ? 'rotate-cw' : 'circle-dot'} size={13} />
              </div>
              <div className="tl-body">
                <div className="tl-title">{t.label}</div>
                <div className="tl-meta"><span>{window.fmtFullTime(t.ts)}</span><span>·</span><span>{t.meta}</span></div>
              </div>
            </div>
          ))}
        </div>
      </div>
      <div className="drawer-section">
        <div className="drawer-section-title">Payload</div>
        <window.JsonViewer data={window.makeSamplePayload(msg)} maxHeight={280} />
      </div>
      <div className="drawer-section">
        <div className="drawer-section-title">Headers</div>
        <window.JsonViewer data={{
          'authorization': 'Bearer EAAJZBs••••••••',
          'content-type': 'application/json',
          'x-blaze-tenant': msg.tenant,
          'x-blaze-trace-id': msg.trace_id,
          'user-agent': 'BlazeConnector/3.4.2 (go1.22)'
        }} />
      </div>
    </window.Drawer>
  );
}

/* =========================================================================
   QUEUES
   ========================================================================= */
function PageQueues({ tenant }) {
  const [tick, setTick] = _us(0);
  _ue(() => { const id = setInterval(() => setTick(t => t + 1), 3000); return () => clearInterval(id); }, []);
  const live = window.QUEUES.map((q, i) => ({ ...q,
    active: Math.max(0, q.active + Math.floor(Math.sin(tick + i) * 8)),
    throughputPerMin: Math.max(0, q.throughputPerMin + Math.floor((Math.random() - 0.5) * 20))
  }));
  const totals = live.reduce((a, q) => ({ active: a.active + q.active, pending: a.pending + q.pending, retry: a.retry + q.retry, failed: a.failed + q.failed, completed: a.completed + q.completed, throughput: a.throughput + q.throughputPerMin, workers: a.workers + q.workers }), { active: 0, pending: 0, retry: 0, failed: 0, completed: 0, throughput: 0, workers: 0 });
  return (
    <div className="page">
      <div className="page-header">
        <div>
          <h1 className="page-title">Colas</h1>
          <p className="page-sub">Asynq · {live.length} colas · {totals.workers} workers · {totals.throughput.toLocaleString()} msgs/m</p>
        </div>
        <div className="page-actions">
          <button className="btn btn-ghost btn-sm"><window.Icon name="server" size={12} /> Workers (48)</button>
          <button className="btn btn-ghost btn-sm"><window.Icon name="refresh-cw" size={12} /> Refrescar</button>
          <button className="btn btn-secondary btn-sm"><window.Icon name="pause" size={12} /> Pausar todas</button>
        </div>
      </div>
      <div className="grid-4" style={{ marginBottom: 12 }}>
        <window.KpiCard label="Active" value={totals.active} delta={2} series={window.DASHBOARD_SERIES.workerActive} color="blue" />
        <window.KpiCard label="Pending" value={totals.pending} delta={isNaN(8.4) ? 0 : 8.4} deltaTone="down" series={window.DASHBOARD_SERIES.queueDepth} color="warn" />
        <window.KpiCard label="Retry" value={totals.retry} delta={0} series={[22,24,28,30,28,26,24,22,20,18,22,24,28,30,32,30,28,26,24,22,20,18,22,24,28,30,32,30,28,26,24,22,20,18,22,24,28,30,32,30,28,26,24,22,20,18,22,24,28,30,32,30,28,26,24,22,20,18,22,24]} color="violet" />
        <window.KpiCard label="Failed (1h)" value={totals.failed} delta={-12} series={[28,24,20,18,22,18,16,14,16,18,14,12,10,12,14,12,10,8,10,12,14,12,10,8,10,12,14,12,10,8,12,14,12,10,8,10,12,10,8,6,8,10,12,10,8,6,4,6,8,10,12,10,8,6,4,6,8,10,12,14]} color="danger" />
      </div>
      <div className="grid-2">
        {live.map(q => {
          const tone = q.pending > 500 ? 'warn' : q.failed > 5 ? 'danger' : 'success';
          return (
            <div key={q.name} className="card">
              <div className="card-head">
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <window.StatusBadge tone={tone} label={tone === 'success' ? 'healthy' : tone === 'warn' ? 'backlog' : 'failing'} />
                  <span style={{ fontSize: 14, fontWeight: 800, fontFamily: 'var(--font-display)', letterSpacing: '-0.01em' }}>{q.name}</span>
                  <span style={{ fontSize: 11, color: 'var(--app-fg3)' }}>weight={q.weight} · workers={q.workers}</span>
                </div>
                <div className="card-actions">
                  <button className="btn btn-ghost btn-sm"><window.Icon name="pause" size={11} /></button>
                  <button className="btn btn-ghost btn-sm"><window.Icon name="settings-2" size={11} /></button>
                </div>
              </div>
              <div className="card-body">
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 0, marginBottom: 12, textAlign: 'left' }}>
                  {[
                    { lbl: 'Active', val: q.active, color: '#1E7BFF' },
                    { lbl: 'Pending', val: q.pending, color: '#F2A900' },
                    { lbl: 'Retry', val: q.retry, color: '#7A3CFF' },
                    { lbl: 'Failed', val: q.failed, color: '#E03E3E' },
                    { lbl: 'p95', val: q.p95 + 'ms', color: 'var(--app-fg2)' }
                  ].map((s, i) => (
                    <div key={i}>
                      <div style={{ fontSize: 10, color: 'var(--app-fg3)', textTransform: 'uppercase', fontWeight: 700, letterSpacing: '0.04em', marginBottom: 2 }}>{s.lbl}</div>
                      <div style={{ fontSize: 18, fontWeight: 800, color: s.color, fontFamily: 'var(--font-display)', fontVariantNumeric: 'tabular-nums' }}>{typeof s.val === 'number' ? s.val.toLocaleString() : s.val}</div>
                    </div>
                  ))}
                </div>
                <div style={{ marginBottom: 8 }}>
                  <window.Sparkline data={window.DASHBOARD_SERIES.msgsPerMin.map(v => Math.max(0, v * (q.weight / 12) + (Math.random() - 0.5) * 40))} color={tone === 'warn' ? 'warn' : tone === 'danger' ? 'danger' : 'blue'} />
                </div>
                <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: 'var(--app-fg3)' }}>
                  <span>Throughput: <span style={{ color: 'var(--app-fg1)', fontWeight: 700 }}>{q.throughputPerMin}/m</span></span>
                  <span>Completed: <span className="mono" style={{ color: 'var(--app-fg2)' }}>{q.completed.toLocaleString()}</span></span>
                </div>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* =========================================================================
   LOGS — streaming, virtualized-ish
   ========================================================================= */
function PageLogs({ tenant, sseEvents }) {
  const [logs, setLogs] = _us(() => window.genLogs(80));
  const [search, setSearch] = _us('');
  const [levelF, setLevelF] = _us('all');
  const [svcF, setSvcF] = _us('all');
  const [expanded, setExpanded] = _us(null);
  const [paused, setPaused] = _us(false);
  const scrollRef = _ur(null);

  _ue(() => {
    if (paused) return;
    const id = setInterval(() => {
      const tpl = window.randomFrom(window.ERROR_TEMPLATES);
      const tnt = window.randomFrom(window.TENANTS);
      const newLog = {
        id: 'log_' + window.randHex(10),
        ts: new Date().toISOString(),
        level: tpl.level,
        svc: tpl.svc,
        tenant: tnt.id, tenantName: tnt.name,
        msg: tpl.msg, code: tpl.code,
        trace_id: window.TRACE_PREFIX(), span_id: window.randHex(8),
        attrs: { env: 'production', region: 'sdq-1', host: 'connector-worker-' + (Math.floor(Math.random() * 6) + 1), request_id: 'req_' + window.randHex(12), user_agent: 'BlazeConnector/3.4.2 (go1.22)' },
        isNew: true
      };
      setLogs(prev => [newLog, ...prev].slice(0, 200));
    }, 2200 + Math.random() * 2000);
    return () => clearInterval(id);
  }, [paused]);

  const filtered = _um(() => {
    const ql = search.toLowerCase();
    return logs.filter(l => {
      if (tenant.id !== '*' && l.tenant !== tenant.id) return false;
      if (levelF !== 'all' && l.level !== levelF) return false;
      if (svcF !== 'all' && l.svc !== svcF) return false;
      if (ql) {
        const blob = (l.msg + ' ' + l.svc + ' ' + l.tenantName + ' ' + l.trace_id + ' ' + (l.code || '')).toLowerCase();
        if (!blob.includes(ql)) return false;
      }
      return true;
    });
  }, [logs, search, levelF, svcF, tenant]);

  const distrib = _um(() => {
    const out = { error: 0, warn: 0, info: 0, debug: 0 };
    logs.forEach(l => { out[l.level] = (out[l.level] || 0) + 1; });
    return out;
  }, [logs]);

  return (
    <div className="page-wide" style={{ padding: '14px 0 0', height: 'calc(100vh - 52px)', display: 'flex', flexDirection: 'column' }}>
      <div className="page-header" style={{ padding: '0 22px' }}>
        <div>
          <h1 className="page-title">Logs</h1>
          <p className="page-sub">Stream estructurado · {filtered.length} / {logs.length} eventos · {paused ? 'pausado' : 'live'}</p>
        </div>
        <div className="page-actions">
          <span style={{ display: 'flex', gap: 10, fontSize: 11, color: 'var(--app-fg3)', alignItems: 'center', marginRight: 8 }}>
            <span><span className="log-level l-error">ERROR</span> <span className="mono">{distrib.error}</span></span>
            <span><span className="log-level l-warn">WARN</span> <span className="mono">{distrib.warn}</span></span>
            <span><span className="log-level l-info">INFO</span> <span className="mono">{distrib.info}</span></span>
            <span><span className="log-level l-debug">DEBUG</span> <span className="mono">{distrib.debug}</span></span>
          </span>
          <button className="btn btn-ghost btn-sm" onClick={() => setPaused(!paused)}>
            <window.Icon name={paused ? 'play' : 'pause'} size={12} />
            {paused ? 'Reanudar' : 'Pausar'}
          </button>
          <button className="btn btn-ghost btn-sm"><window.Icon name="download" size={12} /> Export</button>
        </div>
      </div>

      <div style={{ padding: '0 22px 8px' }}>
        <window.AreaChart data={window.DASHBOARD_SERIES.inbound} color="teal" height={56} yAxis={false} />
      </div>

      <div className="card" style={{ margin: '0 22px', flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
        <window.FilterBar>
          <window.FilterSearch value={search} onChange={setSearch} placeholder='Buscar texto, trace_id, code… ej. svc:msgr.dispatch level:error' />
          <window.FilterChip label="Nivel" value={levelF === 'all' ? 'todos' : levelF.toUpperCase()} active={levelF !== 'all'} onClick={() => setLevelF(levelF === 'all' ? 'error' : levelF === 'error' ? 'warn' : levelF === 'warn' ? 'info' : 'all')} />
          <window.FilterChip label="Servicio" value={svcF === 'all' ? 'todos' : svcF} active={svcF !== 'all'} onClick={() => setSvcF(svcF === 'all' ? 'msgr.dispatch' : svcF === 'msgr.dispatch' ? 'pagos.callback' : 'all')} />
          <window.FilterChip label="Host" icon="plus" />
          <window.FilterChip label="trace_id" icon="plus" />
          <span className="fb-spacer"></span>
          <button className="fb-time"><window.Icon name="clock" size={11} /> Últimos 30 min</button>
          <button className="btn btn-ghost btn-sm" style={{ borderColor: 'var(--app-border)' }}><window.Icon name="bookmark" size={11} /> Guardar vista</button>
        </window.FilterBar>

        <div style={{ flex: 1, overflow: 'auto', minHeight: 0, background: 'var(--app-panel)' }} ref={scrollRef}>
          <div className="log-line" style={{ position: 'sticky', top: 0, background: 'var(--app-panel-2)', borderBottom: '1px solid var(--app-border)', zIndex: 1, fontSize: 10, color: 'var(--app-fg3)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 700, fontFamily: 'var(--font-sans)', padding: '6px 12px' }}>
            <span>timestamp</span><span>level</span><span>service</span><span>tenant</span><span>message</span>
          </div>
          {filtered.length === 0
            ? <window.EmptyState icon="terminal" title="Sin eventos" sub="Ajusta los filtros o reanuda el stream." />
            : filtered.map((l) => (
              <React.Fragment key={l.id}>
                <div className={'log-line ' + (l.isNew ? 'is-new' : '') + (expanded === l.id ? ' is-expanded' : '')} onClick={() => setExpanded(expanded === l.id ? null : l.id)}>
                  <span className="log-time">{l.ts.slice(11, 23)}</span>
                  <span className={'log-level l-' + l.level}>{l.level}</span>
                  <span className="log-svc">{l.svc}</span>
                  <span className="log-tenant">{l.tenantName}</span>
                  <span className="log-msg">{l.msg} {l.code && <span style={{ color: 'var(--app-fg-faint)' }}>· code={l.code}</span>}</span>
                </div>
                {expanded === l.id && (
                  <div className="log-expanded">
                    <window.JsonViewer data={{
                      timestamp: l.ts, level: l.level, service: l.svc,
                      message: l.msg, code: l.code,
                      tenant_id: l.tenant, trace_id: l.trace_id, span_id: l.span_id,
                      attributes: l.attrs
                    }} maxHeight={260} />
                    <div style={{ display: 'flex', gap: 6, marginTop: 8 }}>
                      <button className="btn btn-ghost btn-sm"><window.Icon name="copy" size={11} /> Copiar trace_id</button>
                      <button className="btn btn-ghost btn-sm"><window.Icon name="filter" size={11} /> Filtrar por trace</button>
                      <button className="btn btn-ghost btn-sm"><window.Icon name="external-link" size={11} /> Ver mensaje relacionado</button>
                    </div>
                  </div>
                )}
              </React.Fragment>
            ))}
        </div>
      </div>
    </div>
  );
}

/* =========================================================================
   ALERTAS
   ========================================================================= */
function PageAlerts({ tenant }) {
  const [filter, setFilter] = _us('active');
  const [search, setSearch] = _us('');
  const rows = _um(() => {
    const ql = search.toLowerCase();
    return window.ALERTS.filter(a => {
      if (tenant.id !== '*' && a.tenant && a.tenant !== tenant.id) return false;
      if (filter === 'active' && a.ack) return false;
      if (filter === 'critical' && a.severity !== 'critical') return false;
      if (filter === 'ack' && !a.ack) return false;
      if (ql && !(a.title + ' ' + a.source).toLowerCase().includes(ql)) return false;
      return true;
    });
  }, [filter, tenant, search]);

  return (
    <div className="page">
      <div className="page-header">
        <div>
          <h1 className="page-title">Alertas</h1>
          <p className="page-sub">{window.ALERTS.filter(a => !a.ack).length} sin reconocer · {window.ALERTS.length} totales · políticas activas: 24</p>
        </div>
        <div className="page-actions">
          <button className="btn btn-ghost btn-sm"><window.Icon name="settings-2" size={12} /> Políticas</button>
          <button className="btn btn-ghost btn-sm"><window.Icon name="bell-off" size={12} /> Silenciar</button>
          <button className="btn btn-secondary btn-sm"><window.Icon name="check-check" size={12} /> Reconocer todas</button>
        </div>
      </div>

      <div className="grid-4" style={{ marginBottom: 12 }}>
        <window.KpiCard label="Críticas" value={window.ALERTS.filter(a => a.severity === 'critical').length} color="danger" foot={window.ALERTS.filter(a => a.severity === 'critical' && !a.ack).length + ' sin ack'} />
        <window.KpiCard label="Warnings" value={window.ALERTS.filter(a => a.severity === 'warning').length} color="warn" foot={window.ALERTS.filter(a => a.severity === 'warning' && !a.ack).length + ' sin ack'} />
        <window.KpiCard label="Info" value={window.ALERTS.filter(a => a.severity === 'info').length} color="blue" />
        <window.KpiCard label="MTTA promedio" value="4m 12s" color="violet" foot="↓ 38% vs 30 días" />
      </div>

      <div className="card">
        <window.FilterBar>
          <window.FilterSearch value={search} onChange={setSearch} placeholder="Buscar título, fuente, runbook…" />
          {['active','critical','ack','all'].map(f => (
            <button key={f} className={'fb-chip ' + (filter === f ? 'is-active' : '')} onClick={() => setFilter(f)}>{f === 'active' ? 'Activas' : f === 'critical' ? 'Críticas' : f === 'ack' ? 'Reconocidas' : 'Todas'}</button>
          ))}
        </window.FilterBar>
        <window.DataTable density="cozy" columns={[
          { label: 'Severidad', width: 110, render: (a) => <window.StatusBadge tone={a.severity === 'critical' ? 'danger' : a.severity === 'warning' ? 'warn' : 'info'} label={a.severity.toUpperCase()} /> },
          { label: 'Título', render: (a) => <div><div style={{ fontWeight: 600, color: 'var(--app-fg1)' }}>{a.title}</div><div className="mono" style={{ fontSize: 10.5, color: 'var(--app-fg3)', marginTop: 2 }}>{a.source}</div></div> },
          { label: 'Tenant', width: 160, render: (a) => a.tenant ? <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}><window.TenantAvatar tenant={{ id: a.tenant, name: (window.TENANTS.find(t => t.id === a.tenant) || {}).name || a.tenant }} size={16} /> {(window.TENANTS.find(t => t.id === a.tenant) || {}).name || a.tenant}</span> : <span style={{ color: 'var(--app-fg-faint)' }}>global</span> },
          { label: 'Disparo', width: 140, render: (a) => <span><span className="mono" style={{ fontSize: 11.5 }}>{window.fmtTime(a.fired)}</span> <span style={{ color: 'var(--app-fg3)', fontSize: 11 }}>· {a.age}</span></span> },
          { label: 'Estado', width: 100, render: (a) => a.ack ? <window.StatusBadge tone="neutral" label="reconocida" /> : <window.StatusBadge tone="warn" label="abierta" /> },
          { label: '', width: 200, render: (a) => <div style={{ display: 'flex', gap: 4, justifyContent: 'flex-end' }}>
            {a.runbook && <button className="btn btn-ghost btn-sm">Runbook</button>}
            {!a.ack && <button className="btn btn-secondary btn-sm">Reconocer</button>}
            <button className="btn btn-ghost btn-sm btn-icon-only"><window.Icon name="more-horizontal" size={13} /></button>
          </div> }
        ]} rows={rows} />
      </div>
    </div>
  );
}

Object.assign(window, { PageDashboard, PageMessaging, PageQueues, PageLogs, PageAlerts });
