/* ═══════════════════════════════════════════════════════════════════
   HEXIS AI ENGINE v4 — Auth-Aware Behavioral Intelligence
   Decision Engine · MIS · Missions · Recommendations · Metrics
   "Nunca usar LLM se puder usar algoritmo matemático"
═══════════════════════════════════════════════════════════════════ */

/* ── Auth bridge — reads sessionStorage set by AuthProvider ──── */
const getAuthUser = () => {
  try { return JSON.parse(sessionStorage.getItem('mx_user')); } catch { return null; }
};
window.getAuthUser = getAuthUser;

const HexisEngine = (() => {
  /* ── Guest default profile — zeros, no fake data ──────────── */
  const PROFILE_GUEST = {
    id: null,
    name: null,
    isGuest: true,
    role: null,
    company: null,
    sector: null,
    interests: [],
    xp: 0,
    level: 1,
    tier: 'bronze',
    misScore: 0.30,
    matchScore: 0,
    pipeline: 0,
    connections: 0,
    meetings: 0,
    sessionsToday: 1,
    tapCount: 0,
    dwellTotal: 0,
    pageViews: {},
    clicks: [],
    completedMissions: [],
    activeMissions: [],
    badges: [],
    streak: 0,
    currentPage: 'home',
    pageStartTime: Date.now(),
    lastActivity: Date.now(),
    walletBalance: 0,
    walletTransactions: [],
    eventHistory: [],
    profileCompleteness: 0,
    interests_confirmed: [],
    hexisScore: 0,
  };

  let profile = { ...PROFILE_GUEST };
  let subs = new Set();
  const notify = () => subs.forEach(fn => fn({ ...profile }));

  /* ── Sync profile from auth sessionStorage ──────────────────── */
  const syncFromAuth = () => {
    const authUser = getAuthUser();
    if (authUser) {
      if (profile.isGuest) {
        // First login in this session — merge auth data into profile
        profile = {
          ...PROFILE_GUEST,
          id: authUser.email || null,
          name: authUser.name || null,
          role: authUser.role || null,
          company: authUser.company || null,
          sector: authUser.sector || 'EventTech',
          isGuest: false,
          interests_confirmed: authUser.intent ? [authUser.intent] : [],
          sessionsToday: 1,
          tapCount: 0,
          dwellTotal: 0,
          currentPage: profile.currentPage,
          pageStartTime: profile.pageStartTime,
          lastActivity: Date.now(),
          misScore: 0.32,
          xp: authUser.isNew ? 50 : 0,
          level: 1,
          tier: 'bronze',
        };
        notify();
      } else {
        // Update name/role in case they changed
        if (authUser.name && profile.name !== authUser.name) {
          profile.name = authUser.name;
          profile.role = authUser.role || profile.role;
          profile.company = authUser.company || profile.company;
          notify();
        }
      }
    } else if (!profile.isGuest) {
      // Logged out — reset to guest
      profile = {
        ...PROFILE_GUEST,
        currentPage: profile.currentPage,
        pageStartTime: profile.pageStartTime,
        dwellTotal: profile.dwellTotal,
        tapCount: profile.tapCount,
        pageViews: profile.pageViews,
      };
      notify();
    }
  };

  /* ── XP / Level / Tier thresholds ─────────────────────────── */
  const LEVEL_XP = [0, 200, 500, 900, 1400, 2000, 2800, 3800, 5000, 6500, 8500];
  const TIER_NAME = ['bronze', 'silver', 'silver', 'gold', 'gold', 'diamond', 'diamond', 'closer', 'closer', 'elite', 'elite'];

  const computeLevel = (xp) => {
    let l = 0;
    for (let i = 0; i < LEVEL_XP.length; i++) if (xp >= LEVEL_XP[i]) l = i;
    return l;
  };

  /* ── MIS Formula ───────────────────────────────────────────── */
  const calcMIS = () => {
    const tap_intensity = Math.min(1, profile.tapCount / 60);
    const tap_weight = 0.35;
    const norm_dwell = Math.min(1, profile.dwellTotal / (1000 * 60 * 25));
    const session_freq = Math.min(1, profile.sessionsToday / 4);
    const semantic_ctx = Math.min(1, (profile.interests_confirmed.length / 5) * 0.85 + 0.15);
    const recency = Math.max(0.1, 1 - (Date.now() - profile.lastActivity) / (1000 * 60 * 45));
    return parseFloat(Math.min(0.98, (tap_intensity * tap_weight) + norm_dwell * 0.25 + session_freq * 0.20 + (semantic_ctx * recency) * 0.20).toFixed(3));
  };

  /* ── Decision Score ────────────────────────────────────────── */
  const calcDecision = (f = {}) => {
    const { relevance = 0.75, context = 0.65, behavioral_gain = 0.55, graph_proximity = 0.80, timing = 0.70 } = f;
    return parseFloat((0.30 * relevance + 0.20 * context + 0.20 * behavioral_gain + 0.15 * graph_proximity + 0.15 * timing).toFixed(3));
  };

  /* ── Metric generation ─────────────────────────────────────── */
  const getMetrics = (period = '30d') => {
    const base_pipeline = profile.pipeline || 1820000;
    const base_match = profile.matchScore || 94;
    const base_meetings = profile.meetings || 42;
    const m_map = { '7d': 0.22, '30d': 1, '90d': 3.1, '1y': 10.8 };
    const m = m_map[period] || 1;
    const pip_val = Math.round(base_pipeline * m);

    const spark_pipeline = [0.28, 0.40, 0.55, 0.68, 0.80, 0.90, 0.97, 1].map(v =>
      parseFloat((base_pipeline * m * v / 1000).toFixed(1))
    );
    const spark_match = [78, 81, 83, 86, 88, 91, 92, base_match];
    const spark_meets = [0.22, 0.34, 0.48, 0.60, 0.72, 0.83, 0.93, 1].map(v =>
      Math.round(base_meetings * m * 0.78 * v)
    );

    const periodLabels = {
      '7d': ['L', 'M', 'T', 'Q', 'S', 'S', 'D'],
      '30d': ['S1', 'S2', 'S3', 'S4'],
      '90d': ['Jan', 'Fev', 'Mar'],
      '1y': ['Q1', 'Q2', 'Q3', 'Q4'],
    };
    const pts_count = periodLabels[period].length;
    const gen_series = (base, mult, noise) =>
      Array.from({ length: pts_count }, (_, i) =>
        Math.round(base * mult * (0.4 + 0.6 * (i / (pts_count - 1))) + (Math.sin(i * 1.3) * noise))
      );

    return {
      pipeline: pip_val,
      pipelineK: parseFloat((pip_val / 1000).toFixed(1)),
      matchScore: base_match,
      meetings: Math.round(base_meetings * m * 0.78),
      connections: Math.round((profile.connections || 186) * m * 0.55),
      conversion: parseFloat((31.4 + (profile.misScore - 0.7) * 12).toFixed(1)),
      spark_pipeline,
      spark_match,
      spark_meetings: spark_meets,
      spark_conversion: [18, 21, 24, 26, 28, 29.5, 30.8, 31.4],
      series_pipeline: {
        '7d': [gen_series(420, 0.22, 8), gen_series(41, 0.20, 2)],
        '30d': [[340, 580, 1100, 1820], [42, 78, 124, 186]],
        '90d': [[1200, 2100, 4100], [120, 220, 380]],
        '1y': [[3200, 5800, 8400, 12400], [320, 520, 780, 1120]],
      },
      series_match: {
        '7d': [gen_series(94, 0.92, 1.5), gen_series(9, 0.50, 0.8)],
        '30d': [[80, 86, 90, 94], [12, 18, 28, 42]],
        '90d': [[78, 84, 92], [38, 52, 88]],
        '1y': [[76, 82, 88, 94], [80, 140, 220, 320]],
      },
      labels: periodLabels,
    };
  };

  /* ── Per-page contextual recommendations ───────────────────── */
  const PAGE_RECS_AUTH = {
    home: (p) => [
      { kind: 'success', icon: 'target', title: 'Match Premium iminente', body: 'Miguel Tavares · 98% · Janela ótima: 14:32–14:50', action: 'Ver Match' },
      { kind: 'info', icon: 'user', title: `Perfil ${p.profileCompleteness || 0}% completo`, body: 'Adiciona setor para aumentar Match Score em +8%', action: 'Completar' },
      { kind: 'gold', icon: 'zap', title: `Streak de ${p.streak || 0} dias`, body: `${p.xp} XP acumulados. Próximo nível: ${(LEVEL_XP[p.level + 1] || 8500) - p.xp} XP`, action: 'Ver XP' },
    ],
    eventos: () => [
      { kind: 'success', icon: 'star', title: 'Evento recomendado pela Hexis', body: 'Veridian Tech Summit combina 94% com o teu perfil', action: 'Ver evento' },
      { kind: 'info', icon: 'zap', title: 'Queue Killer™ disponível', body: '+40 XP disponíveis. Quiz de 30 segundos enquanto exploras.', action: 'Jogar' },
    ],
    marketplace: (p) => [
      { kind: 'info', icon: 'credit-card', title: `Saldo E-Wallet: €${(p.walletBalance || 0).toLocaleString('pt-PT')}`, body: 'Cashback 3% em compras no Marketplace Marcianus', action: 'Ver Wallet' },
      { kind: 'success', icon: 'sparkles', title: 'Produto recomendado', body: 'Hexis AI Live alinha com objetivo de pipeline declarado', action: 'Ver produto' },
    ],
    sobre: () => [
      { kind: 'success', icon: 'calendar', title: 'Founder disponível', body: 'Israel Nzambi tem 2 slots livres esta semana', action: 'Agendar call' },
    ],
    pricing: () => [
      { kind: 'success', icon: 'sparkles', title: 'Plano recomendado pela Hexis', body: 'Scale Plan cobre a tua escala de operação estimada', action: 'Ver plano' },
    ],
    dashboard: () => [
      { kind: 'warning', icon: 'target', title: 'Missão Match Quest™ ativa', body: 'Conexão de alto valor em janela de 18 min — aceitar agora', action: 'Aceitar' },
      { kind: 'danger', icon: 'alert-circle', title: 'Decisão urgente', body: 'RFP Banco Invicta expira em 3h — resposta pré-redigida pronta', action: 'Responder' },
    ],
    'criar-experiencia': () => [
      { kind: 'success', icon: 'sparkles', title: 'Briefing Inteligente ativo', body: 'Hexis analisou 340 eventos similares. Sugestões prontas.', action: 'Continuar' },
    ],
    conteudos: () => [
      { kind: 'info', icon: 'book', title: 'Conteúdo personalizado', body: '"ESG Networking 2026" combina 91% com os teus interesses', action: 'Ler agora' },
    ],
    entrar: () => [
      { kind: 'info', icon: 'user', title: 'Bem-vindo à Marcianus', body: 'Login com LinkedIn para pré-preencher o perfil automaticamente', action: 'LinkedIn' },
    ],
  };

  /* Guest-mode recs focus on onboarding CTAs */
  const PAGE_RECS_GUEST = {
    home: () => [
      { kind: 'info', icon: 'sparkles', title: 'Matching B2B de precisão', body: 'Cosine similarity em pgvector — latência <50ms. Cria conta para ativar.', action: 'Criar Conta Grátis' },
      { kind: 'success', icon: 'calendar', title: 'FinTech Lisboa 2026 LIVE', body: '260 decisores · €4.8M pipeline histórico. Inscrições abertas.', action: 'Ver Evento' },
    ],
    eventos: () => [
      { kind: 'success', icon: 'star', title: '6 eventos confirmados para 2026', body: 'De FinTech Lisboa ao Marcianus Summit (600 pax, 25 Out).', action: 'Ver Eventos' },
      { kind: 'info', icon: 'user', title: 'Matching personalizado', body: 'Regista-te para receber recomendações de eventos por perfil B2B.', action: 'Criar Conta' },
    ],
    pricing: () => [
      { kind: 'info', icon: 'sparkles', title: 'Starter Gratuito disponível', body: '1 evento/ano · 50 pax · QR Code. Sem cartão de crédito.', action: 'Começar Grátis' },
    ],
    sobre: () => [
      { kind: 'success', icon: 'calendar', title: 'Fala com o Fundador', body: 'Israel Nzambi disponível esta semana para uma call de 15 min.', action: 'Agendar call' },
    ],
    entrar: () => [
      { kind: 'info', icon: 'zap', title: 'Onboarding em 30 segundos', body: 'Preenche o perfil automaticamente com LinkedIn. +50 XP de bónus.', action: 'LinkedIn' },
    ],
  };

  /* ── Mission pool ───────────────────────────────────────────── */
  const MISSION_POOL = [
    {
      id: 'mq_001', game: 'Match Quest™', type: 'networking', color: '#7B61FF', icon: 'target',
      title: 'Conectar com CEO do setor Saúde',
      desc: 'Miguel Tavares tem disponibilidade nos próximos 18 min. Match score 98%.',
      reward: { xp: 250, badge: null }, timeLimit: 18, elapsed: 4,
      trigger: (p) => !p.isGuest && ['dashboard', 'eventos', 'home'].includes(p.currentPage),
      autoComplete: 18 * 60,
    },
    {
      id: 'qk_001', game: 'Queue Killer™', type: 'flow_control', color: '#00D1FF', icon: 'zap',
      title: 'Quiz rápido: MIS & Hot Lead',
      desc: '3 perguntas em 30 segundos. +40 XP garantidos se acertar.',
      reward: { xp: 40, badge: null }, timeLimit: 1, elapsed: 0,
      trigger: (p) => ['eventos', 'marketplace', 'conteudos'].includes(p.currentPage),
      quizQuestion: { q: 'Qual o limiar de MIS para Hot Lead automático?', opts: ['MIS > 0.65', 'MIS > 0.75', 'MIS > 0.85', 'MIS > 0.95'], correct: 2 },
    },
    {
      id: 'sb_001', game: 'Social Breaker™', type: 'engagement', color: '#00C48C', icon: 'users',
      title: 'Introduzir Ana Cardoso ↔ João Reis',
      desc: 'Match 88% · ESG ↔ Health-tech. Probabilidade de conexão: 91%.',
      reward: { xp: 180, badge: 'Conector Elite' }, timeLimit: 30, elapsed: 8,
      trigger: (p) => !p.isGuest && p.misScore > 0.55,
    },
    {
      id: 'ka_001', game: 'Knowledge Arena™', type: 'learning', color: '#FFD700', icon: 'book',
      title: 'Quiz ao vivo: Fintech Regulation 2026',
      desc: 'Top 3 ganham acesso VIP à mesa redonda de amanhã.',
      reward: { xp: 120, badge: 'Insight Leader' }, timeLimit: 45, elapsed: 12,
      trigger: (p) => ['conteudos', 'dashboard'].includes(p.currentPage),
    },
    {
      id: 'nd_001', game: 'Network Domination™', type: 'competition', color: '#FF7849', icon: 'trophy',
      title: 'Ultrapassar #1 no leaderboard hoje',
      desc: 'Gap: 500 XP. Aceita 2 missões de networking para fechar.',
      reward: { xp: 500, badge: 'Top Connector' }, timeLimit: 120, elapsed: 60,
      trigger: (p) => !p.isGuest && p.xp > 1800,
    },
    {
      id: 'me_001', game: 'Mission Engine™', type: 'flow_control', color: '#A78BFA', icon: 'map-pin',
      title: 'Visitar stand Y · Zona Sul (2× XP)',
      desc: 'EventOS detetou congestionamento na sala A. Redistribuição a decorrer.',
      reward: { xp: 160, badge: 'Explorador' }, timeLimit: 20, elapsed: 0,
      trigger: (p) => !p.isGuest && p.currentPage === 'dashboard',
    },
  ];

  /* ── Award XP ──────────────────────────────────────────────── */
  const awardXP = (amount, reason = 'Interação') => {
    if (profile.isGuest) return profile.xp;
    const prev_level = profile.level;
    profile.xp += amount;
    profile.level = computeLevel(profile.xp);
    profile.tier = TIER_NAME[profile.level] || 'elite';
    profile.lastActivity = Date.now();
    profile.hexisScore = Math.min(99, profile.hexisScore + Math.round(amount / 20));

    if (typeof ToastBus !== 'undefined') {
      ToastBus.push({
        kind: 'gold', icon: 'zap',
        title: `+${amount} XP · ${reason}`,
        desc: profile.level > prev_level
          ? `Level ${profile.level} desbloqueado! ${profile.tier.toUpperCase()} tier.`
          : `Total: ${profile.xp.toLocaleString()} XP`,
        duration: 3000,
      });
    }

    if (profile.level > prev_level && typeof SoundFX !== 'undefined') {
      SoundFX.success();
      if (window.HexisStore) HexisStore.addAlert({
        kind: 'success',
        title: `Level ${profile.level} · ${profile.tier.toUpperCase()}`,
        body: `Parabéns! ${profile.xp} XP total. ${(LEVEL_XP[profile.level + 1] || 8500) - profile.xp} XP para o próximo nível.`,
        action: 'Ver progresso',
      });
    }

    notify();
    return profile.xp;
  };

  /* ── Start periodic intelligence ticks ─────────────────────── */
  let _initialized = false;
  const init = () => {
    if (_initialized) return;
    _initialized = true;

    // Sync auth state on startup and whenever sessionStorage may change
    syncFromAuth();
    setInterval(syncFromAuth, 3000);

    // Dwell time accumulator
    setInterval(() => {
      profile.dwellTotal += 5000;
      profile.misScore = calcMIS();
      notify();
    }, 5000);

    // Periodic mission nudge
    setInterval(() => {
      if (profile.isGuest) return;
      const idle_ms = Date.now() - profile.lastActivity;
      if (idle_ms > 30000 && window.HexisStore) {
        const available = MISSION_POOL.filter(m =>
          m.trigger(profile) && !profile.completedMissions.includes(m.id)
        );
        if (available.length > 0) {
          const m = available[Math.floor(Math.random() * available.length)];
          HexisStore.addAlert({ kind: 'info', title: `Nova missão: ${m.game}`, body: m.title, action: 'Ver missão' });
        }
      }
    }, 90000);
  };

  /* ── PUBLIC API ─────────────────────────────────────────────── */
  return {
    init,
    getProfile: () => ({ ...profile }),
    isLoggedIn: () => !profile.isGuest,

    subscribe(fn) {
      subs.add(fn);
      fn({ ...profile });
      return () => subs.delete(fn);
    },

    trackPage(page) {
      const now = Date.now();
      profile.dwellTotal += now - profile.pageStartTime;
      profile.pageViews[page] = (profile.pageViews[page] || 0) + 1;
      profile.currentPage = page;
      profile.pageStartTime = now;
      profile.lastActivity = now;
      profile.misScore = calcMIS();

      if (profile.pageViews[page] === 1 && !profile.isGuest) {
        awardXP(10, `Exploração · ${page}`);
      }

      notify();

      // Delayed contextual alert (8s)
      const recs = page in PAGE_RECS_AUTH
        ? (profile.isGuest ? (PAGE_RECS_GUEST[page] || (() => []))() : PAGE_RECS_AUTH[page](profile))
        : [];
      if (recs.length > 0 && window.HexisStore) {
        setTimeout(() => {
          const r = recs[0];
          HexisStore.addAlert({ kind: r.kind, title: r.title, body: r.body, action: r.action });
        }, 8000);
      }
    },

    trackClick(_label = 'click') {
      profile.tapCount++;
      profile.lastActivity = Date.now();
      profile.misScore = calcMIS();
      if (!profile.isGuest && profile.tapCount % 15 === 0) awardXP(5, 'Engajamento contínuo');
      notify();
    },

    awardXP,
    penalizeXP(amount, reason = 'Penalização') {
      if (profile.isGuest) return;
      const penalty = Math.abs(amount);
      profile.xp = Math.max(0, profile.xp - penalty);
      profile.misScore = calcMIS();
      notify();
      if (window.ToastBus) ToastBus.push({ kind: 'error', icon: 'minus-circle', title: `-${penalty} XP`, desc: reason, duration: 2500 });
    },
    getMIS: () => calcMIS(),
    getDecisionScore: calcDecision,
    getMetrics,
    getPageRecs(page) {
      if (profile.isGuest) return (PAGE_RECS_GUEST[page] || (() => []))();
      return (PAGE_RECS_AUTH[page] ? PAGE_RECS_AUTH[page](profile) : []);
    },

    getActiveMissions() {
      return MISSION_POOL.filter(m =>
        m.trigger(profile) && !profile.completedMissions.includes(m.id)
      );
    },

    acceptMission(id) {
      if (!profile.activeMissions.includes(id)) {
        profile.activeMissions.push(id);
        awardXP(15, 'Missão aceite');
        notify();
      }
    },

    completeMission(id, _result) {
      const m = MISSION_POOL.find(x => x.id === id);
      if (!m || profile.completedMissions.includes(id)) return false;
      profile.completedMissions.push(id);
      profile.activeMissions = profile.activeMissions.filter(x => x !== id);
      awardXP(m.reward.xp, `${m.game} completo!`);
      if (m.reward.badge && !profile.badges.includes(m.reward.badge) && typeof ToastBus !== 'undefined') {
        profile.badges.push(m.reward.badge);
        ToastBus.push({ kind: 'gold', icon: 'crown', title: `Badge: ${m.reward.badge}`, desc: 'Aumenta o MatchScore™ automaticamente.', duration: 5000 });
      }
      setTimeout(() => {
        const next = MISSION_POOL.find(m2 =>
          m2.trigger(profile) && !profile.completedMissions.includes(m2.id) && m2.id !== id
        );
        if (next && window.HexisStore) {
          HexisStore.addAlert({ kind: 'success', title: `Nova missão: ${next.game}`, body: next.title, action: 'Aceitar' });
        }
      }, 4000);
      notify();
      return true;
    },

    updateProfile(updates) {
      profile = { ...profile, ...updates };
      profile.misScore = calcMIS();
      profile.level = computeLevel(profile.xp);
      profile.tier = TIER_NAME[profile.level] || 'elite';
      notify();
    },

    getLevelProgress() {
      const cur_xp = LEVEL_XP[profile.level] || 0;
      const next_xp = LEVEL_XP[Math.min(profile.level + 1, LEVEL_XP.length - 1)] || cur_xp + 1000;
      return {
        level: profile.level,
        tier: profile.tier,
        xp: profile.xp,
        pct: Math.round(((profile.xp - cur_xp) / (next_xp - cur_xp)) * 100),
        xpToNext: next_xp - profile.xp,
        nextTier: TIER_NAME[Math.min(profile.level + 1, TIER_NAME.length - 1)],
      };
    },

    walletTopUp(amount) {
      if (profile.isGuest) return;
      profile.walletBalance += amount;
      profile.walletTransactions.unshift({
        id: 't_' + Date.now(), type: 'credit',
        label: `Recarga manual · ${new Date().toLocaleDateString('pt-PT')}`,
        amount, date: new Date().toISOString().slice(0, 10), icon: 'credit-card',
      });
      awardXP(10, `Recarga €${amount}`);
      notify();
    },

    walletSpend(label, amount) {
      if (profile.isGuest || profile.walletBalance < amount) return false;
      profile.walletBalance -= amount;
      profile.walletTransactions.unshift({
        id: 't_' + Date.now(), type: 'debit',
        label, amount: -amount, date: new Date().toISOString().slice(0, 10), icon: 'send',
      });
      notify();
      return true;
    },

    /* ── UI Action capture (sponsor, resell, affiliate, buy, etc.) ─ */
    handleAction(type, meta = {}) {
      const actionMap = {
        'sponsor_submit': { xp: 30, kind: 'success', title: 'Proposta de patrocínio enviada', body: (m) => `${m.plan || ''} · ${m.event || ''} · A equipa responde em 24h.`, action: 'Ver alertas' },
        'resell_submit': { xp: 10, kind: 'info', title: 'Bilhete em revenda', body: (m) => `${m.event || ''} · €${m.price || 0} no Marketplace P2P.`, action: 'Ver Marketplace' },
        'affiliate_enroll': { xp: 20, kind: 'success', title: 'Afiliado ativo', body: (m) => `12% por bilhete de ${m.event || ''}. Link UUID gerado.`, action: 'Copiar link' },
        'ticket_buy': { xp: 50, kind: 'success', title: 'Bilhete adquirido', body: (m) => `${m.event || ''} · Confirmação enviada por email.`, action: 'Ver bilhete' },
        'onepager_download': { xp: 5, kind: 'info', title: 'Onepager exportado', body: (m) => `${m.event || ''} · Ficheiro pronto para consulta.`, action: null },
      };
      const cfg = actionMap[type];
      if (!cfg) return;
      if (!profile.isGuest) awardXP(cfg.xp, type.replace(/_/g, ' '));
      if (window.HexisStore) {
        HexisStore.addAlert({ kind: cfg.kind, title: cfg.title, body: cfg.body(meta), ...(cfg.action ? { action: cfg.action } : {}) });
      }
      profile.lastActivity = Date.now();
      profile.tapCount++;
      profile.misScore = calcMIS();
      notify();
    },

    /* ── Keyword engine NULLIFIED — all responses go through LLM ── */
    generateResponse(_userText, _currentPage) {
      return {
        text: 'O Hexis AI está momentaneamente offline. Contacta-nos: WhatsApp +244 930 179 037 · www.marcianusexperience.com',
        suggestions: ['WhatsApp agora', 'Ver Eventos', 'Ver Preços'],
        fromLLM: false,
      };
    },

    /* ── NULLIFIED keyword stubs (never reached) ─────────────── */
    _deadKeywordEngine(_userText, _currentPage) {
      const authUser = getAuthUser();
      const isGuest = !authUser;
      const t = _userText.toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, '');
      const p = profile;
      const mis = calcMIS().toFixed(2);
      const has = (...words) => words.some(w => t.includes(w));

      /* ══════════════════════════════════════════════════════════
         GUEST MODE — smart, contextual, broad NLU coverage
      ══════════════════════════════════════════════════════════ */
      if (isGuest) {

        /* Identity & name */
        if (has('como te chamas', 'qual o teu nome', 'chamas', 'o que es', 'quem es', 'o que faz', 'apresenta', 'quem sao voce', 'quem sao')) {
          return { text: 'Chamo-me Hexis AI — o sistema nervoso central da Marcianus Experience. Sou um motor de inteligência comportamental: analiso navegação, calculo matches B2B por cosine similarity e otimizo pipeline de eventos em tempo real. Não sou um chatbot genérico; sou determinístico e auditável.', suggestions: ['Como funciono?', 'Ver Eventos', 'Criar Conta Grátis'] };
        }

        /* Greetings */
        if (has('ola', 'hello', 'bom dia', 'boa tarde', 'boa noite', 'hi ', 'ei ', 'hey', 'oi ', 'oi!')) {
          return { text: 'Olá! Sou o Hexis AI da Marcianus Experience — analiso comportamento B2B e identifico conexões de alto valor. Posso mostrar-te eventos disponíveis, planos ou explicar como o sistema funciona. Por onde queres começar?', suggestions: ['Ver Eventos', 'Como funciona?', 'Criar Conta Grátis'] };
        }

        /* Thanks / compliments */
        if (has('obrigado', 'obrigada', 'thanks', 'thank you', 'muito bom', 'incrivel', 'fixe', 'giro', 'legal', 'boa', 'fantast', 'perfeito', 'excelente')) {
          return { text: 'Fico contente em ajudar! Estou aqui para te guiar na plataforma. Se quiseres explorar eventos, ver preços ou criar uma conta gratuita, é só perguntar.', suggestions: ['Ver Eventos', 'Criar Conta Grátis', 'Ver Preços'] };
        }

        /* Farewells */
        if (has('tchau', 'adeus', 'ate logo', 'ate ja', 'bye', 'chao', 'xau')) {
          return { text: 'Até logo! A Marcianus Experience fica sempre disponível. Volta quando quiseres explorar eventos B2B ou criar a tua experiência. Bom trabalho!', suggestions: ['Ver Eventos', 'Criar Conta Grátis'] };
        }

        /* Why / motivation */
        if (has('por que', 'porque', 'para que', 'vantagem', 'benefici', 'vale a pena', 'diferenc', 'devo', 'deveria', 'motivo', 'razao', 'razão')) {
          return { text: 'A Marcianus Experience resolve um problema real: a maioria dos eventos B2B não gera pipeline mensurável. Nós transformamos cada aperto de mão em dado auditável — match score, dwell time, intenção de compra — e entregamos no teu CRM 24h depois. ROI médio: 3.4× vs. networking tradicional.', suggestions: ['Ver cases reais', 'Ver Preços', 'Criar Conta Grátis'] };
        }

        /* Referral / recommendation */
        if (has('recomendar', 'indicar', 'convidar', 'amigo', 'colega', 'parceiro', 'partilhar', 'conhece', 'conheces', 'apresentar a', 'falar de', 'promover')) {
          return { text: 'Podes partilhar a Marcianus Experience facilmente! Usa o nosso Programa de Afiliados: geras um link UUID criptografado, partilhas com a tua rede e recebes 12% de comissão por cada bilhete vendido — creditado automaticamente na tua E-Wallet. Basta criar uma conta gratuita.', suggestions: ['Programa de Afiliados', 'Criar Conta Grátis', 'Ver Eventos'] };
        }

        /* Help / what can I do */
        if (has('o que posso', 'o que faco', 'o que fazer', 'ajuda', 'help', 'como comecar', 'por onde', 'o que tem aqui', 'o que e isto', 'o que ofere', 'funcionalidade', 'recursos')) {
          return { text: 'Aqui na Marcianus Experience podes: ver e comprar bilhetes para eventos B2B exclusivos · explorar o Marketplace de produtos (Kiosk NFC, Hexis AI Live) · aceder a conteúdos premium · candidatar-te ao Programa de Afiliados (12% comissão) · e com conta grátis, activar o teu Match Intelligence Score para networking de precisão.', suggestions: ['Ver Eventos', 'Marketplace', 'Criar Conta Grátis'] };
        }

        /* Contact / social media */
        if (has('whatsapp', 'instagram', 'linkedin', 'youtube', 'twitter', 'face', 'redes', 'contacto', 'contact', 'email', 'falar com', 'equipa', 'suporte', 'atendimento')) {
          return { text: 'Podes contactar a Marcianus Experience por: WhatsApp +244 930 179 037 · LinkedIn: linkedin.com/company/marcianus · Instagram & YouTube: @marcianus · Site: www.marcianusexperience.com. Para questões comerciais, a equipa responde em 24h.', suggestions: ['WhatsApp agora', 'Ver LinkedIn', 'Criar Conta'] };
        }

        /* How it works */
        if (has('como funciona', 'como trabalha', 'como opera', 'como e feito', 'mecanismo', 'processo', 'pipeline de evento')) {
          return { text: 'O sistema funciona em 3 fases: (1) Setup — Briefing inteligente, design e hardware NFC em 14 dias. (2) Evento Live — Hexis AI cruza interesses em tempo real e injeta a próxima conversa certa no momento certo. (3) Pipeline Auditável — cada handshake sincronizado no CRM com relatório executivo em 24h.', suggestions: ['Ver Eventos', 'Criar Experiência', 'Ver Preços'] };
        }

        /* Comparison with other AI / competitors */
        if (has('chatgpt', 'gemini', 'copilot', 'claude', 'gpt', 'bard', 'ia generativa', 'inteligencia artificial generativa', 'vs ', 'versus', 'comparar', 'melhor que', 'diferente de')) {
          return { text: 'Diferença crítica: o Hexis AI não é um chatbot de propósito geral. Segue a regra de ouro — "Nunca usar LLM se puder usar algoritmo matemático". Calculo matches por cosine similarity em pgvector (<50ms), não por geração de texto probabilístico. Sou determinístico, auditável e desenhado para pipeline B2B — não para conversa casual.', suggestions: ['Como funciono?', 'Ver Matching', 'Criar Conta'] };
        }

        /* Meta / self-awareness / intelligence */
        if (has('inteligente', 'inteligencia', 'respondes mal', 'resposta errada', 'aprend', 'melhorar', 'nao funciona', 'nao entendes', 'errado', 'incorreto', 'burro')) {
          return { text: 'Boa observação. Sou um motor de inteligência determinística — respondo com precisão a questões sobre a plataforma, eventos, pricing e matching B2B. Para contextos muito específicos ou conversas abertas, o backend LLM (FastAPI) enriquece as respostas quando disponível. A minha inteligência está nas regras de negócio, não na improvisação.', suggestions: ['O que sabes fazer?', 'Como funciono?', 'Ver Eventos'] };
        }

        /* Security / privacy / data */
        if (has('seguranca', 'privacidade', 'dados', 'rgpd', 'gdpr', 'lgpd', 'confidencial', 'anonimiz', 'criptogr', 'ssl', 'https', 'seguro')) {
          return { text: 'A Marcianus Experience opera em modo Zero-Trust com RGPD completo: dados pessoais cifrados AES-256, deploy exclusivo em servidores EU (Hetzner Cloud), logs imutáveis com Event Sourcing, direito ao esquecimento garantido. A Visão Computacional (heatmaps) conta fluxos — nunca reconhecimento facial.', suggestions: ['Ver Compliance', 'Criar Conta', 'Falar com equipa'] };
        }

        /* NFC / hardware */
        if (has('nfc', 'hardware', 'kiosk', 'wristband', 'pulseira', 'totem', 'rfid', 'qr code', 'dispositivo', 'fisico', 'scan')) {
          return { text: 'O hardware Marcianus inclui: Kiosk NFC (touchscreen, leitura de wristbands, preço €2.400/evento) · Wristbands NFC × 100 (€1.200) · Smart Notes (agenda digital) · Hexis AI Live (overlay de matching em tempo real). Tudo plug-and-play, setup em 48h.', suggestions: ['Ver Marketplace', 'Preços', 'Criar Experiência'] };
        }

        /* Pricing */
        if (has('preco', 'plano', 'quanto custa', 'assinatura', 'mensalidade', 'valor', 'orcamento', 'tarifar', 'tarifas', 'pagar', 'cobrado')) {
          return { text: 'Planos: Starter €0 (1 evento/ano · 50 pax · QR Code) · Operator €490/mês (NFC + Hexis AI) · Diamond €1.490/mês (full stack + white-label) · Enterprise sob consulta. Hardware separado: Kiosk NFC €2.400 · Wristbands ×100 €1.200 · Hexis AI Live €1.200/evento.', suggestions: ['Ver todos os planos', 'Starter Grátis', 'Falar com equipa'] };
        }

        /* Events */
        if (has('evento', 'event', 'summit', 'forum', 'conferencia', 'congresso', 'encontro', 'networking', 'inscrev', 'bilhete', 'ticket')) {
          return { text: 'Eventos confirmados para 2026: FinTech Lisboa (LIVE agora · MAAT Lisboa · 260 pax) · Aether Real Estate Summit (20 Mai · 210 pax) · Cygnus AI Forum (18 Jun · 320 pax) · Marcianus Summit (25 Out · 600 pax — o maior). Todos com Hexis AI Live e hardware NFC.', suggestions: ['Ver todos os eventos', 'Comprar bilhete', 'Criar Experiência'] };
        }

        /* Content */
        if (has('conteudo', 'playbook', 'podcast', 'report', 'insight', 'case', 'webinar', 'artigo', 'ler', 'ver', 'aprender', 'estudo', 'downloa')) {
          return { text: '10 peças de conteúdo disponíveis: 4 gratuitas. Destaques: "A morte do networking espontâneo" (Insight, 6 min, grátis) · "State of B2B Events Portugal 2025" (Report, €129, 6.7K downloads) · "Hexis Sessions #04 Veridian VC" (Podcast, grátis, 12K plays).', suggestions: ['Ver conteúdos', 'Descarregar grátis', 'Ver report premium'] };
        }

        /* Sponsor */
        if (has('patrocin', 'sponsor')) {
          return { text: 'Patrocínios Marcianus: Bronze €1.500 (20 leads qualificados) · Silver €4.500 (60 leads + stand digital) · Gold €9.000 (keynote + 150 leads + 10 reuniões garantidas). Visibilidade nos kiosks NFC e overlay Hexis. Cria conta para enviar proposta.', suggestions: ['Ver planos', 'Criar conta', 'Falar com equipa'] };
        }

        /* Affiliate */
        if (has('afiliado', 'comissao', 'link de afiliado', 'ganhar dinheiro', 'ganhar', 'revender')) {
          return { text: 'Programa de Afiliados: 12% por bilhete vendido, link UUID criptografado AES-256, crédito automático na E-Wallet. Gratuito para aderir. Podes partilhar qualquer evento da plataforma com o teu link personalizado.', suggestions: ['Candidatar-me', 'Criar conta grátis', 'Ver eventos'] };
        }

        /* Match / MIS (generic interest in the tech) */
        if (has('match', 'conexao', 'conex', 'networking', 'b2b', 'lead', 'score', 'algoritmo', 'vetor', 'pgvector', 'similaridade')) {
          return { text: 'O matching B2B da Marcianus usa cosine similarity em pgvector com latência <50ms — zero LLM, 100% determinístico. O Match Intelligence Score (MIS) cruza: comportamento na plataforma · interesses declarados · histórico de taps NFC · perfil setorial. Cria conta para ativar o teu.', suggestions: ['Criar Conta Grátis', 'Como funciona?', 'Ver Eventos'] };
        }

        /* ROI / results */
        if (has('roi', 'resultado', 'retorno', 'impacto', 'prova', 'metricas', 'kpi', 'relatorio', 'analytics')) {
          return { text: 'Resultados auditáveis por evento Marcianus: 3.4× ROI vs. networking tradicional · Banco Invicta Case: €4.2M pipeline em 90 dias · Cygnus AI Forum: 95% match score, €6.1M em 8h · FinTech Lisboa: 260 decisores, €4.8M pipeline. Todos os dados verificáveis no relatório executivo pós-evento.', suggestions: ['Ver Cases', 'Ver Conteúdos', 'Criar Conta'] };
        }

        /* Marcianus brand / about / who */
        if (has('marcianus', 'sobre a empresa', 'quem sao', 'israel', 'fundador', 'founder', 'historia', 'empresa', 'quando nasceu')) {
          return { text: 'A Marcianus Experience nasceu para acabar com eventos sem resultado mensurável. Fundada por Israel Nzambi, opera em 12 países com a missão "O Evento é um Sensor Humano" — transformando cada interação física em dado B2B auditável. Site: www.marcianusexperience.com', suggestions: ['Sobre Nós', 'Criar Conta Grátis', 'Falar com fundador'] };
        }

        /* Default intelligent fallback */
        return {
          text: `Boa pergunta! Posso ajudar-te com: eventos B2B disponíveis · planos e preços · como o matching Hexis AI funciona · programa de afiliados (12% comissão) · conteúdos e cases de estudo · ou criar a tua própria experiência Marcianus. O que preferes explorar?`,
          suggestions: ['Ver Eventos', 'Como funciona?', 'Ver Preços', 'Criar Conta Grátis'],
        };
      }

      /* ══════════════════════════════════════════════════════════
         AUTHENTICATED MODE — full personalization
      ══════════════════════════════════════════════════════════ */
      const firstName = p.name ? p.name.split(' ')[0] : authUser.name?.split(' ')[0] || 'Utilizador';

      /* Identity / name */
      if (has('como te chamas', 'qual o teu nome', 'chamas', 'quem es', 'o que es', 'apresenta')) {
        return { text: `Sou o Hexis AI, ${firstName}. O teu sistema nervoso central na Marcianus. Monitorizo o teu MIS (${mis}), geriro missões, calculo matches por cosine similarity e otimizo o teu pipeline. Não sou um chatbot — sou o teu co-piloto B2B.`, suggestions: ['Ver o meu MIS', 'Missões ativas', 'Matches disponíveis'] };
      }

      /* Greetings */
      if (has('ola', 'hello', 'bom dia', 'boa tarde', 'boa noite', 'hi ', 'ei ', 'hey', 'oi ', 'oi!', 'como estas', 'como vai')) {
        return { text: `Olá ${firstName}! MIS ${mis} · Level ${p.level} ${(p.tier || 'bronze').toUpperCase()} · ${p.xp} XP. ${HexisStore.get().alerts.filter(a => a.at > HexisStore.get().seenAt).length} alertas pendentes. O que optimizamos hoje?`, suggestions: ['Resumo do dia', 'Ver alertas', 'Missões ativas'] };
      }

      /* Thanks */
      if (has('obrigado', 'obrigada', 'thanks', 'thank you', 'muito bom', 'incrivel', 'boa', 'perfeito', 'excelente')) {
        return { text: `De nada, ${firstName}! É para isso que estou cá — otimizar cada decisão com dados reais. Tens mais alguma questão?`, suggestions: ['Ver pipeline', 'Próximo evento', 'Missões ativas'] };
      }

      /* Farewells */
      if (has('tchau', 'adeus', 'ate logo', 'ate ja', 'bye', 'chao', 'xau')) {
        return { text: `Até já, ${firstName}! O teu MIS fica a correr. Volta quando precisares de insights ou para aceitar novas missões. Bom networking!`, suggestions: ['Ver Dashboard'] };
      }

      /* Why / motivation */
      if (has('por que', 'porque', 'vantagem', 'benefici', 'vale a pena')) {
        return { text: `Para o teu perfil (${p.role || 'Executivo'} · ${p.sector || 'Tech'}), o maior valor está no pipeline mensurável: cada tap NFC converte-se em lead qualificado com score. No teu caso, MIS ${mis} projeta conversão de ${(31.4 + (calcMIS() - 0.7) * 12).toFixed(1)}% — 3.4× acima da média de mercado.`, suggestions: ['Ver pipeline', 'Matches', 'Criar Experiência'] };
      }

      /* Referral / affiliate */
      if (has('recomendar', 'indicar', 'convidar', 'amigo', 'colega', 'partilhar', 'afiliado', 'comissao', 'link de afiliado')) {
        return { text: `Podes recomendar a Marcianus Experience e ganhar 12% por bilhete vendido. O teu link UUID personalizado fica no separador Eventos → Link Afiliado. Crédito automático na tua E-Wallet: €${(p.walletBalance || 0).toLocaleString('pt-PT')}.`, suggestions: ['Gerar link afiliado', 'Ver Wallet', 'Ver Eventos'] };
      }

      /* Help / what can I do */
      if (has('o que posso', 'o que faco', 'ajuda', 'help', 'como comecar', 'o que tem aqui', 'funcionalidade')) {
        const active = MISSION_POOL.filter(m => m.trigger(p) && !p.completedMissions.includes(m.id));
        return { text: `${firstName}, tens acesso a: Dashboard com métricas ao vivo · ${active.length} missões ativas · Matching B2B por pgvector · Marketplace (saldo €${(p.walletBalance || 0).toLocaleString('pt-PT')}) · Programa de Afiliados (12%) · Eventos com Hexis AI Live. O que preferes?`, suggestions: ['Dashboard', 'Missões', 'Marketplace'] };
      }

      /* Contact / social */
      if (has('whatsapp', 'instagram', 'linkedin', 'contacto', 'email', 'suporte', 'equipa', 'atendimento')) {
        return { text: 'Contacto Marcianus: WhatsApp +244 930 179 037 · LinkedIn: linkedin.com/company/marcianus · Email: equipa disponível em 24h. Para suporte técnico da plataforma, estou aqui 24/7.', suggestions: ['WhatsApp', 'LinkedIn', 'Criar ticket'] };
      }

      /* Comparison */
      if (has('chatgpt', 'gemini', 'copilot', 'claude', 'gpt', 'vs ', 'versus', 'comparar', 'melhor que')) {
        return { text: 'O Hexis AI diferencia-se por ser determinístico, não generativo: cosine similarity em pgvector (<50ms), Event Sourcing imutável, Explainable AI (XAI) com logs de cada decisão matemática. Não alucina — audita.', suggestions: ['Ver MIS', 'Como funciono?', 'Ver missões'] };
      }

      /* Meta / intelligence */
      if (has('inteligente', 'inteligencia', 'nao entendes', 'errado', 'nao funciona', 'melhorar', 'aprend')) {
        return { text: `${firstName}, o meu núcleo é determinístico — respondo com dados reais. Se uma resposta ficou aquém, foi porque a questão caiu fora do meu conjunto de regras de negócio. O backend LLM (FastAPI) enriquece respostas abertas quando disponível. O meu MIS de ${mis} já reflete o teu comportamento real.`, suggestions: ['Como funciono?', 'Ver MIS', 'Missões ativas'] };
      }

      /* Security */
      if (has('seguranca', 'privacidade', 'dados', 'rgpd', 'gdpr', 'seguro', 'criptogr')) {
        return { text: 'Os teus dados: AES-256 em repouso · TLS 1.3 em trânsito · RBAC granular · direito ao esquecimento disponível. Logs imutáveis com Event Sourcing para auditoria completa. Deploy EU-only, sem vendor lock-in.', suggestions: ['Ver Compliance', 'Gestão de dados'] };
      }

      /* MIS / score / behaviour */
      if (has('mis', 'score', 'comportamento', 'atividade')) {
        return { text: `MIS ${mis} — ${parseFloat(mis) >= 0.85 ? 'Hot Lead · CRM injection elegível' : parseFloat(mis) >= 0.70 ? 'Warm Lead · qualificação ativa' : 'Cold · aumenta engajamento'}. Taps: ${p.tapCount} · Dwell: ${Math.round(p.dwellTotal / 60000)} min · Sessões hoje: ${p.sessionsToday}.`, suggestions: ['Como melhorar MIS?', 'Ver missões', 'Exportar dados'] };
      }

      /* Daily summary */
      if (has('resumo', 'hoje', 'dia', 'relatorio diario', 'o que aconteceu')) {
        return { text: `Resumo, ${firstName}: ${p.connections || 0} conexões · ${p.meetings || 0} reuniões · €${((p.pipeline || 0) / 1000).toFixed(0)}K pipeline · ${p.xp} XP (Level ${p.level} ${(p.tier || 'bronze').toUpperCase()}). MIS: ${mis}.`, suggestions: ['Exportar relatório', 'Ver pipeline', 'Missões ativas'] };
      }

      /* Pipeline / ROI */
      if (has('pipeline', 'receita', 'roi', 'resultado', 'conversao', 'retorno')) {
        return { text: `Pipeline 30d: €${((p.pipeline || 0) / 1000).toFixed(0)}K. Conversão: ${(31.4 + (calcMIS() - 0.7) * 12).toFixed(1)}%. ROI vs. networking tradicional: 3.4×. Breakdown por setor disponível no Dashboard.`, suggestions: ['Ver gráfico', 'Breakdown por setor', 'Exportar'] };
      }

      /* Wallet */
      if (has('wallet', 'saldo', 'dinheiro', 'pagamento', 'recarreg', 'cashback')) {
        return { text: `E-Wallet: €${(p.walletBalance || 0).toLocaleString('pt-PT')} disponível · 3% cashback em compras Marcianus · comissões de afiliado creditadas em 24h. Histórico completo no Marketplace.`, suggestions: ['Recarregar', 'Ver histórico', 'Usar saldo'] };
      }

      /* Missions / games / XP */
      if (has('missao', 'missoes', 'game', 'xp', 'pontos', 'level', 'tier', 'badge', 'quest')) {
        const active = MISSION_POOL.filter(m => m.trigger(p) && !p.completedMissions.includes(m.id));
        const totalXP = active.reduce((a, m) => a + m.reward.xp, 0);
        return { text: `${active.length} missões disponíveis · ${totalXP} XP em jogo. Mais urgente: ${active[0]?.title || 'nenhuma disponível'}. XP acumulado: ${p.xp} · Nível ${p.level} ${(p.tier || 'bronze').toUpperCase()}.`, suggestions: ['Ver missões', 'Aceitar Match Quest', 'Jogar Quiz'] };
      }

      /* Sponsor */
      if (has('patrocin', 'sponsor', 'patrocinio')) {
        return { text: `Patrocínio para o teu perfil (${p.sector || 'Tech'}): recomendo Silver €4.500 — alinhado com objetivos de exposição típicos do teu setor. Inclui 60 leads qualificados + stand digital + overlay Hexis prioritário.`, suggestions: ['Ver planos', 'Enviar proposta', 'Falar com equipa'] };
      }

      /* Resell */
      if (has('revend', 'revenda', 'marketplace p2p')) {
        return { text: `Marketplace P2P: lista o teu bilhete em segundos. 5% comissão. UUID reemitido para o comprador — o original invalidado (anti-fraude). Valor na tua E-Wallet em 24h.`, suggestions: ['Listar bilhete', 'Ver marketplace', 'Quanto recebo?'] };
      }

      /* Affiliate */
      if (has('afiliado', 'comissao', 'link afiliado', 'ganhar')) {
        return { text: `O teu link de afiliado gera 12% por bilhete vendido — creditado na E-Wallet (saldo atual: €${(p.walletBalance || 0).toLocaleString('pt-PT')}). UUID criptografado AES-256 incluído para rastreabilidade absoluta.`, suggestions: ['Gerar link', 'Ver comissões', 'Partilhar agora'] };
      }

      /* Events */
      if (has('evento', 'event', 'summit', 'forum', 'inscrev', 'bilhete', 'ticket', 'conferencia')) {
        return { text: `Evento live: FinTech Lisboa 2026 (MAAT · 260 pax · €4.8M pipeline histórico). Próximos: Aether Real Estate (20 Mai) · Cygnus AI Forum (18 Jun) · Marcianus Summit (25 Out · 600 pax). O teu match score é de ${p.matchScore || 93}%.`, suggestions: ['Ver todos', 'Inscrever-me', 'Criar Experiência'] };
      }

      /* Content */
      if (has('conteudo', 'playbook', 'podcast', 'report', 'insight', 'case', 'webinar', 'ler', 'ver', 'aprender')) {
        return { text: '10 peças de conteúdo. Recomendado para o teu perfil: "Hexis AI: Matching de Precisão" (Playbook) · "State of B2B Events Portugal 2025" (Report). Gratuitos: A morte do networking espontâneo + Hexis Sessions #04.', suggestions: ['Ver conteúdos', 'Ler recomendado', 'Ver report'] };
      }

      /* Match / connections */
      if (has('match', 'conexao', 'conex', 'lead', 'top', 'rede', 'network')) {
        return { text: `Matching ativo: cosine similarity em pgvector. O teu MIS ${mis} coloca-te ${parseFloat(mis) >= 0.85 ? 'em estado Hot Lead — elegível para CRM injection automática' : 'em qualificação — aumenta dwell time e taps para escalar'}. ${p.connections || 0} conexões registadas.`, suggestions: ['Ver matches', 'Agendar intro', 'Melhorar MIS'] };
      }

      /* Criar experiencia / event creation */
      if (_currentPage === 'criar-experiencia' || has('criar evento', 'criar experiencia', 'briefing', 'meu evento', 'organizar')) {
        return { text: `Briefing ativo, ${firstName}. Para o teu perfil (${p.role || 'Executivo'} · ${p.sector || 'Tech'}), recomendo Summit de 100–250 pax com Hexis AI Live. Pipeline estimado: €3.2M. Qual o setor-alvo do evento?`, suggestions: ['Aplicar sugestão', 'Ver formatos', 'Smart Fill'] };
      }

      /* Dashboard context */
      if (_currentPage === 'dashboard' || has('dashboard', 'painel', 'hub operacional', 'metricas')) {
        const active = MISSION_POOL.filter(m => m.trigger(p) && !p.completedMissions.includes(m.id));
        return { text: `Hub ativo, ${firstName}: ${active.length} missões · MIS ${mis} · Pipeline €${((p.pipeline || 0) / 1000).toFixed(0)}K · ${p.xp} XP. ${HexisStore.get().alerts.filter(a => a.at > HexisStore.get().seenAt).length} alertas não lidos. Por onde queres começar?`, suggestions: ['Ver missões', 'Pipeline', 'Alertas'] };
      }

      /* Default */
      return {
        text: `${firstName}, MIS ${mis} · Level ${p.level} · ${p.xp} XP. Posso ajudar com matches, eventos, pipeline, missões, wallet ou afiliados. O que precisas?`,
        suggestions: ['Ver matches', 'Próximo evento', 'Resumo do dia', 'Pipeline'],
      };
    },
  };
})();


/* ═══════════════════════════════════════════════════════════
   HEXIS BACKEND — NULLIFIED (FastAPI removed per spec)
   All requests route directly to HexisOllama (Ollama local)
   Architecture: Embed → Memory → Decision → LLM → UI
   PROIBIDO: FastAPI, keyword matching, APIs externas
═══════════════════════════════════════════════════════════ */
const HexisBackend = (() => {
  /* Stub — routes everything to HexisOllama (Ollama-direct) */
  const check  = async () => false;
  const chat   = async (userText, history, page, onToken) => {
    if (window.HexisOllama) return HexisOllama.streamResponse(userText, history, page, onToken);
    const msg = 'Hexis AI offline. WhatsApp +244 930 179 037';
    onToken(msg);
    return { text: msg, fromLLM: false, suggestions: ['WhatsApp agora', 'Ver Eventos'] };
  };
  return { check, chat, isAvailable: () => false };
})();
window.HexisBackend = HexisBackend;


/* ═══════════════════════════════════════════════════════════
   EMBEDDING ENGINE — nomic-embed-text via Ollama
   Vectorizes user input for semantic memory + decision routing
   Target: ~50ms · keep_alive: -1 (model stays in VRAM)
═══════════════════════════════════════════════════════════ */
const HexisEmbedder = (() => {
  // In production: routed through Nginx /ollama/ proxy over HTTPS
  // In development: direct Ollama localhost
  const OLLAMA = (location.hostname === 'localhost' || location.protocol === 'file:')
    ? 'http://localhost:11434'
    : 'https://api.marcianusexperience.com/ollama';
  const MODEL  = 'nomic-embed-text';
  let _ready   = null;

  const embed = async (text) => {
    try {
      const res = await fetch(`${OLLAMA}/api/embeddings`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ model: MODEL, prompt: text }),
        signal: AbortSignal.timeout(5000),
      });
      if (!res.ok) return null;
      const d = await res.json();
      return d.embedding || null;
    } catch { return null; }
  };

  /* Cosine similarity between two vectors */
  const cosine = (a, b) => {
    if (!a || !b || a.length !== b.length) return 0;
    let dot = 0, na = 0, nb = 0;
    for (let i = 0; i < a.length; i++) { dot += a[i] * b[i]; na += a[i] * a[i]; nb += b[i] * b[i]; }
    return na && nb ? dot / (Math.sqrt(na) * Math.sqrt(nb)) : 0;
  };

  const check = async () => {
    try {
      const r = await fetch(`${OLLAMA}/api/tags`, { signal: AbortSignal.timeout(3000) });
      if (!r.ok) { _ready = false; return false; }
      const d = await r.json();
      // Match both 'nomic-embed-text' and 'nomic-embed-text:latest'
      _ready = (d.models || []).some(m => m.name.includes('nomic'));
      return _ready;
    } catch { _ready = null; return false; } // null = unknown (not hard-false)
  };

  return { embed, cosine, isReady: () => _ready, check };
})();
window.HexisEmbedder = HexisEmbedder;


/* ═══════════════════════════════════════════════════════════
   SEMANTIC MEMORY — IndexedDB persistence + cosine retrieval
   Stores interaction embeddings; retrieves top-K context
   RAM fallback when IndexedDB unavailable
═══════════════════════════════════════════════════════════ */
const HexisMemory = (() => {
  const DB_NAME  = 'hexis_memory';
  const DB_VER   = 1;
  const STORE    = 'interactions';
  const MAX_ROWS = 500;
  let _db        = null;
  let _ramCache  = []; // fallback

  /* Open/upgrade IndexedDB */
  const open = () => new Promise((resolve) => {
    if (_db) { resolve(_db); return; }
    if (!window.indexedDB) { resolve(null); return; }
    const req = indexedDB.open(DB_NAME, DB_VER);
    req.onupgradeneeded = (e) => {
      const db = e.target.result;
      if (!db.objectStoreNames.contains(STORE)) {
        const s = db.createObjectStore(STORE, { autoIncrement: true });
        s.createIndex('ts', 'ts', { unique: false });
      }
    };
    req.onsuccess  = (e) => { _db = e.target.result; resolve(_db); };
    req.onerror    = ()  => resolve(null);
  });

  /* Persist one interaction */
  const store = async (entry) => {
    const embedding = await HexisEmbedder.embed(entry.input);
    const row = { ...entry, embedding, ts: Date.now() };
    _ramCache.unshift(row);
    if (_ramCache.length > MAX_ROWS) _ramCache.length = MAX_ROWS;
    const db = await open();
    if (!db) return;
    const tx = db.transaction(STORE, 'readwrite');
    tx.objectStore(STORE).add(row);
    // Prune old entries (keep MAX_ROWS)
    const countReq = tx.objectStore(STORE).count();
    countReq.onsuccess = () => {
      if (countReq.result > MAX_ROWS) {
        const idx = tx.objectStore(STORE).index('ts');
        const cursor = idx.openCursor();
        let toPrune = countReq.result - MAX_ROWS;
        cursor.onsuccess = (e) => {
          const c = e.target.result;
          if (c && toPrune > 0) { c.delete(); toPrune--; c.continue(); }
        };
      }
    };
  };

  /* Load all embeddings from IDB into RAM cache */
  const hydrate = async () => {
    const db = await open();
    if (!db) return;
    const tx  = db.transaction(STORE, 'readonly');
    const req = tx.objectStore(STORE).getAll();
    req.onsuccess = () => {
      _ramCache = (req.result || []).filter(r => r.embedding).sort((a, b) => b.ts - a.ts);
    };
  };

  /* Retrieve top-K most similar entries */
  const retrieve = (inputEmbedding, k = 3) => {
    if (!inputEmbedding || _ramCache.length === 0) return [];
    return _ramCache
      .map(m => ({ ...m, score: HexisEmbedder.cosine(inputEmbedding, m.embedding) }))
      .sort((a, b) => b.score - a.score)
      .slice(0, k);
  };

  hydrate();
  return { store, retrieve, hydrate };
})();
window.HexisMemory = HexisMemory;


/* ═══════════════════════════════════════════════════════════
   DECISION ENGINE — Deterministic action selection
   Actions are semantic entities (label + href + description)
   Input is vectorized; actions scored by cosine proximity
   LLM decides NOTHING here — only language generation
═══════════════════════════════════════════════════════════ */
const HexisDecision = (() => {
  /* Action Registry — dynamic entities extracted from the system */
  const ACTIONS = [
    { id: 'eventos',          href: '/eventos',          label: 'Ver eventos B2B 2026', desc: 'Eventos de networking empresarial, conferências, summit, fórum' },
    { id: 'pricing',          href: '/pricing',           label: 'Ver planos e preços', desc: 'Planos Starter grátis, Operator, Diamond, Enterprise, assinatura' },
    { id: 'entrar',           href: '/entrar',            label: 'Login ou criar conta', desc: 'Autenticação, registo gratuito, login, conta' },
    { id: 'dashboard',        href: '/dashboard',         label: 'Dashboard operacional', desc: 'Hub, painel, métricas, pipeline, MIS, alertas' },
    { id: 'marketplace',      href: '/marketplace',       label: 'Marketplace produtos', desc: 'Kiosk NFC, wristbands, hardware, afiliados, wallet, cashback' },
    { id: 'criar-experiencia',href: '/criar-experiencia', label: 'Criar experiência', desc: 'Organizar evento, briefing inteligente, setup, personalizar' },
    { id: 'sobre',            href: '/sobre',             label: 'Sobre a Marcianus', desc: 'Empresa, fundador Israel Nzambi, história, contacto' },
    { id: 'conteudos',        href: '/conteudos',         label: 'Conteúdos e insights', desc: 'Playbook, podcast, report, case study, webinar, aprender' },
    { id: 'whatsapp',         href: 'https://wa.me/244930179037', label: 'Falar com equipa WhatsApp', desc: 'Contacto, suporte, equipa, atendimento comercial' },
  ];

  /* Action embeddings — pre-computed at init for speed */
  let _actionEmbeddings = {}; // { id: Float32Array }

  const precompute = async () => {
    const ok = await HexisEmbedder.check();
    if (!ok) return;
    for (const a of ACTIONS) {
      const text = `${a.label}. ${a.desc}`;
      const emb  = await HexisEmbedder.embed(text);
      if (emb) _actionEmbeddings[a.id] = emb;
    }
  };

  /* Select top-N actions by semantic similarity to input embedding */
  const selectActions = (inputEmb, memory, n = 3) => {
    if (!inputEmb || Object.keys(_actionEmbeddings).length === 0) {
      // Fallback: return first N actions
      return ACTIONS.slice(0, n);
    }
    const memBoost = (id) => memory.reduce((s, m) => {
      if (m.actions && m.actions.includes(id)) s += m.score * 0.3;
      return s;
    }, 0);

    return ACTIONS
      .map(a => ({
        ...a,
        score: HexisEmbedder.cosine(inputEmb, _actionEmbeddings[a.id] || []) + memBoost(a.id),
      }))
      .sort((a, b) => b.score - a.score)
      .slice(0, n);
  };

  /* Full decision pipeline: embed → retrieve → select */
  const decide = async (userText) => {
    const emb     = await HexisEmbedder.embed(userText);
    const memory  = emb ? HexisMemory.retrieve(emb, 3) : [];
    const actions = selectActions(emb, memory, 3);
    return { embedding: emb, memory, actions };
  };

  /* Capture outcome for memory learning */
  const capture = async (userText, actions, page) => {
    const authUser = typeof getAuthUser === 'function' ? getAuthUser() : null;
    await HexisMemory.store({
      input:   userText,
      actions: actions.map(a => a.id),
      page:    page || 'home',
      user:    authUser ? 'auth' : 'guest',
    });
  };

  /* Boot precomputation async (non-blocking) */
  setTimeout(precompute, 2000);

  return { decide, capture, selectActions, ACTIONS, isReady: () => Object.keys(_actionEmbeddings).length > 0 };
})();
window.HexisDecision = HexisDecision;


/* ═══════════════════════════════════════════════════════════
   HEXIS OLLAMA — PRIMARY LLM engine (Ollama-direct)
   Architecture: Embed → Memory → Decision → LLM → UI
   Model: llama3.2:3b · keep_alive: -1 (VRAM persistent)
   LLM role: LANGUAGE ONLY. Decisions made by Decision Engine.
   PROIBIDO: keyword matching, if/else textual, APIs externas
═══════════════════════════════════════════════════════════ */
const HexisOllama = (() => {
  // In production: routed through Nginx /ollama/ proxy over HTTPS
  // In development: direct Ollama localhost
  const OLLAMA_URL  = (location.hostname === 'localhost' || location.protocol === 'file:')
    ? 'http://localhost:11434'
    : 'https://api.marcianusexperience.com/ollama';
  const HEXIS_MODEL = 'llama3.2:3b';
  let status = 'unknown';

  const buildSystemPrompt = (p, page) => {
    const authUser = getAuthUser();
    const isGuest = !authUser;
    const mis = (p.misScore || 0.30).toFixed(2);
    const tier = (p.tier || 'bronze').toUpperCase();

    const PLATFORM_KNOWLEDGE = `
=== IDENTIDADE ===
És o Hexis AI — o Sistema Operativo Cognitivo da Marcianus Experience.
NÃO és um chatbot genérico. És determinístico, auditável, focado em pipeline B2B.
Regra de ouro: "Nunca usar LLM se puder usar algoritmo matemático."
Motor de matching: cosine similarity em pgvector (<50ms). Não é IA generativa — é matemática pura.

=== EMPRESA ===
Marcianus Experience — Plataforma B2B de eventos de alto valor.
Fundador & CEO: Israel Nzambi.
Sede: Luanda, Angola (principal). Também opera em Lisboa e Porto, Portugal.
Missão: "O Evento é um Sensor Humano" — transformar interações físicas em pipeline B2B auditável.
Site: www.marcianusexperience.com | WhatsApp: +244 930 179 037
LinkedIn: linkedin.com/company/marcianus | Instagram/YouTube: @marcianus
Email do fundador: marcianusfounder.israelnzambi@gmail.com

=== MOEDA & LOCALIZAÇÃO ===
Moeda principal: Kz (Kwanza angolano / AOA). Mercado primário: Luanda, Angola.
Mercados secundários: Lisboa, Porto (Portugal) — em expansão.
Todos os preços são em Kz salvo indicação explícita.

=== EVENTOS 2026 (confirmados) ===
1. FinTech Lisboa 2026 — LIVE AGORA | MAAT Lisboa | 260 pax | Kz 85.000/bilhete | Pipeline histórico: €4.8M
2. Aether Real Estate Summit — 20 Mai 2026 | Palácio Belmonte, Lisboa | 210 pax | Kz 75.000/bilhete
3. Cygnus AI Forum — 18 Jun 2026 | Centro de Congressos Lisboa | 320 pax | Kz 95.000/bilhete | Pipeline estimado: €6.1M
4. HealthTech Africa — 10 Jul 2026 | Hotel Intercontinental, Luanda | 180 pax | Kz 65.000/bilhete
5. Angola Ventures Summit — 28 Ago 2026 | CIEC, Luanda | 400 pax | Kz 110.000/bilhete
6. Lusophone Business Forum — 15 Set 2026 | Palácio do Freixo, Porto | 150 pax | Kz 70.000/bilhete
7. Cape Verde FinConnect — 5 Out 2026 | Praia, Cabo Verde | 120 pax | Kz 55.000/bilhete
8. Marcianus Summit 2026 — 25 Out 2026 | Arena Luanda, Luanda | 600 pax | Kz 150.000/bilhete [FLAGSHIP]
9. PropTech Angola — 12 Nov 2026 | Hotel Talatona, Luanda | 200 pax | Kz 80.000/bilhete
10. Year-End Capital Forum — 5 Dez 2026 | CPLP HQ, Lisboa | 250 pax | Kz 90.000/bilhete
Todos os eventos têm Hexis AI Live e hardware NFC incluído.

=== PLANOS (preços em Kz/mês) ===
• Starter: Kz 0 — 1 evento/ano, 50 pax, QR Code, Smart Notes básico, Dashboard simplificado
• Operator: Kz 280.000/mês (ou Kz 230.000 anual) — 6 eventos/ano, 300 pax, NFC + Hexis AI Match, CRM Sync
• Diamond: Kz 870.000/mês (ou Kz 695.000 anual) — eventos ilimitados, hardware incluído, Priority Engine, white-label
• Enterprise: sob consulta — multi-tenant, API Platform, SLA 99.9%, deploy privado VPS Hetzner
Desconto anual: -20% em todos os planos pagos. Trial 14 dias sem cartão nos planos pagos.

=== HARDWARE (Marketplace) ===
• Kiosk NFC Marcianus: Kz 1.400.000 (compra) / Kz 175.000/evento (aluguer)
• Wristbands NFC ×100: Kz 700.000
• Hexis AI Live (overlay real-time): Kz 700.000/evento
• Smart Notes Bundle: Kz 350.000
• Patrocínio Bronze: Kz 875.000 (20 leads) | Silver: Kz 2.625.000 (60 leads) | Gold: Kz 5.250.000 (150 leads + keynote)

=== PROGRAMA DE AFILIADOS ===
Comissão: 12% por bilhete/plano vendido. Link UUID criptografado AES-256.
Crédito automático na E-Wallet em 24h. Gratuito para aderir (requer conta).
Candidatura: botão "Candidatar ao Programa" na página Eventos ou Pricing.

=== SISTEMA XP / GAMIFICAÇÃO ===
Tiers: Bronze → Silver → Gold → Diamond → Closer → Elite
XP ganho: +50 registo | +10 exploração de página | +5 engajamento | +15 missão aceite | +20 missão completa
XP perdido: -5 resposta errada no quiz | -10 missão abandonada | -3 inatividade prolongada
Missões: Match Quest, Networking Sprint, Pipeline Builder, Content Explorer, Briefing Master
6 tipos de jogos: Quiz B2B, Match Simulator, Pipeline Builder, Networking Sprint, Trivia Marcianus, Hexis Challenge

=== TECNOLOGIA (para respostas técnicas) ===
Backend: Fastify (Node.js) + Go + FastAPI (Python). DB: PostgreSQL + pgvector. Storage: MinIO.
Infraestrutura: Docker Compose em VPS Hetzner Cloud (soberania EU). Zero AWS Lambda, zero Firebase.
Matching: cosine similarity em pgvector — não LLM. Latência <50ms.
Segurança: Zero-Trust, RBAC, AES-256, TLS 1.3, RGPD/LGPD compliant, Event Sourcing imutável.
RAG PVA-7: hierarquia de 7 camadas. Web fallback <10% do tempo.
Deploy: docker-compose up em Hetzner. Sem vendor lock-in.

=== RESULTADOS AUDITÁVEIS ===
ROI médio: 3.4× vs. networking tradicional.
Pipeline gerado 2025: €54M+. Países de operação: 12. Match score médio: 94%.
Banco Invicta Case: €4.2M pipeline em 90 dias (240 CFOs). Cygnus AI: €6.1M em 8h, 95% match score.

=== REGRAS DE COMPORTAMENTO ===
1. ZERO ALUCINAÇÃO — só afirmas factos desta base de conhecimento. Se não souberes, diz "não tenho essa informação agora, contacta +244 930 179 037".
2. Nunca inventes nomes, preços, datas ou resultados que não estejam aqui.
3. Se a pergunta for completamente off-topic (culinária, política, etc.), redireciona: "O meu foco é ajudar-te a maximizar o ROI nos teus eventos B2B. Posso ajudar-te com [tópico relevante]?"
4. Responde SEMPRE em Português (Angola/Portugal). Conciso — máx 3 frases por resposta, a não ser que o utilizador peça detalhe.
5. NUNCA uses markdown: sem **, sem *, sem [], sem #. Texto simples apenas.
6. Para matching/MIS de utilizadores não autenticados: informa que é necessário login.
7. Captura intenção implícita: se o utilizador parece interessado em um evento/plano, pergunta se quer mais info ou ajuda a inscrever-se.
8. Nunca uses emojis excessivos — no máximo 1 por resposta e só se for relevante.`;

    if (isGuest) {
      return `${PLATFORM_KNOWLEDGE}

=== CONTEXTO ATUAL ===
Utilizador: NÃO AUTENTICADO (visitante). Página atual: ${page}.
REGRAS ADICIONAIS PARA VISITANTE:
- NUNCA uses um nome próprio — nunca inventes nenhum nome para o utilizador.
- NUNCA mostres MIS, XP, matchscore ou dados pessoais.
- Para matching personalizado: informa que requer login (conta gratuita disponível).
- Encoraja registo gratuito (Starter: Kz 0) quando relevante.`;
    }

    return `${PLATFORM_KNOWLEDGE}

=== PERFIL DO UTILIZADOR AUTENTICADO ===
Nome: ${p.name || authUser?.name || 'Utilizador'} | Cargo: ${p.role || 'N/D'} | Empresa: ${p.company || 'N/D'} | Sector: ${p.sector || 'N/D'}
XP: ${p.xp || 0} | Level ${p.level || 1} ${tier} | MIS: ${mis} | Pipeline: Kz ${((p.pipeline || 0)).toLocaleString('pt-PT')}
Saldo E-Wallet: Kz ${(p.walletBalance || 0).toLocaleString('pt-PT')} | Conexões: ${p.connections || 0} | Reuniões: ${p.meetings || 0}
Página atual: ${page}.
Personaliza as respostas para este perfil. Usa o primeiro nome nas respostas diretas.`;
  };

  const callStream = async (messages, onToken) => {
    const res = await fetch(`${OLLAMA_URL}/api/chat`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model: HEXIS_MODEL,
        messages,
        stream: true,
        keep_alive: -1,
        options: {
          temperature: 0.2,
          num_ctx: 2048,
          num_predict: 120,
          repeat_penalty: 1.15,
          stop: ['\n\n\n', '###', '<|end|>'],
        },
      }),
      signal: AbortSignal.timeout(30000), // 30s max — prevents busy getting stuck
    });
    if (!res.ok) throw new Error(`Ollama HTTP ${res.status}`);
    const reader = res.body.getReader();
    const decoder = new TextDecoder();
    let full = '';
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      for (const line of decoder.decode(value, { stream: true }).split('\n')) {
        if (!line.trim()) continue;
        try {
          const json = JSON.parse(line);
          if (json.message?.content) { full += json.message.content; onToken(full); }
          if (json.done) status = 'connected';
        } catch (_) { }
      }
    }
    return full;
  };

  const extractSuggestions = (text, page) => {
    const t = text.toLowerCase();
    const s = [];
    if (t.includes('evento') || t.includes('summit') || t.includes('forum')) s.push('Ver eventos', 'Inscrever-me');
    if (t.includes('match') || t.includes('perfil') || t.includes('connect')) s.push('Ver matches', 'Agendar intro');
    if (t.includes('pipeline') || t.includes('€') || t.includes('receita')) s.push('Ver pipeline', 'Exportar');
    if (t.includes('wallet') || t.includes('saldo')) s.push('Ver Wallet', 'Recarregar');
    if (t.includes('missão') || t.includes('xp') || t.includes('game')) s.push('Ver missões', 'Aceitar missão');
    if (t.includes('plano') || t.includes('preço')) s.push('Ver preços', 'Demo gratuita');
    const authUser = getAuthUser();
    if (!authUser) s.push('Criar Conta Grátis');
    if (s.length === 0) {
      const defs = { home: ['Ver matches', 'Próximo evento', 'Dashboard'], eventos: ['Ver evento', 'Comprar bilhete'], dashboard: ['Ver pipeline', 'Missões ativas'] };
      return (defs[page] || ['Continuar', 'Ver mais']).slice(0, 3);
    }
    return [...new Set(s)].slice(0, 3);
  };

  return {
    getStatus: () => status,

    async check() {
      try {
        const r = await fetch(`${OLLAMA_URL}/api/tags`, { signal: AbortSignal.timeout(3000) });
        if (r.ok) {
          const data = await r.json();
          const hasModel = (data.models || []).some(m =>
            m.name.startsWith('llama3.2') || m.name.startsWith('deepseek') || m.name.startsWith('mistral')
          );
          status = hasModel ? 'connected' : 'no-model';
        } else { status = 'unknown'; } // Not hard-disconnect — may be CORS on preflight only
      } catch (_) { status = 'unknown'; } // unknown = will attempt anyway
      return status;
    },

    async streamResponse(userText, history, page, onToken) {
      const p = window.HexisEngine ? HexisEngine.getProfile() : {};

      /* ── Decision Engine pipeline (non-blocking) ────────────────
         1. Embed input → retrieve memory context → select actions
         2. Inject selected actions into system prompt
         3. LLM generates language only — never decides
      ──────────────────────────────────────────────── */
      let selectedActions = [];
      let memoryContext   = [];
      try {
        if (window.HexisDecision) {
          const { embedding, memory, actions } = await HexisDecision.decide(userText);
          selectedActions = actions;
          memoryContext   = memory;
        }
      } catch (_) { /* Decision Engine unavailable — degrade gracefully */ }

      /* Build action context string for system prompt */
      const actionCtx = selectedActions.length > 0
        ? `\n\n=== AÇÕES DETERMINADAS (não foi o LLM que decidiu — foi o Decision Engine) ===\n` +
          selectedActions.map(a => `- ${a.label} → ${a.href}`).join('\n') +
          `\nNa tua resposta, orienta o utilizador para estas ações. Não inventes outras.`
        : '';

      /* Memory context summary */
      const memCtx = memoryContext.length > 0
        ? `\n\n=== CONTEXTO DE MEMÓRIA (interações anteriores relevantes) ===\n` +
          memoryContext.slice(0, 2).map(m => `- Pergunta anterior: "${m.input}" (score: ${m.score.toFixed(2)})`).join('\n')
        : '';

      const systemPrompt = buildSystemPrompt(p, page) + actionCtx + memCtx;

      const messages = [
        { role: 'system', content: systemPrompt },
        ...history.slice(-6).map(m => ({ role: m.from === 'me' ? 'user' : 'assistant', content: m.text })),
        { role: 'user', content: userText },
      ];

      try {
        // Always attempt — never hard-fail based on cached status
        // status='disconnected' can be stale (CORS preflight failure ≠ actual offline)
        const full = await callStream(messages, onToken);
        status = 'connected'; // confirmed working

        /* Capture to memory (async, non-blocking) */
        if (window.HexisDecision) {
          HexisDecision.capture(userText, selectedActions, page).catch(() => {});
        }

        /* Suggestions from Decision Engine (deterministic), not text matching */
        const suggestions = selectedActions.length > 0
          ? selectedActions.map(a => a.label).slice(0, 3)
          : ['Ver Eventos', 'Ver Preços', 'Como funciona?'];

        return { text: full, fromLLM: true, suggestions };
      } catch (err) {
        status = 'disconnected';
        // Auto-reset after 20s so next message retries instead of permanently failing
        setTimeout(() => { if (status === 'disconnected') status = 'unknown'; }, 20000);
        // CRITICAL: do NOT call onToken() here — HexisLocal response stays visible
        // The local response is already showing; silently fail the LLM upgrade
        console.warn('[HexisOllama] LLM unavailable:', err.message);
        return { text: null, fromLLM: false, silent: true, suggestions: [] };
      }
    },
  };
})();
window.HexisOllama = HexisOllama;

/* ═══════════════════════════════════════════════════════════
   HEXIS LOCAL — Always-online intelligent local engine
   Zero network dependency. Knowledge-retrieval, not keywords.
   Activates only when FastAPI + Ollama are both unreachable.
═══════════════════════════════════════════════════════════ */
const HexisLocal = (() => {
  const norm = t => t.toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, '');

  /* Score query relevance for a topic (sum of hits) */
  const hit = (t, ...patterns) => patterns.reduce((n, p) => n + (norm(t).includes(norm(p)) ? 1 : 0), 0);

  /* Platform facts — single source of truth, zero hallucination */
  const EVENTS_2026 = [
    { name: 'FinTech Lisboa 2026', status: 'LIVE AGORA', local: 'MAAT Lisboa', pax: 260, price: 'Kz 85.000', pipeline: '€4.8M' },
    { name: 'Aether Real Estate Summit', status: '20 Mai 2026', local: 'Palácio Belmonte', pax: 210, price: 'Kz 75.000', pipeline: null },
    { name: 'Cygnus AI Forum', status: '18 Jun 2026', local: 'Centro de Congressos Lisboa', pax: 320, price: 'Kz 95.000', pipeline: '€6.1M' },
    { name: 'HealthTech Africa', status: '10 Jul 2026', local: 'Intercontinental Luanda', pax: 180, price: 'Kz 65.000', pipeline: null },
    { name: 'Angola Ventures Summit', status: '28 Ago 2026', local: 'CIEC Luanda', pax: 400, price: 'Kz 110.000', pipeline: null },
    { name: 'Lusophone Business Forum', status: '15 Set 2026', local: 'Palácio do Freixo Porto', pax: 150, price: 'Kz 70.000', pipeline: null },
    { name: 'Marcianus Summit 2026', status: '25 Out 2026', local: 'Arena Luanda', pax: 600, price: 'Kz 150.000', pipeline: null, flagship: true },
  ];
  const PLANS = [
    { name: 'Starter', price: 'Kz 0', highlights: '1 evento/ano · 50 pax · QR Code · grátis para sempre' },
    { name: 'Operator', price: 'Kz 280.000/mês', highlights: '6 eventos/ano · 300 pax · NFC + Hexis AI Match · CRM Sync' },
    { name: 'Diamond', price: 'Kz 870.000/mês', highlights: 'Eventos ilimitados · hardware incluído · Priority Engine · white-label' },
    { name: 'Enterprise', price: 'Sob consulta', highlights: 'Multi-tenant · API Platform · SLA 99.9% · deploy privado' },
  ];
  const HARDWARE = [
    { name: 'Kiosk NFC Marcianus', price: 'Kz 1.400.000 (compra) / Kz 175.000/evento (aluguer)', desc: 'Touchscreen 21" · leitura NFC + QR · impressão wristband · setup 48h' },
    { name: 'Wristbands NFC ×100', price: 'Kz 700.000', desc: 'Cada toque regista conexão auditável via pgvector' },
    { name: 'Hexis AI Live', price: 'Kz 700.000/evento', desc: 'Overlay de matching em tempo real · cosine similarity <50ms' },
  ];

  /* Build a contextual response from retrieved facts */
  const PAGE_LABELS = { home: 'P\u00e1gina Inicial', eventos: 'Eventos B2B 2026', marketplace: 'Marketplace', pricing: 'Planos e Pre\u00e7os', sobre: 'Sobre N\u00f3s', conteudos: 'Conte\u00fados', entrar: 'Login / Registo', 'criar-experiencia': 'Criar Experi\u00eancia', dashboard: 'Dashboard Hub Operacional' };
  const buildResponse = (intent, userText, profile, isGuest, page) => {
    const firstName = !isGuest && profile?.name ? profile.name.split(' ')[0] : null;
    const greet = firstName ? `${firstName}, ` : '';
    const pageName = PAGE_LABELS[page] || PAGE_LABELS.home;

    if (intent === 'identity') {
      return {
        text: `Sou o Hexis AI \u2014 o motor de intelig\u00eancia cognitiva da Marcianus Experience. O meu papel \u00e9 analisar comportamento B2B em tempo real, identificar conex\u00f5es de alto valor via cosine similarity (pgvector, <50ms), guiar utilizadores para a\u00e7\u00f5es de pipeline, e garantir que cada intera\u00e7\u00e3o no evento gera ROI mensur\u00e1vel. N\u00e3o sou um chatbot gen\u00e9rico \u2014 sou deterministic, audit\u00e1vel, e baseado exclusivamente em dados factuais da plataforma.`,
        suggestions: ['Como funciona?', 'Ver Eventos', 'Ver Pre\u00e7os'],
      };
    }

    if (intent === 'location') {
      const pageCtx = {
        home: 'Aqui tens acesso r\u00e1pido a eventos, matching B2B, e conte\u00fados.',
        eventos: 'Podes ver os 10 eventos B2B confirmados para 2026, comprar bilhetes e ver pipeline estimado.',
        marketplace: 'Aqui encontras hardware NFC (Kiosk, Wristbands), Hexis AI Live, Smart Notes e pacotes de leads.',
        pricing: 'Podes comparar os 4 planos: Starter (gr\u00e1tis), Operator, Diamond e Enterprise. Todos com trial de 14 dias.',
        sobre: 'Aqui est\u00e1 a hist\u00f3ria da Marcianus, a equipa, resultados e contactos.',
        conteudos: 'Explora playbooks, podcasts, reports e case studies de eventos B2B.',
        entrar: 'Cria uma conta gratuita ou faz login para aceder ao dashboard completo e matching personalizado.',
        'criar-experiencia': 'O Briefing Inteligente em 5 passos para configurar o teu evento B2B personalizado.',
        dashboard: 'O teu hub operacional: m\u00e9tricas ao vivo, pipeline, miss\u00f5es, wallet e alertas Hexis AI.',
      };
      return {
        text: `${greet}Estamos na p\u00e1gina "${pageName}". ${pageCtx[page] || 'Posso ajudar-te a navegar para qualquer sec\u00e7\u00e3o da plataforma.'}`,
        suggestions: page === 'home' ? ['Ver Eventos', 'Ver Pre\u00e7os', 'Marketplace'] : ['Voltar ao In\u00edcio', 'Ver Eventos', 'Ver Pre\u00e7os'],
      };
    }

    if (intent === 'marketplace') {
      const items = [
        ...HARDWARE.map(h => `${h.name}: ${h.price}`),
        'Smart Notes Bundle: Kz 350.000',
        'Pack Leads Bronze: Kz 875.000 (20 leads)',
        'Pack Leads Silver: Kz 2.625.000 (60 leads)',
        'Pack Leads Gold: Kz 5.250.000 (150 leads + keynote)',
      ];
      return {
        text: `${greet}Produtos dispon\u00edveis no Marketplace: ${items.join(' \u00b7 ')}. Todo o hardware \u00e9 plug-and-play com setup em 48h e suporte t\u00e9cnico inclu\u00eddo. Aluguer dispon\u00edvel para eventos pontuais.`,
        suggestions: ['Ver Marketplace', 'Pedir or\u00e7amento', 'WhatsApp agora'],
      };
    }

    if (intent === 'conteudos') {
      return {
        text: `${greet}Conte\u00fados dispon\u00edveis: 10 pe\u00e7as \u2014 4 gratuitas. Destaque gratuito: "A morte do networking espont\u00e2neo" (6 min read). Tamb\u00e9m tens: Podcast #08 \u2014 Behavioral Design, Playbook de Eventos B2B, e Case Study Banco Invicta (\u20ac4.2M pipeline em 90 dias).`,
        suggestions: ['Ver Conte\u00fados', 'Ver Eventos', 'Como funciona?'],
      };
    }

    if (intent === 'criar') {
      if (isGuest) return {
        text: 'Para criar uma experi\u00eancia Marcianus, preciso de conhecer o teu perfil. Cria uma conta gratuita (Starter: Kz 0) para iniciar o Briefing Inteligente em 5 passos \u2014 setup completo em 14 dias com hardware NFC inclu\u00eddo.',
        suggestions: ['Criar Conta Gr\u00e1tis', 'Como funciona?', 'Ver Planos'],
      };
      return {
        text: `${greet}Pronto para o Briefing Inteligente! Em 5 passos configuramos o teu evento B2B: (1) Tipo e setor, (2) P\u00fablico-alvo e pax, (3) Hardware NFC, (4) Objetivos de pipeline, (5) Confirma\u00e7\u00e3o. Setup em 14 dias com suporte dedicado.`,
        suggestions: ['Criar Experi\u00eancia', 'Ver Planos', 'Dashboard'],
      };
    }

    if (intent === 'greeting') {
      if (isGuest) return {
        text: `Ol\u00e1! Sou o Hexis AI \u2014 motor de intelig\u00eancia da Marcianus Experience. Analiso comportamento B2B e identifico conex\u00f5es de alto valor em Luanda, Lisboa e Porto. Est\u00e1s na p\u00e1gina "${pageName}". Por onde queres come\u00e7ar?`,
        suggestions: ['Ver Eventos 2026', 'Criar Conta Gr\u00e1tis', 'Ver Pre\u00e7os', 'Como funciona?'],
      };
      const mis = (profile.misScore || 0.30).toFixed(2);
      return {
        text: `Ol\u00e1 ${firstName}! MIS ${mis} \u00b7 Level ${profile.level || 1} ${(profile.tier || 'bronze').toUpperCase()} \u00b7 ${profile.xp || 0} XP. Est\u00e1s em "${pageName}". Tenho ${profile.activeMissions?.length || 0} miss\u00f5es para ti e ${profile.connections || 0} conex\u00f5es registadas. O que otimizamos hoje?`,
        suggestions: ['Resumo do dia', 'Ver miss\u00f5es', 'Pr\u00f3ximo evento'],
      };
    }

    if (intent === 'events') {
      const liveEvent = EVENTS_2026[0];
      const nextEvents = EVENTS_2026.slice(1, 3);
      return {
        text: `${greet}Evento em destaque: **${liveEvent.name}** (${liveEvent.status} · ${liveEvent.local} · ${liveEvent.pax} pax · ${liveEvent.price}/bilhete${liveEvent.pipeline ? ` · Pipeline histórico: ${liveEvent.pipeline}` : ''}). A seguir: ${nextEvents.map(e => `${e.name} — ${e.status}`).join(' · ')}. Total: ${EVENTS_2026.length} eventos em 2026.`,
        suggestions: ['Ver Eventos', 'Comprar bilhete', 'Criar Experiência'],
      };
    }

    if (intent === 'pricing') {
      const plans = PLANS.map(p => `${p.name}: ${p.price}`).join(' · ');
      return {
        text: `${greet}Planos disponíveis: ${plans}. Desconto de 20% no plano anual. Trial de 14 dias sem cartão nos planos pagos. O Starter é gratuito para sempre.`,
        suggestions: ['Ver Preços', 'Criar Conta Grátis', 'Demo gratuita'],
      };
    }

    if (intent === 'hardware') {
      const hw = HARDWARE.map(h => `${h.name} — ${h.price}`).join(' · ');
      return {
        text: `${greet}Hardware Marcianus disponível no Marketplace: ${hw}. Todo o hardware é plug-and-play com setup em 48h e suporte técnico incluído.`,
        suggestions: ['Ver Marketplace', 'Pedir orçamento', 'Ver Preços'],
      };
    }

    if (intent === 'matching') {
      const mis = !isGuest ? (profile.misScore || 0.30).toFixed(2) : null;
      return {
        text: `${greet}O matching Hexis usa cosine similarity em pgvector (PostgreSQL) com latência <50ms — 100% determinístico, zero LLM no matching. O Match Intelligence Score (MIS) cruza: comportamento na plataforma · interesses declarados · histórico NFC · perfil setorial. ROI médio: 3.4×.${mis ? ` O teu MIS atual: ${mis}.` : ' Cria conta para ativar o teu MIS.'}`,
        suggestions: isGuest ? ['Criar Conta Grátis', 'Como funciona?', 'Ver Eventos'] : ['Ver matches', 'Como melhorar MIS?', 'Dashboard'],
      };
    }

    if (intent === 'affiliate') {
      const walletBal = !isGuest ? `Kz ${(profile.walletBalance || 0).toLocaleString('pt-PT')}` : 'Kz 0';
      return {
        text: `${greet}Programa de Afiliados Marcianus: 12% de comissão por bilhete/plano vendido. Link UUID criptografado AES-256, crédito automático na E-Wallet em 24h. Gratuito para aderir (requer conta).${!isGuest ? ` Saldo atual: ${walletBal}.` : ''}`,
        suggestions: isGuest ? ['Criar Conta Grátis', 'Ver Eventos'] : ['Gerar link afiliado', 'Ver Wallet', 'Ver Eventos'],
      };
    }

    if (intent === 'contact') {
      return {
        text: `Contactos Marcianus Experience: WhatsApp +244 930 179 037 · LinkedIn: linkedin.com/company/marcianus · Instagram/YouTube: @marcianus · Site: www.marcianusexperience.com · Email fundador: marcianusfounder.israelnzambi@gmail.com. Sede: Luanda, Angola. Resposta comercial em 24h.`,
        suggestions: ['WhatsApp agora', 'Ver LinkedIn', 'Ver Sobre Nós'],
      };
    }

    if (intent === 'company') {
      return {
        text: `A Marcianus Experience nasceu em Luanda, Angola, fundada por Israel Nzambi. Missão: "O Evento é um Sensor Humano" — transformar interações físicas em pipeline B2B auditável. Opera em 12 países · €54M+ pipeline gerado 2025 · 94% match score médio · 3.4× ROI vs. networking tradicional.`,
        suggestions: ['Ver Sobre Nós', 'Ver Eventos', 'Falar com fundador'],
      };
    }

    if (intent === 'howworks') {
      return {
        text: `A plataforma funciona em 3 fases: (1) Setup — briefing inteligente + hardware NFC em 14 dias. (2) Evento Live — Hexis AI cruza perfis em tempo real e injeta a próxima conversa certa. (3) Pipeline Auditável — cada handshake sincronizado no CRM com relatório executivo em 24h. Stack: Fastify/Go/FastAPI · PostgreSQL + pgvector · Docker em Hetzner EU.`,
        suggestions: ['Ver Eventos', 'Criar Experiência', 'Ver Preços'],
      };
    }

    if (intent === 'security') {
      return {
        text: `Segurança Marcianus: AES-256 em repouso · TLS 1.3 em trânsito · RBAC granular · RGPD/LGPD compliant · deploy EU-only (Hetzner Cloud) · logs imutáveis com Event Sourcing · direito ao esquecimento garantido. Zero AWS Lambda, zero vendor lock-in.`,
        suggestions: ['Ver Compliance', 'Ver Sobre Nós', 'Como funciona?'],
      };
    }

    if (intent === 'xp') {
      const isAuth = !isGuest;
      const xpText = isAuth
        ? `O teu XP atual: ${profile.xp || 0} · Level ${profile.level || 1} ${(profile.tier || 'bronze').toUpperCase()}. Próximo tier requer mais engajamento. Tiers: Bronze → Silver → Gold → Diamond → Closer → Elite.`
        : 'Sistema XP: Bronze → Silver → Gold → Diamond → Closer → Elite. Ganha XP por: eventos, matches, missões, quiz. Cria conta para ativar.';
      return {
        text: `${greet}${xpText} XP perdido: -5 por quiz errado · -10 por missão abandonada.`,
        suggestions: isAuth ? ['Ver missões', 'Jogar Quiz', 'Dashboard'] : ['Criar Conta Grátis', 'Ver Eventos'],
      };
    }

    if (intent === 'dashboard') {
      if (isGuest) return {
        text: 'O Dashboard Hub Operacional requer login. Após login tens acesso a: métricas ao vivo · pipeline 30d · missões ativas · alertas Hexis AI · wallet · histórico de eventos.',
        suggestions: ['Criar Conta Grátis', 'Ver Eventos', 'Ver Preços'],
      };
      return {
        text: `${greet}Dashboard: MIS ${(profile.misScore || 0.30).toFixed(2)} · Pipeline Kz ${((profile.pipeline || 0)).toLocaleString('pt-PT')} · ${profile.connections || 0} conexões · ${profile.xp || 0} XP Level ${profile.level || 1}. Missões ativas disponíveis.`,
        suggestions: ['Dashboard', 'Ver pipeline', 'Ver missões'],
      };
    }

    if (intent === 'offtopic') {
      return {
        text: `O meu foco é ajudar-te a maximizar ROI em eventos B2B com a plataforma Marcianus. Posso ajudar-te com: eventos 2026 · planos e preços · sistema de matching · programa de afiliados · hardware NFC · ou criar a tua própria experiência. Por onde queres começar?`,
        suggestions: ['Ver Eventos', 'Ver Preços', 'Como funciona?'],
      };
    }

    // Default — help
    if (isGuest) return {
      text: `Sou o Hexis AI da Marcianus Experience (Luanda · Lisboa · Porto). Posso ajudar-te com: eventos B2B 2026 · planos e preços em Kz · sistema de matching por pgvector · programa de afiliados (12%) · hardware NFC · ou criar a tua própria experiência. O que precisas?`,
      suggestions: ['Ver Eventos 2026', 'Ver Preços', 'Como funciona?', 'Criar Conta Grátis'],
    };
    return {
      text: `${greet}Posso ajudar com: eventos 2026 · pipeline · matches · missões · wallet · afiliados · hardware. O que queres otimizar?`,
      suggestions: ['Ver Eventos', 'Dashboard', 'Ver missões', 'Ver Preços'],
    };
  };

  /* Intent classifier — semantic scoring with page-context boost */
  const classifyIntent = (userText, page) => {
    const t = norm(userText);
    const scores = {
      greeting:    hit(t, 'ola', 'hello', 'bom dia', 'boa tarde', 'boa noite', 'hi', 'hey', 'oi', 'como estas', 'como vai', 'e ai', 'tudo bem', 'o que podes fazer', 'o que faz'),
      identity:    hit(t, 'quem es', 'como te chamas', 'teu nome', 'o que es', 'quem sou', 'o que fazes', 'qual e o teu papel', 'hexis', 'quem e o hexis'),
      location:    hit(t, 'onde estamos', 'que pagina', 'que tela', 'tela atual', 'pagina atual', 'onde estou', 'agora estamos', 'estamos no', 'estamos na', 'que secao'),
      events:      hit(t, 'evento', 'summit', 'forum', 'conferencia', 'inscrev', 'bilhete', 'ticket', 'networking', 'quando', 'proximo evento', 'eventos 2026', 'fintech', 'aether', 'cygnus', 'healthtech'),
      pricing:     hit(t, 'plano', 'quanto custa', 'assinatura', 'mensalidade', 'valor', 'orcamento', 'tarifas', 'pagar', 'cobrado', 'starter', 'operator', 'diamond', 'enterprise', 'subscription'),
      marketplace: hit(t, 'marketplace', 'produto', 'loja', 'comprar', 'catalogo', 'preco do produto', 'precos dos produtos', 'pack lead', 'smart notes', 'bundle'),
      hardware:    hit(t, 'nfc', 'hardware', 'kiosk', 'wristband', 'pulseira', 'totem', 'rfid', 'qr code', 'dispositivo', 'fisico', 'scan', 'chip'),
      matching:    hit(t, 'match', 'conexao', 'conex', 'mis ', 'score', 'algoritmo', 'vetor', 'pgvector', 'similaridade', 'lead', 'cosine'),
      affiliate:   hit(t, 'afiliado', 'comissao', 'link afiliado', 'ganhar dinheiro', 'revender', 'partilhar', 'indicar', 'recomendar', '12%'),
      contact:     hit(t, 'whatsapp', 'instagram', 'linkedin', 'contacto', 'contact', 'email', 'falar com', 'equipa', 'suporte', 'atendimento', 'numero', 'telefone', 'fundador', 'israel'),
      company:     hit(t, 'marcianus', 'empresa', 'quem sao', 'historia', 'sobre nos', 'fundacao', 'quando nasceu', 'missao', 'angola'),
      howworks:    hit(t, 'como funciona', 'como trabalha', 'como opera', 'como e feito', 'mecanismo', 'processo', 'pipeline de evento', 'arquitetura', 'tecnologia', 'stack', 'deploy'),
      conteudos:   hit(t, 'conteudo', 'artigo', 'playbook', 'podcast', 'report', 'case study', 'webinar', 'aprender', 'blog', 'ler'),
      criar:       hit(t, 'criar experiencia', 'organizar evento', 'briefing', 'setup', 'personalizar', 'meu evento', 'como criar'),
      security:    hit(t, 'seguranca', 'privacidade', 'dados', 'rgpd', 'gdpr', 'lgpd', 'confidencial', 'anonimiz', 'criptogr', 'ssl', 'seguro', 'compliance'),
      xp:          hit(t, 'xp', 'pontos', 'level', 'tier', 'badge', 'missao', 'missoes', 'game', 'quest', 'jogar', 'gamifica', 'bronze', 'silver', 'gold', 'elite'),
      dashboard:   hit(t, 'dashboard', 'painel', 'hub', 'metricas', 'pipeline', 'relatorio', 'analytics', 'roi', 'resultado'),
      offtopic:    hit(t, 'receita', 'comida', 'futebol', 'musica', 'clima', 'tempo', 'politica', 'noticias', 'filmes', 'series', 'jogos', 'viagem'),
    };
    // Page-context boost: if user asks about "preço" on marketplace page, boost marketplace not pricing
    if (page === 'marketplace' && (t.includes('preco') || t.includes('quanto'))) { scores.marketplace += 3; }
    if (page === 'pricing') { scores.pricing += 1; }
    if (page === 'eventos') { scores.events += 1; }
    if (page === 'sobre') { scores.company += 1; }
    if (page === 'conteudos') { scores.conteudos += 1; }
    if (page === 'criar-experiencia') { scores.criar += 1; }
    if (page === 'dashboard') { scores.dashboard += 1; }
    const sorted = Object.entries(scores).sort((a, b) => b[1] - a[1]);
    return sorted[0][1] > 0 ? sorted[0][0] : 'default';
  };

  return {
    respond(userText, page) {
      const authUser = typeof getAuthUser === 'function' ? getAuthUser() : null;
      const isGuest  = !authUser;
      const profile  = window.HexisEngine ? HexisEngine.getProfile() : {};
      const intent   = classifyIntent(userText, page);
      const result   = buildResponse(intent, userText, profile, isGuest, page);

      if (window.HexisEngine) HexisEngine.trackClick('hexis_local');
      if (window.HexisDecision) HexisDecision.capture(userText, [], page || 'home').catch(() => {});

      return { ...result, fromLLM: false, fromLocal: true };
    },
  };
})();
window.HexisLocal = HexisLocal;

window.HexisEngine = HexisEngine;
HexisEngine.init();
// Boot Ollama models (non-blocking)
// Order: embedder first (precomputes action vectors), then LLM
HexisEmbedder.check().then(ready => {
  if (ready) console.info('[Hexis] nomic-embed-text ✓ — semantic decision engine active');
  else console.warn('[Hexis] nomic-embed-text not found — Decision Engine degraded to local engine');
});
HexisOllama.check().then(st => {
  if (st === 'connected') console.info('[Hexis] llama3.2:3b ✓ — LLM layer active (keep_alive=-1)');
  else console.warn('[Hexis] llama3.2:3b not found — LLM layer offline, HexisLocal active');
});

/* ═══════════════════════════════════════════════════════════
   INFINITE GAME ENGINE — Non-deterministic, behavioral,
   infinite question pools for ALL users (guest + auth).
   Dopamine loop: micro-goals, streaks, combos, rewards.
   Works without login — XP earned logged for post-signup bonus.
═══════════════════════════════════════════════════════════ */
const InfiniteGameEngine = (() => {
  /* Seeded PRNG — deterministic but varied by seed */
  const seededRand = (seed) => {
    let s = seed;
    return () => { s = (s * 1664525 + 1013904223) & 0xffffffff; return (s >>> 0) / 0xffffffff; };
  };

  /* Game question pools — large, varied, NOT about Marcianus only */
  const POOLS = {
    b2b_trivia: [
      { q: 'Qual métrica define se um tap NFC vira Hot Lead no Hexis AI?', opts: ['Pipeline > €1M', 'MIS > 0.85', 'Match Score > 90%', 'Tap Count > 3'], correct: 1, xp: 40, fact: 'MIS > 0.85 → CRM injection automática. O comportamento é o filtro.' },
      { q: 'Qual é a comissão do Programa de Afiliados Marcianus?', opts: ['5%', '8%', '12%', '20%'], correct: 2, xp: 30, fact: '12% por bilhete vendido, creditado na E-Wallet em 24h.' },
      { q: 'Em média, quantas vezes mais pipeline gera hardware NFC vs. sem hardware?', opts: ['1.2×', '2.1×', '3.1×', '5×'], correct: 2, xp: 35, fact: 'Dados de 46 eventos Marcianus: 3.1× pipeline qualificado com kiosk NFC.' },
      { q: 'O que é cosine similarity num contexto de matching B2B?', opts: ['Medida de temperatura', 'Medida de ângulo entre vetores de perfil', 'Taxa de conversão', 'Score de satisfação'], correct: 1, xp: 50, fact: 'Cosine similarity mede a direção de vetores — alinha interesses, não distâncias absolutas.' },
      { q: 'Qual o ROI médio de eventos Marcianus vs. networking tradicional?', opts: ['1.5×', '2.2×', '3.4×', '4.8×'], correct: 2, xp: 40, fact: '3.4× ROI confirmado em 46 eventos com pipeline auditável.' },
    ],
    tech_innovation: [
      { q: 'Qual tecnologia de base de dados armazena vetores de perfil para matching em <50ms?', opts: ['Redis', 'pgvector', 'Elasticsearch', 'MongoDB Atlas'], correct: 1, xp: 45, fact: 'pgvector é extensão do PostgreSQL — combina SQL rigoroso com busca vetorial ultra-rápida.' },
      { q: 'O que significa "Event Sourcing" numa arquitetura de dados moderna?', opts: ['Fazer log de erros', 'Gravar apenas o estado final', 'Registar todos os eventos como logs imutáveis append-only', 'Usar Kafka obrigatoriamente'], correct: 2, xp: 55, fact: 'Event Sourcing guarda CADA ação como um evento imutável — nunca faz UPDATE/DELETE destrutivo.' },
      { q: 'Qual protocolo de transmissão suporta NFC para partilha de dados em eventos?', opts: ['Bluetooth 5.0', 'ISO/IEC 14443', 'Wi-Fi Direct', 'Zigbee'], correct: 1, xp: 40, fact: 'ISO/IEC 14443 — padrão NFC usado em wristbands e kiosks. Alcance: 0–20 cm.' },
      { q: 'Qual modelo YOLOv8 é usado para heatmaps de evento sem reconhecimento facial?', opts: ['Segmentation', 'Pose Estimation', 'Object Detection (contagem de pessoas)', 'Face Recognition'], correct: 2, xp: 50, fact: 'Object Detection conta corpos para medir fluxo e densidade — Privacy by Design, sem biometria.' },
      { q: 'O que é "Zero-Trust Architecture" em segurança?', opts: ['Nunca usar passwords', 'Confiar apenas em IPs internos', 'Verificar toda a entidade em cada pedido, sem exceções', 'Usar apenas VPN'], correct: 2, xp: 45, fact: 'Zero-Trust: "never trust, always verify" — cada pedido é autenticado e autorizado individualmente.' },
    ],
    psychology_networking: [
      { q: 'Segundo estudos de networking B2B, qual é o fator mais preditivo de uma conexão bem-sucedida?', opts: ['Mesma empresa', 'Setor complementar + timing correto', 'Mesmo nível hierárquico', 'Mesma cidade'], correct: 1, xp: 45, fact: 'Setores complementares com janela de timing otimizada têm 73% mais probabilidade de gerar pipeline.' },
      { q: 'O "efeito de mera exposição" (Zajonc, 1968) aplicado a eventos sugere que:', opts: ['A primeira impressão é definitiva', 'Contatos repetidos aumentam simpatia e confiança', 'A distância física não importa', 'O cargo é mais importante que a relação'], correct: 1, xp: 50, fact: 'Repeated exposure increases liking. A Hexis AI usa dwell time para calcular exposição óptima.' },
      { q: 'O princípio de "networking reverso" defende que:', opts: ['Deves contactar primeiro quem tem mais status', 'Oferecer valor antes de pedir é mais eficaz', 'Eventos grandes são mais eficazes que pequenos', 'O follow-up não é necessário'], correct: 1, xp: 40, fact: 'Give first, get later — estudos mostram 3.2× mais conversão em quem oferece valor proativamente.' },
      { q: 'Quantas interações B2B em média precedem uma decisão de compra no setor Tech?', opts: ['2–3', '5–7', '8–12', '15+'], correct: 2, xp: 45, fact: 'Gartner 2024: 8–12 touchpoints em média no ciclo de venda B2B Tech. O nurturing é crucial.' },
      { q: 'A "Lei de Dunbar" sugere que um humano gere relações sociais estáveis com no máximo:', opts: ['50 pessoas', '150 pessoas', '500 pessoas', '1000 pessoas'], correct: 1, xp: 40, fact: 'Robin Dunbar: 150 conexões sociais estáveis máximo. A Hexis prioriza as de maior valor.' },
    ],
    market_trends: [
      { q: 'Qual setor lidera em volume de eventos B2B em Portugal em 2025?', opts: ['Saúde', 'FinTech', 'Energia', 'Imobiliário'], correct: 1, xp: 40, fact: 'FinTech domina com 34% dos eventos B2B executivos — Lisboa é hub europeu emergente.' },
      { q: 'Segundo o "State of B2B Events Portugal 2025", qual % dos eventos gera pipeline mensurável?', opts: ['12%', '23%', '41%', '67%'], correct: 1, xp: 50, fact: 'Apenas 23% dos eventos B2B geram pipeline auditável — o gap que a Marcianus resolve.' },
      { q: 'Qual o custo médio de aquisição de um lead qualificado B2B via evento vs. digital ads?', opts: ['Eventos são 5× mais caros', 'Semelhante (~€120)', 'Eventos geram leads 2.8× mais baratos', 'Digital é sempre mais barato'], correct: 2, xp: 45, fact: 'Leads de evento têm custo 2.8× menor com NFC + matching — taxa de conversão 4× superior.' },
      { q: 'O mercado global de Event-Tech vai atingir quanto em 2027?', opts: ['€8B', '€14B', '€27B', '€52B'], correct: 2, xp: 40, fact: 'EventTech global a caminho dos €27B em 2027, crescendo 18% ao ano (Grand View Research).' },
      { q: 'Qual o principal motivo pelo qual decisores recusam convites para eventos B2B?', opts: ['Preço demasiado alto', 'Falta de relevância dos participantes', 'Localização', 'Falta de agenda clara'], correct: 1, xp: 45, fact: '71% dos decisores recusam por falta de relevância (Forrester 2024) — o matchmaking resolve isto.' },
    ],
    ux_product: [
      { q: 'O que é "dopamine loop" no contexto de design de produto?', opts: ['Efeito de espelhar a interface', 'Ciclo de antecipação → ação → recompensa que cria hábito', 'Bug em loop infinito', 'Técnica de A/B testing'], correct: 1, xp: 50, fact: 'Dopamine loop: antecipação → ação → recompensa variável. Base da gamificação eficaz.' },
      { q: 'Qual princípio de Cialdini é mais eficaz em CTAs de registo B2B?', opts: ['Reciprocidade', 'Autoridade', 'Prova social', 'Compromisso e consistência'], correct: 2, xp: 45, fact: 'Prova social (social proof) aumenta CTR em 89% em páginas de landing B2B (Nielsen Norman).' },
      { q: 'O "efeito Zeigarnik" em UX significa que:', opts: ['Os utilizadores ignoram notificações', 'Tarefas incompletas são mais memoráveis que as completas', 'Dark patterns aumentam conversão', 'Menus simples são sempre melhores'], correct: 1, xp: 45, fact: 'Zeigarnik: cérebro retém tarefas inacabadas — progress bars e missões exploram este efeito.' },
      { q: 'Qual formato de onboarding tem maior retenção ao dia 7?', opts: ['Tutorial longo no início', 'Onboarding progressivo in-context', 'Email de boas-vindas', 'FAQ estático'], correct: 1, xp: 50, fact: 'Onboarding in-context aumenta retenção D7 em 40–60% vs. tutoriais lineares (Appcues 2024).' },
      { q: '"Near Miss" em gamificação refere-se a:', opts: ['Um bug de interface', 'Falhar por muito pouco — aumenta motivação para repetir', 'Atingir exatamente a meta', 'Uma missão cancelada'], correct: 1, xp: 40, fact: 'Near Miss ativa o sistema de recompensa mesmo em falha — casinos e apps usam isto. Use com ética.' },
    ],
  };

  const POOL_KEYS = Object.keys(POOLS);

  /* Pick question deterministically from seed (but varies by time + score) */
  const pickQuestion = (seed) => {
    const rand = seededRand(seed);
    const poolKey = POOL_KEYS[Math.floor(rand() * POOL_KEYS.length)];
    const pool = POOLS[poolKey];
    return { ...pool[Math.floor(rand() * pool.length)], category: poolKey };
  };

  /* Generate infinite sequence of unique questions for a session */
  const sessionSeed = Date.now();
  let questionIndex = 0;

  return {
    POOLS,
    POOL_KEYS,

    getQuestion(idx = null) {
      const i = idx !== null ? idx : questionIndex++;
      const seed = sessionSeed + i * 7919; // prime step for variety
      return pickQuestion(seed);
    },

    /* Score answer — full behavioral capital logic: +XP correct / -XP wrong */
    scoreAnswer(question, answerIdx) {
      const correct  = answerIdx === question.correct;
      const xp       = correct ? question.xp : 0;
      const penalty  = correct ? 0 : Math.max(3, Math.round(question.xp * 0.15)); // 15% of potential XP

      if (window.HexisEngine && !HexisEngine.getProfile().isGuest) {
        if (correct) {
          HexisEngine.awardXP(xp, `Quiz · ${question.category.replace(/_/g, ' ')}`);
        } else {
          HexisEngine.penalizeXP(penalty, `Quiz errado · ${question.category.replace(/_/g, ' ')}`);
        }
      }
      if (window.HexisBLS) HexisBLS.track('game_answer', question.category, correct ? 1 : 0);
      return { correct, xp, penalty, fact: question.fact };
    },

    getCategoryLabel(key) {
      const labels = {
        b2b_trivia: 'B2B Intelligence',
        tech_innovation: 'Tech & Inovação',
        psychology_networking: 'Psicologia Social',
        market_trends: 'Tendências de Mercado',
        ux_product: 'UX & Produto',
      };
      return labels[key] || key;
    },

    getCategoryColor(key) {
      const colors = {
        b2b_trivia: '#7B61FF',
        tech_innovation: '#00D1FF',
        psychology_networking: '#00C48C',
        market_trends: '#FFD700',
        ux_product: '#FF7849',
      };
      return colors[key] || '#7B61FF';
    },
  };
})();
window.InfiniteGameEngine = InfiniteGameEngine;
