/* admin_users_components.jsx — sub-componentes reutilizáveis para Admin · Users.
   Sem state global. Cada componente é puro/controlled.

   Expostos em window:
     AdminUsers.Avatar
     AdminUsers.EmpresaTags          — tag única ou "N empresas (FBS, DDI...)" com tooltip
     AdminUsers.RelativeTime         — "há 4h" + tooltip absoluto
     AdminUsers.TipoBadge            — pill colorido por tipo
     AdminUsers.PortalBadge          — Activo verde / Sem acesso cinza
     AdminUsers.SSOBadge             — ✓ se portal_activo + tooltip
     AdminUsers.ApolloBadge          — chip
     AdminUsers.SectionHeader
     AdminUsers.FieldRow             — label esq · valor dir · edit inline opcional
     AdminUsers.EmpresaJunctionTable — tabela editável colaborador_empresa
     AdminUsers.PermissoesEditor     — editor RBAC (collapsed por default)
     AdminUsers.ModosAcessoEditor    — checkboxes dev/interno/clientes/board
     AdminUsers.PortalAccessCard
     AdminUsers.AuditLogList
     AdminUsers.SessionsList
     AdminUsers.ConversasList
*/

const D = window.AdminUsersData;

// ════════════════════════════════════════════════════════════════
// Helpers
// ════════════════════════════════════════════════════════════════
const fmtAbs = (iso) => {
  if (!iso) return '—';
  const d = new Date(iso);
  return d.toLocaleString('pt-PT', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' });
};
const fmtRel = (iso) => {
  if (!iso) return '—';
  const diff = Date.now() - new Date(iso).getTime();
  const m = Math.floor(diff / 60_000);
  if (m < 1)   return 'agora';
  if (m < 60)  return `há ${m}m`;
  const h = Math.floor(m / 60);
  if (h < 24)  return `há ${h}h`;
  const d = Math.floor(h / 24);
  if (d < 30)  return `há ${d}d`;
  const mo = Math.floor(d / 30);
  if (mo < 12) return `há ${mo}m`;
  const y = Math.floor(d / 365);
  return `há ${y}a`;
};
const initials = (nome) => {
  if (!nome) return '··';
  return nome.split(' ').filter(Boolean).slice(0, 2).map(s => s[0]?.toUpperCase()).join('') || '··';
};

// ════════════════════════════════════════════════════════════════
// Avatar — colored bubble com iniciais. Se foto_url existir, mock photo (gradient).
// ════════════════════════════════════════════════════════════════
const Avatar = ({ user, size = 32 }) => {
  const has = !!user?.foto_url;
  const ini = initials(user?.nome_apresentar || user?.nome_completo);
  // Hash-based hue para diversificar
  const hash = [...(user?.nome_completo || 'X')].reduce((a, c) => a + c.charCodeAt(0), 0);
  const hue = hash % 360;
  const bg = has
    ? `linear-gradient(135deg, oklch(0.65 0.13 ${hue}), oklch(0.45 0.16 ${(hue + 40) % 360}))`
    : `oklch(0.30 0.04 ${hue})`;
  return (
    <div style={{
      width: size, height: size, borderRadius: size <= 28 ? 6 : 8,
      background: bg,
      display: 'grid', placeItems: 'center', flexShrink: 0,
      color: has ? '#fff' : 'var(--text)',
      fontSize: size * 0.40, fontWeight: 600, letterSpacing: '0.02em',
      fontFamily: 'var(--font-display)',
      textTransform: 'uppercase',
      border: has ? '0' : '1px solid var(--border)',
    }}>{ini}</div>
  );
};

// ════════════════════════════════════════════════════════════════
// Tooltip simples (top-right) on-hover
// ════════════════════════════════════════════════════════════════
const Tooltip = ({ children, text, side = 'top' }) => {
  const [hover, setHover] = React.useState(false);
  return (
    <span
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{ position: 'relative', display: 'inline-flex' }}
    >
      {children}
      {hover && text && (
        <span style={{
          position: 'absolute',
          [side === 'top' ? 'bottom' : 'top']: 'calc(100% + 6px)',
          left: '50%', transform: 'translateX(-50%)',
          background: 'var(--bg-elev)',
          border: '1px solid var(--border)',
          borderRadius: 6, padding: '6px 10px',
          fontSize: 11, whiteSpace: 'pre-line', maxWidth: 280,
          boxShadow: 'var(--shadow-md)', color: 'var(--text)',
          zIndex: 1500, pointerEvents: 'none', fontFamily: 'var(--font-sans)',
        }}>{text}</span>
      )}
    </span>
  );
};

// ════════════════════════════════════════════════════════════════
// EmpresaTags — uma empresa = nome curto; várias = "3 empresas" + tooltip
// ════════════════════════════════════════════════════════════════
const EmpresaTags = ({ user, mode = 'compact' }) => {
  const list = user?.empresas || [];
  if (!list.length) return <span style={{ color: 'var(--text-dim)' }}>—</span>;
  if (list.length === 1) {
    const e = D.getEmpresa(list[0].id);
    return (
      <span style={{ fontSize: 12, color: 'var(--text)' }}>{e?.nome || list[0].id}</span>
    );
  }
  const primary = list.find(x => x.is_primary) || list[0];
  const otherShorts = list.filter(x => x.id !== primary.id).slice(0, 3).map(x => D.getEmpresa(x.id)?.short || x.id);
  const more = list.length - 1 - otherShorts.length;
  const summaryText = list.map(x => {
    const e = D.getEmpresa(x.id);
    return `${x.is_primary ? '● ' : '  '}${e?.nome || x.id} — ${x.cargo || ''}`;
  }).join('\n');
  return (
    <Tooltip text={summaryText}>
      <span style={{
        display: 'inline-flex', alignItems: 'center', gap: 6,
        fontSize: 12, color: 'var(--text)',
        cursor: 'help', borderBottom: '1px dashed var(--border)',
      }}>
        <strong style={{ fontWeight: 600 }}>{list.length}</strong>
        <span style={{ color: 'var(--text-muted)' }}>empresas ·</span>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10.5, color: 'var(--text-muted)' }}>
          {[D.getEmpresa(primary.id)?.short, ...otherShorts].filter(Boolean).join(', ')}{more > 0 ? `, +${more}` : ''}
        </span>
      </span>
    </Tooltip>
  );
};

// ════════════════════════════════════════════════════════════════
// RelativeTime
// ════════════════════════════════════════════════════════════════
const RelativeTime = ({ iso }) => {
  if (!iso) return <span style={{ color: 'var(--text-dim)' }}>—</span>;
  return (
    <Tooltip text={fmtAbs(iso)}>
      <span style={{ fontSize: 12, color: 'var(--text)', cursor: 'help' }}>{fmtRel(iso)}</span>
    </Tooltip>
  );
};

// ════════════════════════════════════════════════════════════════
// Badges
// ════════════════════════════════════════════════════════════════
const TipoBadge = ({ tipo }) => {
  const t = D.getTipo(tipo);
  if (!t) return <span style={{ color: 'var(--text-dim)' }}>—</span>;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', padding: '2px 8px',
      borderRadius: 999, fontSize: 10.5, fontWeight: 600,
      letterSpacing: '0.04em', textTransform: 'uppercase',
      background: `color-mix(in oklch, ${t.color} 18%, transparent)`,
      border: `1px solid color-mix(in oklch, ${t.color} 35%, transparent)`,
      color: t.color, fontFamily: 'var(--font-display)',
    }}>{t.label}</span>
  );
};

const PortalBadge = ({ activo }) => activo ? (
  <span style={{
    display: 'inline-flex', alignItems: 'center', gap: 4,
    padding: '2px 8px', borderRadius: 999, fontSize: 10.5,
    background: 'color-mix(in oklch, var(--ok) 16%, transparent)',
    border: '1px solid color-mix(in oklch, var(--ok) 35%, transparent)',
    color: 'var(--ok)', fontFamily: 'var(--font-mono)',
  }}>● Activo</span>
) : (
  <span style={{
    display: 'inline-flex', alignItems: 'center', gap: 4,
    padding: '2px 8px', borderRadius: 999, fontSize: 10.5,
    background: 'var(--bg-sunken)', border: '1px solid var(--border)',
    color: 'var(--text-dim)', fontFamily: 'var(--font-mono)',
  }}>○ Sem acesso</span>
);

const SSOBadge = ({ activo }) => (
  <Tooltip text={'Sincronizado com Microsoft 365 SSO.\n2FA gerido pelo Microsoft Authenticator.'}>
    <span style={{
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      width: 18, height: 18, borderRadius: 4,
      fontSize: 11, fontFamily: 'var(--font-mono)',
      cursor: 'help',
      background: activo ? 'color-mix(in oklch, var(--ok) 16%, transparent)' : 'var(--bg-sunken)',
      border: `1px solid ${activo ? 'color-mix(in oklch, var(--ok) 35%, transparent)' : 'var(--border)'}`,
      color: activo ? 'var(--ok)' : 'var(--text-dim)',
    }}>{activo ? '✓' : '✗'}</span>
  </Tooltip>
);

const ApolloBadge = ({ enriched }) => enriched ? (
  <Tooltip text="Enriquecido via Apollo.io">
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 4,
      padding: '1px 6px', borderRadius: 4, fontSize: 9.5,
      background: 'color-mix(in oklch, var(--ai-500) 14%, transparent)',
      color: 'var(--ai-500)', fontFamily: 'var(--font-mono)',
      letterSpacing: '0.04em',
    }}>APOLLO ✓</span>
  </Tooltip>
) : (
  <span style={{
    display: 'inline-flex', alignItems: 'center', padding: '1px 6px',
    borderRadius: 4, fontSize: 9.5, background: 'var(--bg-sunken)',
    color: 'var(--text-dim)', fontFamily: 'var(--font-mono)',
  }}>— pendente</span>
);

// ════════════════════════════════════════════════════════════════
// SectionHeader (drawer)
// ════════════════════════════════════════════════════════════════
const SectionHeader = ({ title, subtitle, action }) => (
  <div style={{
    display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between',
    marginBottom: 12, paddingBottom: 8, borderBottom: '1px solid var(--border)',
  }}>
    <div>
      <div className="font-display" style={{
        fontSize: 11, fontWeight: 600, letterSpacing: '0.12em',
        textTransform: 'uppercase', color: 'var(--text-muted)',
      }}>{title}</div>
      {subtitle && <div style={{ fontSize: 11, color: 'var(--text-dim)', marginTop: 2 }}>{subtitle}</div>}
    </div>
    {action}
  </div>
);

// ════════════════════════════════════════════════════════════════
// FieldRow — label esq · value dir · edit inline (lápis on hover)
// ════════════════════════════════════════════════════════════════
const FieldRow = ({ label, value, onChange, editable = true, type = 'text', source, options, multiline, badge }) => {
  const [editing, setEditing] = React.useState(false);
  const [draft, setDraft]     = React.useState(value || '');
  const [hover, setHover]     = React.useState(false);
  React.useEffect(() => setDraft(value || ''), [value]);

  const commit = () => {
    setEditing(false);
    if (draft !== (value || '') && onChange) onChange(draft);
  };
  const cancel = () => { setDraft(value || ''); setEditing(false); };

  return (
    <div
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        display: 'grid', gridTemplateColumns: '180px 1fr', gap: 16,
        padding: '10px 0', borderBottom: '1px dashed var(--border-subtle, var(--border))',
        alignItems: multiline ? 'flex-start' : 'center',
      }}
    >
      <div style={{
        fontSize: 11, color: 'var(--text-muted)',
        fontFamily: 'var(--font-display)', letterSpacing: '0.04em',
        textTransform: 'uppercase', fontWeight: 500,
        display: 'flex', alignItems: 'center', gap: 6,
      }}>
        <span>{label}</span>
        {source && <span style={{
          padding: '0 6px', fontSize: 8.5, borderRadius: 3,
          background: 'var(--bg-sunken)', color: 'var(--text-dim)',
          fontFamily: 'var(--font-mono)', letterSpacing: '0.06em',
        }}>{source}</span>}
      </div>

      {editing ? (
        <div style={{ display: 'flex', gap: 6 }}>
          {type === 'select' ? (
            <select
              autoFocus value={draft}
              onChange={e => setDraft(e.target.value)}
              onBlur={commit}
              onKeyDown={e => { if (e.key === 'Enter') commit(); if (e.key === 'Escape') cancel(); }}
              style={_fieldInputStyle(false)}
            >
              {(options || []).map(o => typeof o === 'string'
                ? <option key={o} value={o}>{o}</option>
                : <option key={o.id} value={o.id}>{o.label}</option>)}
            </select>
          ) : multiline ? (
            <textarea
              autoFocus value={draft} rows={4}
              onChange={e => setDraft(e.target.value)}
              onBlur={commit}
              onKeyDown={e => { if (e.key === 'Escape') cancel(); }}
              style={{ ..._fieldInputStyle(true), resize: 'vertical', fontFamily: 'var(--font-sans)' }}
            />
          ) : (
            <input
              autoFocus type={type} value={draft}
              onChange={e => setDraft(e.target.value)}
              onBlur={commit}
              onKeyDown={e => { if (e.key === 'Enter') commit(); if (e.key === 'Escape') cancel(); }}
              style={_fieldInputStyle(false)}
            />
          )}
        </div>
      ) : (
        <div
          onClick={() => editable && onChange && setEditing(true)}
          style={{
            fontSize: 13, color: value ? 'var(--text)' : 'var(--text-dim)',
            cursor: editable && onChange ? 'text' : 'default',
            display: 'flex', alignItems: multiline ? 'flex-start' : 'center', gap: 8,
            minHeight: 22, whiteSpace: multiline ? 'pre-wrap' : 'normal',
            lineHeight: multiline ? 1.5 : 1.3,
          }}
        >
          <span style={{ flex: 1 }}>{value || <em style={{ color: 'var(--text-dim)', fontStyle: 'normal' }}>—</em>}</span>
          {badge}
          {editable && onChange && hover && (
            <Icon name="more" size={12} style={{ color: 'var(--text-dim)', opacity: 0.6 }} />
          )}
        </div>
      )}
    </div>
  );
};
// Renomeado para evitar colisão com inputStyle (objecto) em admin_users_modals.jsx
const _fieldInputStyle = (multi) => ({
  flex: 1, padding: multi ? '6px 8px' : '4px 8px',
  background: 'var(--bg-elev)', border: '1px solid var(--ai-500)',
  borderRadius: 4, fontSize: 13, color: 'var(--text)',
  outline: 'none', fontFamily: 'var(--font-sans)',
});

// ════════════════════════════════════════════════════════════════
// EmpresaJunctionTable — tabela editável colaborador_empresa
// ════════════════════════════════════════════════════════════════
const EmpresaJunctionTable = ({ user, onChange, currentUserTipo }) => {
  const list = user?.empresas || [];
  const visible = D.visibleEmpresas(currentUserTipo);
  const setPrimary = (idx) => onChange(list.map((x, i) => ({ ...x, is_primary: i === idx })));
  const update = (idx, patch) => onChange(list.map((x, i) => i === idx ? { ...x, ...patch } : x));
  const remove = (idx) => onChange(list.filter((_, i) => i !== idx));
  const add = () => {
    const taken = new Set(list.map(x => x.id));
    const free = visible.find(e => !taken.has(e.id));
    if (!free) return;
    onChange([...list, { id: free.id, cargo: '', direccao: '', departamento: '', is_primary: list.length === 0 }]);
  };

  return (
    <div style={{ marginTop: 4 }}>
      <div style={{
        display: 'grid',
        gridTemplateColumns: '180px 1fr 1fr 60px 30px',
        gap: 8, padding: '6px 8px',
        fontSize: 10, color: 'var(--text-muted)',
        fontFamily: 'var(--font-display)', letterSpacing: '0.08em',
        textTransform: 'uppercase', fontWeight: 600,
        borderBottom: '1px solid var(--border)',
      }}>
        <div>Empresa</div>
        <div>Cargo</div>
        <div>Direcção · Depto</div>
        <div style={{ textAlign: 'center' }}>Primária</div>
        <div></div>
      </div>
      {list.map((row, idx) => {
        const e = D.getEmpresa(row.id);
        return (
          <div key={idx} style={{
            display: 'grid',
            gridTemplateColumns: '180px 1fr 1fr 60px 30px',
            gap: 8, padding: '8px',
            borderBottom: '1px solid var(--border)',
            alignItems: 'center', fontSize: 12,
          }}>
            <select
              value={row.id}
              onChange={ev => update(idx, { id: ev.target.value })}
              style={cellInput()}
            >
              {visible.map(emp => <option key={emp.id} value={emp.id}>{emp.nome}</option>)}
            </select>
            <input
              type="text" value={row.cargo || ''}
              placeholder="Cargo"
              onChange={ev => update(idx, { cargo: ev.target.value })}
              style={cellInput()}
            />
            <input
              type="text"
              value={[row.direccao, row.departamento].filter(Boolean).join(' · ') || ''}
              placeholder="Direcção · Depto"
              onChange={ev => {
                const parts = ev.target.value.split('·').map(s => s.trim());
                update(idx, { direccao: parts[0] || '', departamento: parts[1] || '' });
              }}
              style={cellInput()}
            />
            <div style={{ display: 'flex', justifyContent: 'center' }}>
              <button
                onClick={() => setPrimary(idx)}
                title={row.is_primary ? 'Empresa primária' : 'Definir como primária'}
                style={{
                  width: 18, height: 18, borderRadius: '50%',
                  border: `2px solid ${row.is_primary ? 'var(--ai-500)' : 'var(--border)'}`,
                  background: row.is_primary ? 'var(--ai-500)' : 'transparent',
                  cursor: 'pointer', padding: 0,
                  display: 'grid', placeItems: 'center',
                }}
              >
                {row.is_primary && <span style={{ width: 6, height: 6, borderRadius: '50%', background: '#fff' }} />}
              </button>
            </div>
            <button
              onClick={() => remove(idx)}
              title="Remover empresa"
              className="btn btn-ghost btn-sm"
              style={{ padding: 4, justifyContent: 'center' }}
            ><Icon name="close" size={12} /></button>
          </div>
        );
      })}
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 8px' }}>
        <button onClick={add} className="btn btn-sm">
          <Icon name="plus" size={12} />
          Adicionar empresa
        </button>
        <Tooltip text="A empresa primária é a que aparece no header do utilizador. As outras são acessos adicionais." side="top">
          <span style={{ fontSize: 10.5, color: 'var(--text-dim)', display: 'inline-flex', alignItems: 'center', gap: 4 }}>
            <Icon name="circle" size={10} style={{ opacity: 0.4 }} />
            sobre primária
          </span>
        </Tooltip>
      </div>
    </div>
  );
};
const cellInput = () => ({
  padding: '5px 7px', background: 'var(--bg-sunken)',
  border: '1px solid transparent', borderRadius: 4,
  fontSize: 12, color: 'var(--text)', outline: 'none',
  fontFamily: 'var(--font-sans)', width: '100%',
});

// ════════════════════════════════════════════════════════════════
// PermissoesEditor — collapsed por default, com badge "Override"
// ════════════════════════════════════════════════════════════════
const PermissoesEditor = ({ user, onChange, expanded, setExpanded }) => {
  const def = D.TIPOS_DEFAULTS[user.tipo_utilizador] || { dados: [], marcas: [], skills: [], features: [], modos: [] };
  const cur = user.permissoes || def;
  const isOverride = JSON.stringify({...cur, modos:undefined}) !== JSON.stringify({...def, modos: undefined});

  const toggle = (group, key) => {
    const set = new Set(cur[group] || []);
    if (set.has(key)) set.delete(key); else set.add(key);
    onChange({ ...cur, [group]: [...set] });
  };
  const revert = () => onChange({ ...def });

  // Resumos
  const counts = {
    dados:    `${(cur.dados || []).length}/${D.DADOS_KEYS.length}`,
    marcas:   `${(cur.marcas || []).length}/${D.MARCAS_KEYS.length}`,
    skills:   `${(cur.skills || []).length}/${D.SKILLS_KEYS.length}`,
    features: `${(cur.features || []).length}/${D.FEATURES_KEYS.length}`,
  };

  return (
    <div style={{
      border: '1px solid var(--border)', borderRadius: 8,
      background: 'var(--bg-sunken)', overflow: 'hidden',
    }}>
      <div style={{ padding: '12px 14px' }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
          <div className="font-display" style={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--text-muted)' }}>
            Resumo permissões
          </div>
          {isOverride && (
            <span style={{
              padding: '2px 8px', borderRadius: 999, fontSize: 9.5,
              background: 'color-mix(in oklch, var(--warn) 18%, transparent)',
              border: '1px solid color-mix(in oklch, var(--warn) 35%, transparent)',
              color: 'var(--warn)',
              fontFamily: 'var(--font-mono)', letterSpacing: '0.06em',
            }}>OVERRIDE PONTUAL</span>
          )}
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '6px 18px', fontSize: 12 }}>
          <SummaryRow label="Dados"    count={counts.dados} />
          <SummaryRow label="Marcas"   count={counts.marcas} />
          <SummaryRow label="Skills"   count={counts.skills} />
          <SummaryRow label="Features" count={counts.features} />
        </div>

        <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
          <button
            onClick={() => setExpanded(!expanded)}
            className="btn btn-sm"
            style={{ flex: 1 }}
          >
            <Icon name={expanded ? 'arrowUp' : 'arrowDown'} size={12} />
            {expanded ? 'Esconder editor' : 'Personalizar permissões'}
          </button>
          {isOverride && (
            <button onClick={revert} className="btn btn-sm btn-ghost">
              <Icon name="refresh" size={12} />
              Reverter para defaults
            </button>
          )}
        </div>
      </div>

      {expanded && (
        <div style={{ padding: '14px', borderTop: '1px solid var(--border)' }}>
          <PermGroup title="Dados"    keys={D.DADOS_KEYS}    selected={cur.dados}    onToggle={(k) => toggle('dados', k)}    cols={2} />
          <PermGroup title="Marcas"   keys={D.MARCAS_KEYS}   selected={cur.marcas}   onToggle={(k) => toggle('marcas', k)}   cols={3} />
          <PermGroup title="Skills"   keys={D.SKILLS_KEYS}   selected={cur.skills}   onToggle={(k) => toggle('skills', k)}   cols={3} />
          <PermGroup title="Features" keys={D.FEATURES_KEYS} selected={cur.features} onToggle={(k) => toggle('features', k)} cols={3} last />
        </div>
      )}
    </div>
  );
};
const SummaryRow = ({ label, count }) => (
  <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8 }}>
    <span style={{ color: 'var(--text-muted)' }}>{label}:</span>
    <span style={{ fontFamily: 'var(--font-mono)', color: 'var(--text)' }}>{count}</span>
  </div>
);
const PermGroup = ({ title, keys, selected, onToggle, cols = 3, last }) => {
  const sel = new Set(selected || []);
  return (
    <div style={{ marginBottom: last ? 0 : 14 }}>
      <div className="font-display" style={{
        fontSize: 10, fontWeight: 600, letterSpacing: '0.12em',
        textTransform: 'uppercase', color: 'var(--text-dim)', marginBottom: 6,
      }}>{title}</div>
      <div style={{ display: 'grid', gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: '4px 10px' }}>
        {keys.map(k => (
          <label key={k} style={{
            display: 'flex', alignItems: 'center', gap: 6,
            fontSize: 11.5, fontFamily: 'var(--font-mono)',
            cursor: 'pointer', padding: '3px 0',
          }}>
            <input
              type="checkbox" checked={sel.has(k)}
              onChange={() => onToggle(k)}
              style={{ accentColor: 'var(--ai-500)' }}
            />
            <span style={{ color: sel.has(k) ? 'var(--text)' : 'var(--text-dim)' }}>{k}</span>
          </label>
        ))}
      </div>
    </div>
  );
};

// ════════════════════════════════════════════════════════════════
// ModosAcessoEditor
// ════════════════════════════════════════════════════════════════
const ModosAcessoEditor = ({ value, onChange }) => {
  const sel = new Set(value || []);
  const toggle = (k) => {
    const next = new Set(sel);
    if (next.has(k)) next.delete(k); else next.add(k);
    onChange([...next]);
  };
  const items = [
    { id: 'dev',      label: 'Dev',      desc: 'developers e admins' },
    { id: 'interno',  label: 'Interno',  desc: 'colaboradores · CRM · KPIs · módulos' },
    { id: 'clientes', label: 'Clientes', desc: 'modo público — sem dados internos' },
    { id: 'board',    label: 'Board',    desc: 'executivos — KPIs estratégicos · Pipeline 3' },
  ];
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {items.map(it => (
        <label key={it.id} style={{
          display: 'flex', alignItems: 'center', gap: 10,
          padding: '8px 10px', borderRadius: 6,
          background: sel.has(it.id) ? 'color-mix(in oklch, var(--ai-500) 8%, transparent)' : 'var(--bg-sunken)',
          border: `1px solid ${sel.has(it.id) ? 'color-mix(in oklch, var(--ai-500) 30%, transparent)' : 'var(--border)'}`,
          cursor: 'pointer',
        }}>
          <input
            type="checkbox" checked={sel.has(it.id)}
            onChange={() => toggle(it.id)}
            style={{ accentColor: 'var(--ai-500)' }}
          />
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 12, fontWeight: 500, color: 'var(--text)' }}>{it.label}</div>
            <div style={{ fontSize: 10.5, color: 'var(--text-dim)' }}>{it.desc}</div>
          </div>
        </label>
      ))}
    </div>
  );
};

// ════════════════════════════════════════════════════════════════
// PortalAccessCard
// ════════════════════════════════════════════════════════════════
const PortalAccessCard = ({ user, onChange }) => {
  const set = (patch) => onChange({ ...user, ...patch });
  const usernameAvailable = !!user.portal_username && /^[a-z0-9._-]+$/.test(user.portal_username);
  return (
    <div style={{
      border: '1px solid var(--border)', borderRadius: 8,
      background: 'var(--bg-sunken)', padding: '14px',
    }}>
      <label style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14 }}>
        <input
          type="checkbox" checked={user.portal_activo}
          onChange={ev => set({ portal_activo: ev.target.checked })}
          style={{ accentColor: 'var(--ai-500)' }}
        />
        <span style={{ fontSize: 13, fontWeight: 500 }}>Portal activo</span>
        <PortalBadge activo={user.portal_activo} />
      </label>

      <div style={{ display: 'grid', gridTemplateColumns: '120px 1fr', gap: 10, fontSize: 12, alignItems: 'center', marginBottom: 8 }}>
        <span style={{ color: 'var(--text-muted)' }}>Username:</span>
        <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
          <input
            type="text" value={user.portal_username || ''}
            onChange={ev => set({ portal_username: ev.target.value.toLowerCase() })}
            disabled={!user.portal_activo}
            placeholder="username.utilizador"
            style={{
              flex: 1, padding: '5px 8px',
              background: 'var(--bg-elev)', border: '1px solid var(--border)',
              borderRadius: 4, fontSize: 12, color: 'var(--text)',
              fontFamily: 'var(--font-mono)', outline: 'none',
            }}
          />
          {user.portal_activo && (
            <span style={{
              fontSize: 10.5, color: usernameAvailable ? 'var(--ok)' : 'var(--warn)',
              fontFamily: 'var(--font-mono)',
            }}>{usernameAvailable ? '✓ Disponível' : '⚠ inválido'}</span>
          )}
        </div>

        <span style={{ color: 'var(--text-muted)' }}>Password:</span>
        <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
          <span style={{ flex: 1, fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--text-dim)' }}>••••••••••</span>
          <button className="btn btn-sm btn-ghost"><Icon name="refresh" size={11} />Reset password</button>
        </div>

        <span style={{ color: 'var(--text-muted)' }}>SSO MS 365:</span>
        <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
          <SSOBadge activo={user.portal_activo} />
          {user.portal_activo && user.ultima_interacao_digi && (
            <span style={{ fontSize: 11, color: 'var(--text-dim)' }}>
              último login {fmtRel(user.ultima_interacao_digi)}
            </span>
          )}
        </div>
      </div>

      <div style={{ display: 'flex', gap: 8, marginTop: 16, paddingTop: 12, borderTop: '1px solid var(--border)' }}>
        <button className="btn btn-sm btn-ghost"><Icon name="refresh" size={11} />Forçar logout de todas as sessões</button>
        <button className="btn btn-sm btn-ghost" style={{ color: 'var(--err)' }}>
          <Icon name="warning" size={11} />Suspender utilizador
        </button>
      </div>
    </div>
  );
};

// ════════════════════════════════════════════════════════════════
// Audit · Sessions · Conversas
// ════════════════════════════════════════════════════════════════
const AuditLogList = ({ entries }) => (
  <div style={{ border: '1px solid var(--border)', borderRadius: 8, overflow: 'hidden' }}>
    {entries.length === 0 ? (
      <div style={{ padding: 16, fontSize: 12, color: 'var(--text-dim)', textAlign: 'center' }}>Sem alterações registadas.</div>
    ) : entries.map((e, i) => (
      <div key={i} style={{
        display: 'grid', gridTemplateColumns: '120px 1fr',
        gap: 12, padding: '10px 12px', fontSize: 12,
        borderBottom: i < entries.length - 1 ? '1px solid var(--border)' : '0',
      }}>
        <div style={{ display: 'flex', flexDirection: 'column' }}>
          <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-muted)' }}>{fmtRel(e.ts)}</span>
          <span style={{ fontSize: 10, color: 'var(--text-dim)' }}>{e.who}</span>
        </div>
        <div>
          <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-muted)', marginBottom: 2 }}>{e.field}</div>
          <div style={{ fontSize: 12 }}>
            <span style={{ color: 'var(--text-dim)', textDecoration: 'line-through' }}>{e.from || '∅'}</span>
            <span style={{ color: 'var(--text-dim)', margin: '0 6px' }}>→</span>
            <span style={{ color: 'var(--ok)' }}>{e.to || '∅'}</span>
          </div>
        </div>
      </div>
    ))}
  </div>
);

const SessionsList = ({ sessions }) => (
  <div style={{ border: '1px solid var(--border)', borderRadius: 8, overflow: 'hidden' }}>
    {sessions.length === 0 ? (
      <div style={{ padding: 16, fontSize: 12, color: 'var(--text-dim)', textAlign: 'center' }}>Portal inactivo — sem sessões.</div>
    ) : sessions.map((s, i) => (
      <div key={i} style={{
        display: 'grid', gridTemplateColumns: '120px 110px 1fr 80px',
        gap: 12, padding: '8px 12px', fontSize: 11.5,
        borderBottom: i < sessions.length - 1 ? '1px solid var(--border)' : '0',
        fontFamily: 'var(--font-mono)',
      }}>
        <span style={{ color: 'var(--text-muted)' }}>{fmtRel(s.ts)}</span>
        <span style={{ color: 'var(--text)' }}>{s.ip}</span>
        <span style={{ color: 'var(--text-dim)' }}>{s.ua}</span>
        <span style={{ color: 'var(--text)', textAlign: 'right' }}>{s.duration}</span>
      </div>
    ))}
  </div>
);

const ConversasList = ({ conversas }) => (
  <div style={{ border: '1px solid var(--border)', borderRadius: 8, overflow: 'hidden' }}>
    {conversas.length === 0 ? (
      <div style={{ padding: 16, fontSize: 12, color: 'var(--text-dim)', textAlign: 'center' }}>Sem conversas registadas.</div>
    ) : (
      <>
        {conversas.map((c, i) => (
          <div key={i} style={{
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
            padding: '10px 12px', fontSize: 12,
            borderBottom: i < conversas.length - 1 ? '1px solid var(--border)' : '0',
          }}>
            <span style={{ color: 'var(--text)' }}>{c.mes}</span>
            <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
              <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-muted)' }}>{c.count} interacções</span>
              <div style={{ width: 80, height: 4, background: 'var(--bg-sunken)', borderRadius: 2, overflow: 'hidden' }}>
                <div style={{
                  height: '100%', width: `${Math.min(100, c.count / 2)}%`,
                  background: 'var(--ai-500)',
                }} />
              </div>
            </div>
          </div>
        ))}
        <div style={{ padding: '10px 12px', borderTop: '1px solid var(--border)', display: 'flex', justifyContent: 'flex-end' }}>
          <button className="btn btn-sm btn-ghost">
            <Icon name="link" size={11} />Abrir Langfuse
          </button>
        </div>
      </>
    )}
  </div>
);

// ════════════════════════════════════════════════════════════════
// PortalSubsEditor — controlo completo: departamentos + submenus
// ════════════════════════════════════════════════════════════════
const PortalSubsEditor = ({ value, onChange, userTipo }) => {
  const [expanded, setExpanded] = React.useState(false);
  const [activeDept, setActiveDept] = React.useState(null);
  const _SINGLE_DEPT = new Set(['comercial','tecnico','marketing','administrativo','operacional']);
  const catalog = (D.PORTAL_SUBS_CATALOG || []).filter(d =>
    !_SINGLE_DEPT.has(userTipo) || !d.tiposComAcesso || d.tiposComAcesso.includes(userTipo)
  );
  const subs = value || null;

  // Modelo whitelist: quando subs != null, só depts com chave são visíveis.
  // subs[key] ausente = hidden; null = livre; [] = hidden (compat); ['ids'] = restrito
  const isDeptHidden = (subKey) => {
    if (!subs) return false;
    if (!(subKey in subs)) return true; // ausente = oculto
    return Array.isArray(subs[subKey]) && subs[subKey].length === 0; // [] = oculto
  };
  const defaultVisible = (items) => items.filter(i => !i.restricted).map(i => i.id);

  const getDeptStatus = (subKey, items) => {
    if (!subs) return 'livre';
    if (!(subKey in subs) || (Array.isArray(subs[subKey]) && subs[subKey].length === 0)) return 'hidden';
    if (subs[subKey] === null) return 'livre';
    const def = new Set(defaultVisible(items));
    const cur = new Set(subs[subKey]);
    if (def.size === cur.size && [...def].every(id => cur.has(id))) return 'livre';
    return 'restricted';
  };

  const getDeptVisible = (subKey, items) => {
    if (!subs || !(subKey in subs) || subs[subKey] === null) return defaultVisible(items);
    return subs[subKey].length > 0 ? subs[subKey] : defaultVisible(items);
  };

  // Toggle dept on/off (whitelist: presente=visível, ausente=oculto)
  const toggleDept = (subKey) => {
    if (isDeptHidden(subKey)) {
      // tornar visível: adicionar chave com null (libre)
      const newSubs = { ...(subs || {}) };
      newSubs[subKey] = null;
      onChange(newSubs);
    } else {
      // ocultar: remover chave da whitelist
      if (!subs) {
        // era null (tudo livre) — criar whitelist com todos os depts excepto este
        const newSubs = {};
        catalog.forEach(d => { if (d.subKey !== subKey) newSubs[d.subKey] = null; });
        onChange(Object.keys(newSubs).length > 0 ? newSubs : null);
      } else {
        const newSubs = { ...subs };
        delete newSubs[subKey];
        onChange(Object.keys(newSubs).length > 0 ? newSubs : null);
      }
    }
  };

  // Toggle individual submenu item
  const toggleItem = (subKey, items, itemId) => {
    const current = getDeptVisible(subKey, items);
    const set = new Set(current);
    if (set.has(itemId)) set.delete(itemId); else set.add(itemId);
    const newArr = [...set];
    const def = new Set(defaultVisible(items));
    const newSet = new Set(newArr);
    const matchesDefault = def.size === newSet.size && [...def].every(id => newSet.has(id));
    const newSubs = { ...(subs || {}) };
    if (matchesDefault) { delete newSubs[subKey]; } else { newSubs[subKey] = newArr; }
    onChange(Object.keys(newSubs).length > 0 ? newSubs : null);
  };

  const resetDept = (subKey) => {
    const newSubs = { ...(subs || {}) };
    delete newSubs[subKey];
    onChange(Object.keys(newSubs).length > 0 ? newSubs : null);
  };

  const hiddenCount     = catalog.filter(d => isDeptHidden(d.subKey)).length;
  const restrictedCount = catalog.filter(d => getDeptStatus(d.subKey, d.items) === 'restricted').length;
  const hasChanges      = hiddenCount > 0 || restrictedCount > 0;

  const activeDeptData = catalog.find(d => d.subKey === activeDept) || catalog[0];

  if (catalog.length === 0) return (
    <div style={{ padding: '10px 14px', fontSize: 12, color: 'var(--text-dim)', border: '1px solid var(--border)', borderRadius: 8, background: 'var(--bg-sunken)' }}>
      Sem departamentos configuráveis para este tipo de utilizador.
    </div>
  );

  const statusColor = (status) => status === 'hidden' ? 'var(--text-dim)' : status === 'restricted' ? 'var(--warn)' : 'var(--ok)';
  const statusLabel = (status, visible, total) => status === 'hidden' ? 'oculto' : status === 'restricted' ? `${visible}/${total}` : 'livre';

  return (
    <div style={{ border: '1px solid var(--border)', borderRadius: 8, background: 'var(--bg-sunken)', overflow: 'hidden' }}>
      <div style={{ padding: '12px 14px' }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
          <div className="font-display" style={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--text-muted)' }}>
            Resumo visualizações
          </div>
          {hasChanges ? (
            <span style={{ padding: '2px 8px', borderRadius: 999, fontSize: 9.5, background: 'color-mix(in oklch, var(--warn) 18%, transparent)', border: '1px solid color-mix(in oklch, var(--warn) 35%, transparent)', color: 'var(--warn)', fontFamily: 'var(--font-mono)', letterSpacing: '0.06em' }}>
              {hiddenCount > 0 ? `${hiddenCount} OCULTOS` : `${restrictedCount} RESTRITOS`}
            </span>
          ) : (
            <span style={{ padding: '2px 8px', borderRadius: 999, fontSize: 9.5, background: 'color-mix(in oklch, var(--ok) 12%, transparent)', border: '1px solid color-mix(in oklch, var(--ok) 30%, transparent)', color: 'var(--ok)', fontFamily: 'var(--font-mono)', letterSpacing: '0.06em' }}>
              LIVRE
            </span>
          )}
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '5px 18px', fontSize: 12, marginBottom: 12 }}>
          {catalog.map(d => {
            const status  = getDeptStatus(d.subKey, d.items);
            const visible = getDeptVisible(d.subKey, d.items);
            return (
              <div key={d.subKey} style={{ display: 'flex', justifyContent: 'space-between', gap: 8 }}>
                <span style={{ color: status === 'hidden' ? 'var(--text-dim)' : 'var(--text-muted)', textDecoration: status === 'hidden' ? 'line-through' : 'none' }}>{d.label}:</span>
                <span style={{ fontFamily: 'var(--font-mono)', color: statusColor(status) }}>
                  {statusLabel(status, visible.length, d.items.length)}
                </span>
              </div>
            );
          })}
        </div>
        <button onClick={() => setExpanded(!expanded)} className="btn btn-sm" style={{ width: '100%' }}>
          <Icon name={expanded ? 'arrowUp' : 'arrowDown'} size={12} />
          {expanded ? 'Esconder editor' : 'Gerir visualizações'}
        </button>
      </div>

      {expanded && (
        <div style={{ borderTop: '1px solid var(--border)', display: 'flex', minHeight: 220 }}>
          {/* Left: dept list com toggle visibilidade */}
          <div style={{ width: 148, borderRight: '1px solid var(--border)', padding: '8px 6px', display: 'flex', flexDirection: 'column', gap: 2, flexShrink: 0 }}>
            {catalog.map(d => {
              const isActive  = activeDeptData?.subKey === d.subKey;
              const hidden    = isDeptHidden(d.subKey);
              const status    = getDeptStatus(d.subKey, d.items);
              const dotColor  = hidden ? 'var(--text-dim)' : status === 'restricted' ? 'var(--warn)' : 'var(--ok)';
              return (
                <div key={d.subKey} style={{ display: 'flex', alignItems: 'center', gap: 4, borderRadius: 6, background: isActive ? 'var(--accent-500)' : 'transparent' }}
                  onMouseEnter={e => { if (!isActive) e.currentTarget.style.background = 'var(--bg-hover)'; }}
                  onMouseLeave={e => { if (!isActive) e.currentTarget.style.background = 'transparent'; }}
                >
                  <input type="checkbox" checked={!hidden} title={hidden ? 'Dept oculto — clica para mostrar' : 'Clica para ocultar dept'}
                    onChange={() => toggleDept(d.subKey)}
                    style={{ accentColor: 'var(--ai-500)', flexShrink: 0, marginLeft: 8, cursor: 'pointer' }}
                    onClick={e => e.stopPropagation()}
                  />
                  <button onClick={() => setActiveDept(d.subKey)}
                    style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 6, padding: '6px 6px 6px 2px', background: 'transparent', color: isActive ? '#fff' : (hidden ? 'var(--text-dim)' : 'var(--text-muted)'), fontSize: 12, fontWeight: isActive ? 600 : 400, textAlign: 'left', textDecoration: hidden ? 'line-through' : 'none' }}
                  >
                    <span style={{ width: 6, height: 6, borderRadius: '50%', flexShrink: 0, background: isActive ? '#fff' : dotColor, opacity: isActive ? 1 : 0.8 }} />
                    <span style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{d.label}</span>
                  </button>
                </div>
              );
            })}
          </div>

          {/* Right: submenus do dept activo */}
          {activeDeptData && (() => {
            const { subKey, items } = activeDeptData;
            const hidden   = isDeptHidden(subKey);
            const visible  = new Set(getDeptVisible(subKey, items));
            const status   = getDeptStatus(subKey, items);
            return (
              <div style={{ flex: 1, padding: '12px 14px' }}>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
                  <span style={{ fontSize: 11, fontWeight: 600, color: hidden ? 'var(--text-dim)' : 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.08em', fontFamily: 'var(--font-display)', textDecoration: hidden ? 'line-through' : 'none' }}>
                    {activeDeptData.label}
                  </span>
                  {status === 'restricted' && !hidden && (
                    <button onClick={() => resetDept(subKey)} className="btn btn-sm btn-ghost" style={{ fontSize: 10.5, padding: '2px 7px' }}>
                      <Icon name="refresh" size={11} /> Livre
                    </button>
                  )}
                </div>
                {hidden ? (
                  <div style={{ padding: '12px 10px', borderRadius: 6, background: 'var(--bg-hover)', fontSize: 12, color: 'var(--text-dim)', textAlign: 'center' }}>
                    Departamento oculto — os utilizadores não vêem este dept no sidebar.<br />
                    <button onClick={() => toggleDept(subKey)} className="btn btn-sm" style={{ marginTop: 8 }}>
                      <Icon name="check" size={11} /> Tornar visível
                    </button>
                  </div>
                ) : (
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                    {items.map(item => (
                      <label key={item.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 8px', borderRadius: 6, cursor: 'pointer', background: visible.has(item.id) ? 'color-mix(in oklch, var(--ai-500) 6%, transparent)' : 'transparent', border: `1px solid ${visible.has(item.id) ? 'color-mix(in oklch, var(--ai-500) 20%, transparent)' : 'transparent'}` }}>
                        <input type="checkbox" checked={visible.has(item.id)} onChange={() => toggleItem(subKey, items, item.id)} style={{ accentColor: 'var(--ai-500)', flexShrink: 0 }} />
                        <span style={{ fontSize: 12, color: visible.has(item.id) ? 'var(--text)' : 'var(--text-dim)', flex: 1 }}>{item.label}</span>
                        {item.restricted && <span style={{ fontSize: 9.5, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.05em' }}>restrito</span>}
                      </label>
                    ))}
                  </div>
                )}
              </div>
            );
          })()}
        </div>
      )}
    </div>
  );
};

// ════════════════════════════════════════════════════════════════
// Expor
// ════════════════════════════════════════════════════════════════
window.AdminUsers = {
  Avatar, Tooltip,
  EmpresaTags, RelativeTime,
  TipoBadge, PortalBadge, SSOBadge, ApolloBadge,
  SectionHeader, FieldRow,
  EmpresaJunctionTable, PermissoesEditor, ModosAcessoEditor, PortalSubsEditor, PortalAccessCard,
  AuditLogList, SessionsList, ConversasList,
  helpers: { initials, fmtRel, fmtAbs },
};
