/* Shared shell: Sidebar, Topbar, Digi AI chat drawer, Command palette (⌘K) */

// Sub-navegação por departamento. Se existir, o item expande (accordion).
// DEV (build · modificar) — construir e alterar a plataforma
const DEV_SUBNAV = [
  { id: 'inicio', label: 'Início', kbd: '1' },
  { id: 'architecture', label: 'Architecture', kbd: '2' },
  { id: 'prompts', label: 'Prompts', kbd: '3' },
  { id: 'kb', label: 'Knowledge Base', kbd: '4' },
  { id: 'agents', label: 'Sub-agentes', kbd: '5' },
  { id: 'skills', label: 'Skills', kbd: '6' },
  { id: 'tools', label: 'Tools', kbd: '7' },
  { id: 'routing', label: 'Routing', kbd: '8' },
  { id: 'conversations', label: 'Replay', kbd: '9' },
  { id: 'deploy', label: 'Deploy', kbd: 'D' },
  { id: 'integracoes', label: 'Integrações', kbd: 'I' },
  { id: 'roadmap', label: 'Roadmap', kbd: 'R' },
  { id: 'sales_sat_f1', label: 'SALES & SAT F1', kbd: 'S' },
  { id: 'costs', label: 'Custos & ROI', kbd: 'C' },
  { id: 'backups', label: 'Backups', kbd: 'B' },
];

// ADMIN (governance · gestão) — modo privilegiado, gating por lista nominal
const ADMIN_SUBNAV = [
  { id: 'inicio', label: 'Início', kbd: '1' },
  { id: 'utilizadores', label: 'Utilizadores', kbd: '2' },
  { id: 'empresas', label: 'Empresas', kbd: '3' },
  { id: 'audit', label: 'Audit log', kbd: '4' },
  { id: 'integracoes', label: 'Integrações', kbd: '5' },
  { id: 'importar', label: 'Importar Dados', kbd: '6' },
];

// SISTEMA (run · observar) — operar e monitorizar
const SISTEMA_SUBNAV = [
  { id: 'inbox', label: 'Inbox · Live', kbd: '1' },
  { id: 'overview', label: 'Overview', kbd: '2' },
  { id: 'kpis', label: 'KPIs', kbd: '3' },
  { id: 'costs', label: 'Costs', kbd: '4' },
  { id: 'integrations', label: 'Integrations', kbd: '5' },
  { id: 'primavera', label: 'Ligação Primavera', kbd: '6' },
  { id: 'agentes',  label: 'Agentes',           kbd: '7' },
  { id: 'gestor',   label: 'Gestor CRM',        kbd: '8' },
  { id: 'm365',     label: 'M365 Sync',         kbd: '9' },
  { id: 'alerts',   label: 'Alerts',            kbd: 'A' },
];

// RH (Recursos Humanos) — diretório e organograma
const RH_SUBNAV = [
  { id: 'organograma', label: 'Organograma', kbd: '1' },
];

const MARKETING_SUBNAV = [
  { id: 'inicio',            label: 'Início',                   kbd: '1' },
  { id: 'objectivos',        label: 'Objectivos',               kbd: '2' },
  { id: 'resultados',        label: 'Resultados',               kbd: '3' },
  { id: 'marcas',            label: 'Marcas e Estratégia',      kbd: '4' },
  { id: 'plano-comunicacao', label: 'Plano de Comunicação',     kbd: '5' },
  { id: 'briefings',         label: 'Briefings',                kbd: '6' },
  { id: 'campanhas',         label: 'Campanhas',                kbd: '7' },
  { id: 'conteudos',         label: 'Produção de Conteúdos',    kbd: '8' },
  { id: 'publicacao',        label: 'Activação',                kbd: '9' },
  { id: 'crm',           label: 'CRM',                    kbd: '0' },
  { id: 'sdr',               label: 'SDR',                      kbd: 'A' },
  { id: 'performance-ads',   label: 'Performance Ads',          kbd: 'B' },
  { id: 'agentes',           label: 'Sub-agentes',              kbd: 'C' },
  { id: 'open-houses',       label: 'Open Houses',              kbd: 'D' },
  { id: 'budget',            label: 'Budget',                   kbd: 'E' },
  { id: 'producao',          label: 'Produção',                 kbd: 'F' },
];

const FINANCE_SUBNAV = [
  { id: 'cobrancas',              label: 'Cobranças',               kbd: '1', tag: 'Em desenvolvimento' },
  { id: 'tesouraria',             label: 'Tesouraria',              kbd: '2', tag: 'Em desenvolvimento' },
  { id: 'contabilidade',          label: 'Contabilidade',           kbd: '3', tag: 'Em desenvolvimento' },
  { id: 'controlling',            label: 'Controlling',             kbd: '4', tag: 'Em desenvolvimento' },
  { id: 'primavera',              label: 'Primavera Finance',       kbd: '5', tag: 'Em desenvolvimento' },
  { id: 'reports-pl',             label: 'Reports P&L',             kbd: '6', tag: 'Não existe' },
  { id: 'clientes-stocks',        label: 'Clientes & Stocks',       kbd: '7', tag: 'Não existe' },
  { id: 'objectivos-financeiros', label: 'Objectivos Financeiros',  kbd: '8', tag: 'Não existe' },
  { id: 'reconciliacao',          label: 'Reconciliação Faturas',   kbd: '9' },
  { id: 'printplan',              label: 'PrintPlan',               kbd: '0' },
];

const BUSINESS_AI_SUBNAV = [  { id: 'pipeline', label: 'Pipeline', kbd: '1' }, { id: 'roadmap', label: 'Roadmap', kbd: '2' }, { id: 'sugestoes', label: 'Board Intake', kbd: '3' }, { id: 'editar', label: 'Editar Roadmap', kbd: '4' }, { id: 'definir-dashboard', label: 'Gerar Pedido', kbd: '5' }, { id: 'gerir-dashboards', label: 'Gestão de Pedidos', kbd: '6' },];
const COMERCIAL_SUBNAV = [
  { id: 'dashboard',     label: 'Dashboard v1',        kbd: '1' },
  { id: 'dashboard-v2',  label: 'Dashboard',            kbd: '2' },
  { id: 'rpc',           label: 'Prod. Comercial',      kbd: '3' },
  { id: 'bp',            label: 'Business Plan v1',     kbd: '4' },
  { id: 'bp-v2',         label: 'Business Plan',        kbd: '5' },
  { id: 'oportunidades', label: 'Oportunidades',        kbd: '6' },
  { id: 'prospeccao',    label: 'Prospecção',           kbd: '7' },
  { id: 'clientes',      label: 'Clientes',             kbd: '8' },
  { id: 'simulador',     label: 'Simulador',            kbd: '9' },
  { id: 'digi',          label: 'Chat AI',              kbd: 'A', ai: true },
  { id: 'vendas',        label: 'Vendas & Performance', kbd: 'B', restricted: true },
  { id: 'gestor-classic', label: 'Monitor de Vendas ERP', kbd: 'C', restricted: true },
  { id: 'rel-rpc',        label: 'RPC', kbd: 'D', restricted: true },
  { id: 'performance',        label: 'Performance Mimaki',   kbd: 'E' },
  { id: 'performance-media',  label: 'Performance Media',    kbd: 'F' },
  { id: 'bp-studio',          label: 'Objectivos Performance', kbd: 'G' },
];

const LOGISTICA_SUBNAV = [
  { id: 'dias-stock',     label: 'Dias de Stock',                kbd: '1', tag: 'Não existe' },
  { id: 'nivel-servico',  label: 'Nível de Serviço de Entregas', kbd: '2', tag: 'Não existe' },
  { id: 'rotacao-stock',  label: 'Rotação de Stock',             kbd: '3', tag: 'Não existe' },
  { id: 'print-plan',     label: 'Print Plan e Consignações',    kbd: '4', tag: 'Não existe' },
];

const PRODUCAO_SUBNAV = [
  { id: 'kpis',             label: 'KPIs Produção',        kbd: '1' },
  { id: 'stock-pi',         label: 'Stock PI',             kbd: '2' },
  { id: 'plano-mensal',     label: 'Plano Mensal',         kbd: '3' },
  { id: 'nao-conformes',    label: 'Não Conformes',        kbd: '4' },
  { id: 'desperdicios',     label: 'Desperdícios',         kbd: '5' },
  { id: 'planeamento-mrp',  label: 'Planeamento MRP',      kbd: '6' },
];

const QUALIDADE_SUBNAV = [
  { id: 'rec-fornecedores', label: 'Rec. Fornecedores', kbd: '1' },
  { id: 'rec-clientes',     label: 'Rec. Clientes',     kbd: '2' },
  { id: 'avaliacao',        label: 'Aval. Fornecedores', kbd: '3' },
];

const SAT_SUBNAV = [
  { id: 'overview',  label: 'Overview',   kbd: '1' },
  { id: 'inbox',     label: 'Inbox WA',   kbd: '2' },
  { id: 'historico', label: 'Histórico',  kbd: '3' },
];

const NAV = [
  { section: 'Departamentos' },
  { id: 'marketing', label: 'Marketing', icon: 'marketing', target: 'marketing', subKey: 'marketing', sub: MARKETING_SUBNAV, subStorage: 'digi-marketing-sub', subDefault: 'inicio' },
  { section: 'Admin', requiresAdminMode: true },
  { id: 'admin', label: 'ADMIN', subtitle: 'governance · gestão', icon: 'user', iconColor: 'oklch(0.58 0.16 30)', target: 'admin', subKey: 'admin', sub: ADMIN_SUBNAV, subStorage: 'digi-admin-sub', subDefault: 'inicio', requiresAdminMode: true },
];

// Expose module → subnav map for BI forms (Definir Pedido)
window.PORTAL_MODULES = NAV
  .filter(it => it.sub && it.label && !it.section && !['dev','admin'].includes(it.id))
  .map(it => ({
    label: it.label.toUpperCase(),
    submenus: it.sub.filter(s => s.id !== 'definir-dashboard').map(s => s.label).concat(['Outro']),
  }));

// Full nav catalog (id + subnav ids+labels) — used by admin PORTAL_SUBS_CATALOG getter
window.PORTAL_NAV_CATALOG = NAV
  .filter(it => it.sub && it.label && !it.section && !['dev','admin'].includes(it.id))
  .map(it => ({
    id: it.id,
    label: it.label,
    sub: it.sub.map(s => ({ id: s.id, label: s.label })),
  }));

// Shared sub-nav state across Sidebar and screens. Source of truth: localStorage per storage-key.
const useSubNav = (storageKey, fallback) => {
  const [val, setVal] = React.useState(() => {
    if (!storageKey) return fallback;
    try { return localStorage.getItem(storageKey) || fallback; } catch { return fallback; }
  });
  React.useEffect(() => {
    if (!storageKey) return;
    try { localStorage.setItem(storageKey, val); } catch {}
    window.dispatchEvent(new CustomEvent('digi-subnav', { detail: { storageKey, val } }));
  }, [val, storageKey]);
  React.useEffect(() => {
    if (!storageKey) return;
    const onSync = (e) => {
      if (e.detail && e.detail.storageKey === storageKey && e.detail.val !== val) setVal(e.detail.val);
    };
    window.addEventListener('digi-subnav', onSync);
    return () => window.removeEventListener('digi-subnav', onSync);
  }, [storageKey, val]);
  return [val, setVal];
};
window.useSubNav = useSubNav;

function useBreakpoint() {
  const [w, setW] = React.useState(window.innerWidth);
  React.useEffect(() => {
    const fn = () => setW(window.innerWidth);
    window.addEventListener('resize', fn);
    return () => window.removeEventListener('resize', fn);
  }, []);
  return {
    isMobile:  w < 768,
    isTablet:  w >= 768 && w < 1024,
    isDesktop: w >= 1024,
  };
}
window.useBreakpoint = useBreakpoint;

// Indented accordion sub-list. Each row has: vertical rail, label, badge, kbd.
const SubNavList = ({ items, storageKey, fallback, isParentActive, onNavigateParent, userTipo, userModos, subKey, userSubs }) => {
  const [subActive, setSubActive] = useSubNav(storageKey, fallback);
  const isDev = userTipo === 'admin' || (Array.isArray(userModos) && userModos.includes('dev'));
  const allowedSubs = userSubs && subKey ? (userSubs[subKey] || null) : null;
  const visibleItems = items.filter(s => {
    if (s.devOnly && !isDev) return false;
    if (s.requiresTipo && s.requiresTipo !== userTipo) return false;
    if (s.restricted && !isDev && !allowedSubs?.includes(s.id)) return false;
    if (allowedSubs && !allowedSubs.includes(s.id)) return false;
    return true;
  });
  return (
    <div style={{ marginLeft: 8, marginTop: 2, marginBottom: 6 }}>
      {visibleItems.map(s => {
        const active = isParentActive && s.id === subActive;
        return (
          <button key={s.id}
            onClick={() => {
              if (!isParentActive) onNavigateParent();
              setSubActive(s.id);
            }}
            style={{
              width: '100%', display: 'flex', alignItems: 'center', gap: 8,
              padding: '6px 10px', marginBottom: 1,
              borderRadius: 6,
              background: active ? 'var(--accent-500)' : 'transparent',
              color: active ? '#fff' : (s.muted ? 'var(--text-dim)' : 'var(--text-muted)'),
              fontSize: 12, fontWeight: active ? 600 : 400,
              fontStyle: s.muted && !active ? 'italic' : 'normal',
            }}
            onMouseEnter={e => { if (!active) e.currentTarget.style.background = 'var(--bg-hover)'; }}
            onMouseLeave={e => { if (!active) e.currentTarget.style.background = 'transparent'; }}
          >
            <span style={{ width: 5, height: 5, borderRadius: '50%', flexShrink: 0, background: active ? '#fff' : 'var(--text-dim)', opacity: active ? 1 : 0.6 }} />
            <span style={{ flex: 1, textAlign: 'left', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{s.label}</span>
            {s.badge && <span style={{ padding: '0 5px', fontSize: 9, fontFamily: 'var(--font-mono)', color: 'var(--accent-500)', background: 'rgba(0,163,255,0.14)', borderRadius: 3 }}>{s.badge}</span>}
          </button>
        );
      })}
    </div>
  );
};

// Item de nav com sub-menu — extracto em componente próprio para que useSubNav
// não seja chamado dentro de um .map() (viola a regra dos hooks do React).
const NavItemWithSub = ({ item, active, compact, openSub, setOpenSub, onNavigate, userTipo, userModos, userSubs }) => {
  const [subActive] = useSubNav(item.subStorage, item.subDefault);
  const isActive = item.id === active;
  const isExpanded = !compact && openSub === item.subKey;
  return (
    <React.Fragment>
      <button
        onClick={() => {
          if (!compact) {
            if (openSub === item.subKey) {
              setOpenSub(null);
            } else {
              setOpenSub(item.subKey);
              if (!isActive && item.target) onNavigate(item.target);
            }
          } else if (item.target) {
            onNavigate(item.target);
          }
        }}
        title={compact ? item.label : ''}
        style={{
          width: '100%', display: 'flex', alignItems: 'center',
          gap: 12, padding: compact ? '10px' : (item.subtitle ? '7px 10px 6px' : '8px 10px'),
          borderRadius: 'var(--r-3)', marginBottom: 2,
          justifyContent: compact ? 'center' : 'flex-start',
          background: (isActive && !item.sub) ? 'var(--brand-900)' : 'transparent',
          color: isActive ? (item.sub ? 'var(--accent-400)' : '#fff') : 'var(--text)',
          fontSize: 13, fontWeight: isActive ? 500 : 400,
          position: 'relative',
        }}
        onMouseEnter={e => { if (!isActive) e.currentTarget.style.background = 'var(--bg-hover)'; }}
        onMouseLeave={e => { if (!isActive) e.currentTarget.style.background = 'transparent'; }}
      >
        <Icon name={item.icon} size={18} style={{ color: item.iconColor && !isActive ? item.iconColor : undefined, flexShrink: 0 }} />
        {!compact && (
          <span style={{ flex: 1, textAlign: 'left', display: 'flex', flexDirection: 'column', lineHeight: 1.15, minWidth: 0 }}>
            <span style={{ fontFamily: item.subtitle ? 'var(--font-display)' : undefined, fontWeight: item.subtitle ? 600 : (isActive ? 500 : 400), letterSpacing: item.subtitle ? '0.04em' : undefined }}>{item.label}</span>
            {item.subtitle && <span style={{ fontSize: 10, fontStyle: 'italic', color: isActive ? 'rgba(255,255,255,0.65)' : 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.02em', marginTop: 1 }}>{item.subtitle}</span>}
          </span>
        )}
        {!compact && item.badge && <span className="badge badge-danger" style={{ padding: '1px 6px', fontSize: 10 }}>{item.badge}</span>}
        {!compact && <Icon name="chevron" size={12} style={{ transform: isExpanded ? 'rotate(180deg)' : 'none', transition: 'transform 0.18s', opacity: 0.7 }} />}
        {compact && item.badge && <span style={{ position: 'absolute', top: 4, right: 6, minWidth: 14, height: 14, padding: '0 4px', borderRadius: 7, background: 'var(--danger)', color: '#fff', fontSize: 9, fontWeight: 600, display: 'inline-grid', placeItems: 'center', border: '2px solid var(--bg-elev)' }}>{item.badge}</span>}
      </button>
      {isExpanded && (
        <SubNavList
          items={item.sub}
          storageKey={item.subStorage}
          fallback={item.subDefault}
          isParentActive={isActive}
          onNavigateParent={() => { if (!isActive && item.target) onNavigate(item.target); }}
          userTipo={userTipo}
          userModos={userModos}
          subKey={item.subKey}
          userSubs={userSubs}
        />
      )}
    </React.Fragment>
  );
};

const Sidebar = ({ active, onNavigate, variation, allowedScreens, userRole, userEmail, userTipo, userModos, userSubs, drawerOpen, onClose }) => {
  const { isDesktop } = window.useBreakpoint();
  // Se allowedScreens for null → tudo. Senão, só itens cujo target está na lista
  // (ou items section/sem target são mantidos se houver algum item visível à volta).
  // requiresRole filtra também por role do utilizador.
  // requiresAdminMode consulta AdminUsersData.canAccessAdminMode (lista nominal de 5 emails).
  const adminGate = window.AdminUsersData?.canAccessAdminMode;
  const filterNav = (items) => {
    const allowed = allowedScreens ? new Set(allowedScreens) : null;
    const roleOk = (it) => !it.requiresRole || (userRole && it.requiresRole.includes(userRole));
    const adminOk = (it) => !it.requiresAdminMode || (adminGate && adminGate({ email_profissional: userEmail }));
    const subOk = (it) => {
      if (!userSubs || !it.subKey) return true; // sem restrições
      if (!(it.subKey in userSubs)) return false; // ausente na whitelist = oculto
      const allowedSubs = userSubs[it.subKey];
      if (Array.isArray(allowedSubs) && allowedSubs.length === 0) return false; // [] = oculto
      if (!allowedSubs) return true; // null = livre (todos os submenus)
      return it.sub && it.sub.some(s => allowedSubs.includes(s.id));
    };
    const passes = (it) => roleOk(it) && adminOk(it) && subOk(it);
    // Primeiro passo: determina items cujo target é permitido
    const visibleByTarget = items.map(it => {
      if (it.section) return false;
      if (!passes(it)) return false;
      if (!it.target) return false;
      return allowed ? allowed.has(it.target) : true;
    });
    // Segundo passo: mantém sections que tenham pelo menos 1 item visível à sua frente
    return items.filter((it, i) => {
      if (it.section) {
        if (!passes(it)) return false;
        for (let j = i + 1; j < items.length; j++) {
          if (items[j].section) return false;
          if (visibleByTarget[j]) return true;
        }
        return false;
      }
      return visibleByTarget[i];
    });
  };
  const visibleNav = filterNav(NAV);

  const [compact, setCompact] = React.useState(() => {
    try { return localStorage.getItem('sidebar-compact') === '1'; } catch { return false; }
  });
  // Which accordion section is open. Only ONE at a time. null = none open.
  const [openSub, setOpenSub] = React.useState(() => {
    try { return localStorage.getItem('sidebar-open-sub') || null; } catch { return null; }
  });
  // Auto-open on mount/when switching to a dept-with-sub; close when switching to dept without sub.
  const prevActiveRef = React.useRef(null);
  React.useEffect(() => {
    const item = NAV.find(n => n.target === active && n.sub);
    const prev = prevActiveRef.current;
    if (prev !== active) {
      if (item) setOpenSub(item.subKey);
      else if (prev !== null) setOpenSub(null);
    }
    prevActiveRef.current = active;
  }, [active]);
  React.useEffect(() => {
    try { localStorage.setItem('sidebar-open-sub', openSub || ''); } catch {}
  }, [openSub]);
  const toggle = () => {
    setCompact(v => {
      const next = !v;
      try { localStorage.setItem('sidebar-compact', next ? '1' : '0'); } catch {}
      return next;
    });
  };

  // ⌘/ keyboard shortcut to toggle sidebar
  React.useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === '/') {
        e.preventDefault();
        toggle();
      }
    };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, []);
  const isDrawer = !isDesktop;
  return (
    <>
      {/* Scrim — só em drawer mode quando aberto */}
      {isDrawer && drawerOpen && (
        <div
          onClick={onClose}
          style={{
            position: 'fixed', inset: 0,
            background: 'rgba(0,0,0,0.48)',
            zIndex: 199,
            transition: 'opacity 0.25s',
          }}
        />
      )}
      <aside style={{
        width: compact ? 72 : 'var(--sidebar-w)',
        background: 'var(--bg-elev)',
        borderRight: '1px solid var(--border)',
        display: 'flex', flexDirection: 'column',
        height: '100vh', flexShrink: 0,
        transition: 'width 0.22s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s ease',
        ...(isDrawer ? {
          position: 'fixed',
          top: 0, left: 0,
          zIndex: 200,
          transform: drawerOpen ? 'translateX(0)' : 'translateX(-100%)',
          boxShadow: drawerOpen ? '4px 0 32px rgba(0,0,0,0.28)' : 'none',
        } : {
          position: 'sticky', top: 0,
        }),
      }}>
      <div style={{ padding: compact ? '14px 12px' : '14px 18px', borderBottom: '1px solid var(--border)', height: 'var(--topbar-h)', display: 'flex', alignItems: 'center', justifyContent: compact ? 'center' : 'space-between', minWidth: 0, gap: 8 }}>
        <DigiMark size={compact ? 32 : 36} showLabel={!compact} aiDot={false} />
      </div>


      <nav style={{ flex: 1, padding: '4px 8px', overflowY: 'auto', overflowX: 'hidden' }} className="scrollbar">
        {visibleNav.map((item, idx) => {
          if (item.section) {
            if (compact) {
              return idx === 0 ? null : (
                <div key={`s-${idx}`} style={{ height: 1, background: 'var(--border)', margin: '10px 8px' }} />
              );
            }
            return (
              <div key={`s-${idx}`} style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-display)', fontWeight: 600, letterSpacing: '0.1em', padding: idx === 0 ? '8px 10px 6px' : '16px 10px 6px', textTransform: 'uppercase' }}>{item.section}</div>
            );
          }
          // Items with sub-nav → use NavItemWithSub (hook at component level, not inside map)
          if (item.sub) {
            return (
              <NavItemWithSub
                key={item.id}
                item={item}
                active={active}
                compact={compact}
                openSub={openSub}
                setOpenSub={setOpenSub}
                onNavigate={onNavigate}
                userTipo={userTipo}
                userModos={userModos}
                userSubs={userSubs}
              />
            );
          }
          // Items without sub-nav
          const isActive = item.id === active;
          return (
            <button
              key={item.id}
              onClick={() => { if (item.target) { setOpenSub(null); onNavigate(item.target); } }}
              disabled={!item.target}
              title={compact ? item.label : ''}
              style={{
                width: '100%', display: 'flex', alignItems: 'center',
                gap: 12, padding: compact ? '10px' : (item.subtitle ? '7px 10px 6px' : '8px 10px'),
                borderRadius: 'var(--r-3)', marginBottom: 2,
                justifyContent: compact ? 'center' : 'flex-start',
                background: isActive ? 'var(--brand-900)' : 'transparent',
                color: isActive ? '#fff' : (item.target ? 'var(--text)' : 'var(--text-dim)'),
                fontSize: 13, fontWeight: isActive ? 500 : 400,
                opacity: item.target ? 1 : 0.6,
                cursor: item.target ? 'pointer' : 'default',
                position: 'relative',
              }}
              onMouseEnter={e => { if (!isActive && item.target) e.currentTarget.style.background = 'var(--bg-hover)'; }}
              onMouseLeave={e => { if (!isActive) e.currentTarget.style.background = 'transparent'; }}
            >
              <Icon name={item.icon} size={18} style={{ color: item.iconColor && !isActive ? item.iconColor : undefined, flexShrink: 0 }} />
              {!compact && (
                <span style={{ flex: 1, textAlign: 'left', display: 'flex', flexDirection: 'column', lineHeight: 1.15, minWidth: 0 }}>
                  <span style={{ fontFamily: item.subtitle ? 'var(--font-display)' : undefined, fontWeight: item.subtitle ? 600 : (isActive ? 500 : 400), letterSpacing: item.subtitle ? '0.04em' : undefined }}>{item.label}</span>
                  {item.subtitle && <span style={{ fontSize: 10, fontStyle: 'italic', color: isActive ? 'rgba(255,255,255,0.65)' : 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.02em', marginTop: 1 }}>{item.subtitle}</span>}
                </span>
              )}
              {!compact && item.badge && <span className="badge badge-danger" style={{ padding: '1px 6px', fontSize: 10 }}>{item.badge}</span>}
              {compact && item.badge && <span style={{ position: 'absolute', top: 4, right: 6, minWidth: 14, height: 14, padding: '0 4px', borderRadius: 7, background: 'var(--danger)', color: '#fff', fontSize: 9, fontWeight: 600, display: 'inline-grid', placeItems: 'center', border: '2px solid var(--bg-elev)' }}>{item.badge}</span>}
            </button>
          );
        })}
      </nav>

      {/* Collapse toggle */}
      <div style={{ padding: 12, borderTop: '1px solid var(--border)', display: 'flex', flexDirection: 'column', gap: 8 }}>
        <button
          onClick={toggle}
          title={compact ? 'Expandir menu' : 'Colapsar menu'}
          style={{
            display: 'flex', alignItems: 'center', gap: 8,
            padding: compact ? '6px' : '6px 10px',
            borderRadius: 'var(--r-2)',
            border: '1px solid var(--border)',
            background: 'transparent',
            color: 'var(--text-muted)',
            fontSize: 11, fontFamily: 'var(--font-mono)',
            justifyContent: compact ? 'center' : 'space-between',
            transition: 'all 0.15s',
          }}
          onMouseEnter={e => { e.currentTarget.style.background = 'var(--bg-hover)'; e.currentTarget.style.color = 'var(--text)'; }}
          onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--text-muted)'; }}
        >
          {!compact && <span style={{ letterSpacing: '0.06em' }}>Colapsar</span>}
          <Icon name={compact ? 'chevronRight' : 'menu'} size={14} style={{ transform: compact ? 'none' : 'rotate(0deg)' }} />
          {!compact && <kbd style={{ fontFamily: 'var(--font-mono)', fontSize: 9, padding: '1px 4px', border: '1px solid var(--border)', borderRadius: 3, background: 'var(--bg-sunken)' }}>⌘/</kbd>}
        </button>
      </div>
    </aside>
    </>
  );
};

// "Ver como" — só visível para admins. Permite ao JP simular a vista de qualquer colaborador.
const ViewAsPicker = ({ viewAs, onViewAs, currentUser }) => {
  const [open, setOpen]   = React.useState(false);
  const [search, setSearch] = React.useState('');
  const [_tick, setTick]  = React.useState(0);
  const ref = React.useRef(null);

  React.useEffect(() => {
    if (!open) return;
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) { setOpen(false); setSearch(''); } };
    document.addEventListener('mousedown', h);
    return () => document.removeEventListener('mousedown', h);
  }, [open]);

  React.useEffect(() => {
    const h = () => setTick(t => t + 1);
    window.addEventListener('digi-users-loaded', h);
    return () => window.removeEventListener('digi-users-loaded', h);
  }, []);

  const isAdmin = window.AdminUsersData?.canAccessAdminMode?.({ email_profissional: currentUser?.email });
  if (!isAdmin) return null;

  const users = window.AdminUsersData?.ALL_USERS || [];
  const q = search.toLowerCase();
  const filtered = q
    ? users.filter(u => (u.nome_apresentar || u.nome_completo || '').toLowerCase().includes(q) || (u.tipo_utilizador || '').includes(q))
    : users;

  const groups = {};
  filtered.forEach(u => {
    const t = u.tipo_utilizador || 'outros';
    if (!groups[t]) groups[t] = [];
    groups[t].push(u);
  });

  if (viewAs) {
    return (
      <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, padding: '4px 12px', background: 'color-mix(in oklch, var(--warn) 12%, transparent)', border: '1px solid color-mix(in oklch, var(--warn) 40%, transparent)', borderRadius: 999, fontSize: 12, color: 'var(--warn)', fontFamily: 'var(--font-mono)' }}>
        <Icon name="user" size={13} />
        <span style={{ opacity: 0.7 }}>Ver como:</span>
        <span style={{ fontWeight: 600 }}>{viewAs.nome_apresentar || viewAs.nome_completo}</span>
        <button onClick={() => onViewAs(null)} style={{ display: 'grid', placeItems: 'center', background: 'transparent', color: 'var(--warn)', padding: 2, marginLeft: 2, borderRadius: 3 }} title="Sair do modo Ver como">
          <Icon name="close" size={12} />
        </button>
      </div>
    );
  }

  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button
        onClick={() => setOpen(v => !v)}
        style={{ display: 'inline-flex', alignItems: 'center', gap: 7, padding: '5px 12px', border: '1px dashed var(--border)', borderRadius: 'var(--r-3)', background: open ? 'var(--bg-hover)' : 'transparent', color: open ? 'var(--text)' : 'var(--text-muted)', fontSize: 12 }}
        onMouseEnter={e => { e.currentTarget.style.background = 'var(--bg-hover)'; e.currentTarget.style.color = 'var(--text)'; }}
        onMouseLeave={e => { if (!open) { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--text-muted)'; } }}
      >
        <Icon name="user" size={14} />
        <span>Ver como…</span>
        <Icon name="chevron" size={11} style={{ transform: open ? 'rotate(180deg)' : 'none', transition: 'transform 0.15s' }} />
      </button>
      {open && (
        <div style={{ position: 'absolute', top: 'calc(100% + 8px)', left: '50%', transform: 'translateX(-50%)', width: 300, maxHeight: 380, background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 'var(--r-3)', boxShadow: '0 8px 32px rgba(0,0,0,0.18)', overflow: 'hidden', display: 'flex', flexDirection: 'column', zIndex: 200 }}>
          <div style={{ padding: '8px 10px', borderBottom: '1px solid var(--border)', flexShrink: 0 }}>
            <input autoFocus value={search} onChange={e => setSearch(e.target.value)} placeholder="Pesquisar colaborador…" style={{ width: '100%', padding: '5px 8px', borderRadius: 'var(--r-2)', border: '1px solid var(--border)', background: 'var(--bg)', fontSize: 12, color: 'var(--text)', outline: 'none' }} />
          </div>
          <div style={{ overflowY: 'auto', flex: 1 }} className="scrollbar">
            {Object.entries(groups).map(([tipo, list]) => (
              <div key={tipo}>
                <div style={{ padding: '8px 12px 3px', fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', textTransform: 'uppercase', letterSpacing: '0.08em' }}>{tipo}</div>
                {list.slice(0, 30).map(u => {
                  const display = u.nome_apresentar || u.nome_completo || '?';
                  const initials = display.trim().split(' ').filter(Boolean).slice(0, 2).map(p => p[0]).join('').toUpperCase();
                  return (
                    <button key={u.id} onClick={() => { onViewAs(u); setOpen(false); setSearch(''); }}
                      style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 10, padding: '6px 12px', background: 'transparent', color: 'var(--text)', fontSize: 12, textAlign: 'left' }}
                      onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-hover)'}
                      onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                    >
                      <div style={{ width: 28, height: 28, borderRadius: 6, background: 'var(--bg-hover)', border: '1px solid var(--border)', display: 'grid', placeItems: 'center', fontSize: 10, fontWeight: 700, flexShrink: 0, fontFamily: 'var(--font-mono)', color: 'var(--text-muted)' }}>{initials}</div>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{display}</div>
                        <div style={{ fontSize: 10, color: 'var(--text-dim)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{u.perfil_cargo || u.empresas?.[0]?.cargo || tipo}</div>
                      </div>
                    </button>
                  );
                })}
              </div>
            ))}
            {filtered.length === 0 && <div style={{ padding: 20, color: 'var(--text-dim)', fontSize: 12, textAlign: 'center' }}>Sem resultados</div>}
          </div>
        </div>
      )}
    </div>
  );
};

const Topbar = ({ title, subtitle, brand, onOpenChat, onOpenCmd, onToggleTheme, theme, right, livePill, user, onSwitchUser, onOpenDrawer, onNavigate, viewAs, onViewAs, onOpenSidebar }) => {
  const { isMobile, isTablet } = window.useBreakpoint();
  const isCompact = isMobile || isTablet;
  return (
    <header style={{
      height: 'var(--topbar-h)', flexShrink: 0,
      borderBottom: '1px solid var(--border)',
      background: 'var(--bg-elev)',
      display: 'flex', alignItems: 'center',
      padding: isCompact ? '0 12px' : '0 20px', gap: isCompact ? 10 : 16,
      position: 'sticky', top: 0, zIndex: 50,
    }}>
      {isCompact && (
        <button
          onClick={onOpenSidebar}
          className="btn btn-sm btn-ghost"
          style={{ padding: '6px', flexShrink: 0 }}
          title="Menu"
        >
          <Icon name="menu" size={18} />
        </button>
      )}

      <div style={{ minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
          <h1 className="font-display" style={{ margin: 0, fontSize: isCompact ? 16 : 20, fontWeight: 600, letterSpacing: '-0.01em' }}>{title}</h1>
          {subtitle && !isCompact && <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{subtitle}</span>}
        </div>
      </div>

      <div style={{ flex: isCompact ? 'none' : 1, display: 'flex', justifyContent: isCompact ? 'flex-start' : 'center', alignItems: 'center', padding: isCompact ? '0' : '0 16px' }}>
        <ViewAsPicker viewAs={viewAs} onViewAs={onViewAs} currentUser={user} />
      </div>

      {!isCompact && brand && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '4px 10px', border: '1px solid var(--border)', borderRadius: 999, fontSize: 12 }}>
          <span style={{ width: 6, height: 6, borderRadius: '50%', background: brand.color }} />
          <span style={{ fontFamily: 'var(--font-display)', fontWeight: 600, letterSpacing: '0.04em' }}>{brand.name}</span>
          <Icon name="chevron" size={12} style={{ color: 'var(--text-dim)' }} />
        </div>
      )}

      {!isCompact && (
        <button onClick={onOpenCmd} style={{
          display: 'flex', alignItems: 'center', gap: 10,
          padding: '6px 12px 6px 10px',
          border: '1px solid var(--border)',
          borderRadius: 'var(--r-3)',
          background: 'var(--surface-muted)',
          color: 'var(--text-muted)',
          fontSize: 12,
          minWidth: 260,
        }}>
          <Icon name="search" size={14} />
          <span style={{ flex: 1, textAlign: 'left' }}>Pesquisar ou pedir à Digi AI…</span>
          <kbd style={{ fontFamily: 'var(--font-mono)', fontSize: 10, padding: '2px 6px', border: '1px solid var(--border)', borderRadius: 4, background: 'var(--bg-elev)' }}>⌘K</kbd>
        </button>
      )}

      {right}

      {!isCompact && livePill && (
        <div style={{
          display: 'inline-flex', alignItems: 'center', gap: 8,
          padding: '4px 10px 4px 8px',
          borderRadius: 999,
          background: 'color-mix(in oklch, var(--success) 14%, transparent)',
          border: '1px solid color-mix(in oklch, var(--success) 34%, transparent)',
          fontSize: 11, fontFamily: 'var(--font-mono)',
          color: 'var(--success)',
          whiteSpace: 'nowrap',
        }} title="Sessões activas em produção · 24h">
          <span style={{
            width: 7, height: 7, borderRadius: '50%',
            background: 'var(--success)',
            boxShadow: '0 0 0 3px color-mix(in oklch, var(--success) 24%, transparent)',
            animation: 'ai-shimmer 2s ease-in-out infinite',
          }} />
          <span style={{ fontWeight: 600 }}>{livePill.live} ao vivo</span>
          <span style={{ opacity: 0.6 }}>·</span>
          <span style={{ opacity: 0.85 }}>{livePill.total} sessões 24h</span>
        </div>
      )}

      {!isCompact && (
        <button className="btn btn-sm btn-ghost" onClick={onToggleTheme} title="Alternar tema">
          <Icon name={theme === 'dark' ? 'sun' : 'moon'} size={16} />
        </button>
      )}

      {!isCompact && (
        <button className="btn btn-sm btn-ghost" style={{ position: 'relative' }} title="Notificações">
          <Icon name="bell" size={16} />
          <span style={{ position: 'absolute', top: 4, right: 4, width: 7, height: 7, borderRadius: '50%', background: 'var(--danger)' }} />
        </button>
      )}

      <button onClick={onOpenChat} className="btn btn-sm btn-ai" style={{ padding: '6px 12px', flexShrink: 0 }}>
        <Icon name="sparkle" size={14} />
        {!isMobile && 'Digi AI'}
      </button>

      <div style={{ display: 'flex', alignItems: 'center', gap: 8, paddingLeft: isCompact ? 0 : 8, borderLeft: isCompact ? 'none' : '1px solid var(--border)' }}>
        <UserMenu user={user} onSwitchUser={onSwitchUser} onOpenDrawer={onOpenDrawer} onNavigate={onNavigate} />
      </div>
    </header>
  );
};

// Mapa screen-id → NAV item, para o MobileSubNav de index.html
window.NAV_MAP = Object.fromEntries(
  NAV.filter(n => n.id).map(n => [n.id, n])
);

window.Sidebar = Sidebar;
window.Topbar = Topbar;
