// chat-widget.el -- Neuron demo chat widget with Turnstile, session persistence,
//                   local engram graph, and share-pill.
// Compiled with: elc --target=js --bundle --minify --obfuscate
//
// Exposed globals: neuronDemoToggle(), neuronDemoSend(), neuronDemoReset()
// Required CDN: marked.js, Cloudflare Turnstile

fn main() -> Void {
    native_js("(function() {
  if (typeof marked !== 'undefined') { marked.setOptions({ breaks: true, gfm: true }); }
  var TURNSTILE_SITE_KEY = '0x4AAAAAADHAZXyuRb3yD9mr';
  var turnstileToken    = '';
  var turnstileWidgetId = null;
  var turnstileVerified = false;
  var isOpen = false;
  var MAX    = 10;

  function loadSession() {
    try {
      var s = localStorage.getItem('neuron_demo_session');
      return s ? JSON.parse(s) : { messages: [], count: 0, context: '' };
    } catch(e) { return { messages: [], count: 0, context: '' }; }
  }
  function saveSession(session) {
    try { localStorage.setItem('neuron_demo_session', JSON.stringify(session)); } catch(e) {}
  }
  function clearSession() {
    try { localStorage.removeItem('neuron_demo_session'); } catch(e) {}
  }

  function _mg(s) { return s._m || { nodes: [], edges: [] }; }

  function _um(s, nn, ne) {
    if (!nn || !nn.length) return;
    var g = _mg(s), nm = {}, ek = function(e) { return e.from + '->' + e.to; }, em = {};
    g.nodes.forEach(function(n) { nm[n.id] = n; });
    (nn || []).forEach(function(n) {
      if (nm[n.id]) { nm[n.id].w = Math.min(1.0, (nm[n.id].w || 0.5) + 0.08); }
      else { nm[n.id] = n; }
    });
    g.nodes = Object.values(nm);
    g.edges.forEach(function(e) { em[ek(e)] = e; });
    (ne || []).forEach(function(e) {
      var k = ek(e);
      if (em[k]) { em[k].weight = Math.min(1.0, (em[k].weight || 0.5) + 0.05); }
      else { em[k] = e; }
    });
    g.edges = Object.values(em);
    s._m = g; saveSession(s);
  }

  function _ra(g, q) {
    if (!g || !g.nodes || !g.nodes.length) return [];
    var words = q.toLowerCase().split(/\s+/).filter(function(w) { return w.length > 3; });
    var sc = {};
    g.nodes.forEach(function(n) {
      var t = (n.content || '').toLowerCase();
      sc[n.id] = words.filter(function(w) { return t.indexOf(w) !== -1; }).length * 0.6 + (n.w || 0.5) * 0.4;
    });
    (g.edges || []).forEach(function(e) {
      if (sc[e.from] > 0.1) sc[e.to] = (sc[e.to] || 0) + sc[e.from] * (e.weight || 0.5) * 0.4;
    });
    return g.nodes.filter(function(n) { return sc[n.id] > 0.2; })
      .sort(function(a, b) { return sc[b.id] - sc[a.id]; }).slice(0, 5)
      .map(function(n) { return { id: n.id, content: n.content, score: sc[n.id] }; });
  }

  if (window.location.search.indexOf('reset=1') !== -1) {
    clearSession();
    window.history.replaceState({}, '', window.location.pathname);
  }

  var session  = loadSession();
  if (!session.uid) {
    session.uid = 'u' + Date.now().toString(36) + Math.random().toString(36).slice(2, 7);
    saveSession(session);
  }
  var msgCount = session.count || 0;
  var _headerResetInterval = null;

  function _nextMidnightUTC() {
    var now = new Date();
    var midnight = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1));
    return Math.floor(midnight.getTime() / 1000);
  }

  function _startHeaderResetTimer() {
    var el = document.getElementById('neuron-demo-countdown');
    if (!el) return;
    if (_headerResetInterval) return; // already ticking
    var resetAt = _nextMidnightUTC();
    function _tick() {
      var secsLeft = Math.max(0, resetAt - Math.floor(Date.now() / 1000));
      var hh = Math.floor(secsLeft / 3600);
      var mm = Math.floor((secsLeft % 3600) / 60);
      var ss = secsLeft % 60;
      var pad = function(n) { return n < 10 ? '0' + n : '' + n; };
      var ts = hh + ':' + pad(mm) + ':' + pad(ss);
      var el2 = document.getElementById('neuron-demo-countdown');
      if (!el2) { clearInterval(_headerResetInterval); _headerResetInterval = null; return; }
      el2.textContent = 'resets in ' + ts;
      el2.style.color = 'rgba(255,255,255,0.65)';
      el2.style.fontWeight = '600';
      if (secsLeft <= 0) {
        clearInterval(_headerResetInterval);
        _headerResetInterval = null;
        el2.textContent = '10 questions left';
        el2.style.color = '#ffffff';
        el2.style.fontWeight = '700';
      }
    }
    _tick();
    _headerResetInterval = setInterval(_tick, 1000);
  }

  function updateCountdown() {
    var el = document.getElementById('neuron-demo-countdown');
    if (!el) return;
    var remaining = MAX - msgCount;
    if (remaining <= 0) {
      _startHeaderResetTimer();
    } else {
      if (_headerResetInterval) { clearInterval(_headerResetInterval); _headerResetInterval = null; }
      el.textContent   = remaining + ' question' + (remaining === 1 ? '' : 's') + ' left';
      el.style.color   = '#ffffff';
      el.style.fontWeight = '700';
    }
  }

  window.neuronDemoReset = function() {
    if (_headerResetInterval) { clearInterval(_headerResetInterval); _headerResetInterval = null; }
    clearSession();
    session  = { messages: [], count: 0, context: '' };
    msgCount = 0;
    var msgs  = document.getElementById('neuron-demo-messages');
    if (msgs)  msgs.innerHTML = '';
    var input = document.getElementById('neuron-demo-text');
    if (input) { input.disabled = false; input.placeholder = 'Ask me anything...'; }
    var btn   = document.getElementById('neuron-demo-send');
    if (btn)   btn.disabled = false;
    addMsg('ai', 'Hey. What is on your mind?', true);
  };

  window.neuronDemoToggle = function() {
    isOpen = !isOpen;
    var panel = document.getElementById('neuron-demo-panel');
    if (panel) panel.style.display = isOpen ? 'flex' : 'none';
    var btn   = document.getElementById('neuron-demo-btn');
    if (btn)   btn.style.display   = isOpen ? 'none' : '';
    var msgs  = document.getElementById('neuron-demo-messages');
    if (isOpen && turnstileVerified && msgs && msgs.style.display !== 'none' && msgs.children.length === 0) {
      if (session.messages && session.messages.length > 0) {
        session.messages.forEach(function(m) { addMsg(m.role, m.text, true); });
        var remaining = MAX - msgCount;
        if (remaining <= 0) {
          var input = document.getElementById('neuron-demo-text');
          if (input) { input.disabled = true; input.placeholder = 'Interaction limit reached'; }
        }
      } else if (!session.greeted) {
        addMsg('ai', 'Hey. What is on your mind?', true);
        session.greeted = true;
        saveSession(session);
      }
    }
    var input = document.getElementById('neuron-demo-text');
    if (isOpen && input && !input.disabled) input.focus();
    updateCountdown();
    if (isOpen && !turnstileWidgetId && typeof turnstile !== 'undefined') {
      var container = document.getElementById('neuron-demo-turnstile');
      if (container) {
        turnstileWidgetId = turnstile.render(container, {
          sitekey: TURNSTILE_SITE_KEY,
          size: 'compact',
          callback: function(token) {
            turnstileToken    = token;
            turnstileVerified = true;
            if (typeof turnstile !== 'undefined' && turnstileWidgetId !== null) {
              try { turnstile.remove(turnstileWidgetId); } catch(e) {}
              turnstileWidgetId = null;
            }
            var gate     = document.getElementById('neuron-demo-gate');
            var msgs     = document.getElementById('neuron-demo-messages');
            var inputRow = document.getElementById('neuron-demo-input-row');
            if (gate)     gate.style.display     = 'none';
            if (msgs)     msgs.style.display     = 'flex';
            if (inputRow) inputRow.style.display = 'flex';
            addMsg('ai', 'Hey. What is on your mind?', true);
            updateCountdown();
            var inp = document.getElementById('neuron-demo-text');
            if (inp) inp.focus();
          },
          'expired-callback': function() {
            turnstileToken    = '';
            turnstileVerified = false;
          }
        });
      }
    }
  };

  function addMsg(role, text, skipSave) {
    var msgs = document.getElementById('neuron-demo-messages');
    if (!msgs) return null;
    var el     = document.createElement('div');
    el.className = 'demo-msg demo-msg-' + role;
    var avatar = document.createElement('div');
    avatar.className = 'demo-msg-avatar';
    if (role === 'ai') {
      var img = document.createElement('img');
      img.src = '/assets/brand/neuron-brain.png'; img.alt = 'Neuron';
      avatar.appendChild(img);
    } else {
      var svgNS = 'http://www.w3.org/2000/svg';
      var svg   = document.createElementNS(svgNS, 'svg');
      svg.setAttribute('width', '14'); svg.setAttribute('height', '14');
      svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('fill', 'none');
      svg.setAttribute('stroke', 'currentColor'); svg.setAttribute('stroke-width', '2');
      var p1 = document.createElementNS(svgNS, 'path');
      p1.setAttribute('d', 'M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2');
      var c1 = document.createElementNS(svgNS, 'circle');
      c1.setAttribute('cx', '12'); c1.setAttribute('cy', '7'); c1.setAttribute('r', '4');
      svg.appendChild(p1); svg.appendChild(c1); avatar.appendChild(svg);
    }
    var bubble = document.createElement('div');
    bubble.className = 'demo-msg-bubble';
    if (role === 'ai' && typeof marked !== 'undefined') {
      try { bubble.innerHTML = marked.parse(text); } catch(e) { bubble.textContent = text; }
    } else {
      bubble.textContent = text;
    }
    if (role === 'ai') {
      var bodyWrap = document.createElement('div');
      bodyWrap.className = 'demo-msg-ai-body';
      bodyWrap.appendChild(bubble);
      if (!skipSave) {
        var shareBtn = document.createElement('button');
        shareBtn.className = 'demo-share-pill'; shareBtn.title = 'Share this response'; shareBtn.textContent = 'Share ↗';
        shareBtn.onclick = async function() {
          var prevUser = '';
          if (session.messages) {
            for (var i = session.messages.length - 1; i >= 0; i--) {
              if (session.messages[i].role === 'user') { prevUser = session.messages[i].text; break; }
            }
          }
          shareBtn.style.opacity = '0.4';
          try {
            var r = await fetch('/api/share', {
              method: 'POST',
              headers: {'Content-Type': 'application/json'},
              body: JSON.stringify({ question: prevUser, answer: text })
            });
            var d = await r.json();
            if (d.id) window.open('/share/' + d.id, '_blank');
          } catch(e) {}
          shareBtn.style.opacity = '1';
        };
        bodyWrap.appendChild(shareBtn);
      }
      el.appendChild(avatar); el.appendChild(bodyWrap);
    } else {
      el.appendChild(avatar); el.appendChild(bubble);
    }
    msgs.appendChild(el);
    msgs.scrollTop = msgs.scrollHeight;
    if (!skipSave && role !== 'thinking') {
      session.messages = session.messages || [];
      session.messages.push({ role: role, text: text });
      if (session.messages.length > 40) session.messages = session.messages.slice(-40);
      saveSession(session);
    }
    return el;
  }

  window.neuronDemoSend = async function() {
    if (msgCount >= MAX) return;
    var input = document.getElementById('neuron-demo-text');
    var btn   = document.getElementById('neuron-demo-send');
    if (!input || btn.disabled) return;
    var msg = input.value.trim();
    if (!msg) return;
    var MAX_CHARS = 8000;
    if (msg.length > MAX_CHARS) {
      if (input) {
        input.style.outline = '2px solid #e53e3e';
        setTimeout(function() { input.style.outline = ''; }, 2000);
      }
      return;
    }
    input.value = '';
    btn.disabled = true;
    addMsg('user', msg);

    var thinking = document.createElement('div');
    thinking.className = 'demo-msg demo-msg-thinking';
    var thAvatar = document.createElement('div');
    thAvatar.className = 'demo-msg-avatar';
    var thImg = document.createElement('img');
    thImg.src = '/assets/brand/neuron-brain.png'; thImg.alt = 'Neuron';
    thAvatar.appendChild(thImg); thinking.appendChild(thAvatar);
    var thDots = document.createElement('span');
    thDots.className = 'demo-msg-thinking-dots';
    thDots.innerHTML = '<span></span><span></span><span></span>';
    thinking.appendChild(thDots);
    var thMsgsEl = document.getElementById('neuron-demo-messages');
    if (thMsgsEl) { thMsgsEl.appendChild(thinking); thMsgsEl.scrollTop = thMsgsEl.scrollHeight; }

    try {
      var hist = (session.messages || []).slice(-20).filter(function(m) { return m.role !== 'thinking'; }).map(function(m) {
        return { role: m.role === 'ai' ? 'assistant' : 'user', content: m.text };
      });
      var activated_nodes    = _ra(session._m, msg);
      var questionsRemaining = Math.max(0, (MAX - msgCount) - 1);
      var r = await fetch('/api/demo', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
          message:            msg,
          history:            hist,
          cf_token:           turnstileVerified && !session._cfSent ? turnstileToken : '',
          uid:                session.uid || '',
          activated_nodes:    activated_nodes,
          engram_node_count:  (session._m && session._m.nodes) ? session._m.nodes.length : 0,
          questions_remaining: questionsRemaining,
          is_last_question:   questionsRemaining === 0
        })
      });
      var d = await r.json();
      if (thinking) thinking.remove();

      // Server-side rate limit — show a live countdown to reset
      if (d.rate_limited && d.reset_at) {
        var _showRateTimer = function() {
          var now    = Math.floor(Date.now() / 1000);
          var secsLeft = Math.max(0, d.reset_at - now);
          var hh   = Math.floor(secsLeft / 3600);
          var mm   = Math.floor((secsLeft % 3600) / 60);
          var ss   = secsLeft % 60;
          var pad  = function(n) { return n < 10 ? '0' + n : '' + n; };
          var ts   = hh > 0 ? (hh + ':' + pad(mm) + ':' + pad(ss)) : (pad(mm) + ':' + pad(ss));
          return 'You\'ve had 10 conversations today. Come back in ' + ts + '.';
        };
        addMsg('ai', _showRateTimer());
        // Update the last ai message with a live ticker
        var _timerInterval = setInterval(function() {
          var thMsgsInner = document.getElementById('neuron-demo-msgs');
          if (!thMsgsInner) { clearInterval(_timerInterval); return; }
          var aiMsgs = thMsgsInner.querySelectorAll('.neuron-msg-ai');
          var lastAi = aiMsgs[aiMsgs.length - 1];
          if (lastAi) { lastAi.textContent = _showRateTimer(); }
          if (Math.floor(Date.now() / 1000) >= d.reset_at) {
            clearInterval(_timerInterval);
            if (lastAi) { lastAi.textContent = 'You\'re all set — conversations reset. Say hello!'; }
            if (input)  { input.disabled = false; input.placeholder = 'Ask me anything...'; }
            if (btn)    { btn.disabled = false; }
          }
        }, 1000);
        if (input) { input.disabled = true; input.placeholder = 'Come back tomorrow...'; }
        if (btn)   { btn.disabled = true; }
        if (btn)   { btn.disabled = false; }
        if (input) { input.focus(); }
        return;
      }

      _um(session, d.sn, d.se);
      var reply   = d.response || d.reply || d.message || '';
      var isError = !reply || reply === 'Stepped out for a moment. Try again.';
      if (!isError) {
        msgCount++;
        session.count = msgCount;
        saveSession(session);
        updateCountdown();
        if (msgCount >= MAX && input) { input.disabled = true; input.placeholder = 'Interaction limit reached'; }
      }
      addMsg('ai', reply || 'Stepped out for a moment. Try again.');
    } catch(e) {
      if (thinking) thinking.remove();
      addMsg('ai', 'Stepped out for a moment. Try again.');
    }
    if (msgCount < MAX && btn) btn.disabled = false;
    if (input) input.focus();
  };

  var inp = document.getElementById('neuron-demo-text');
  if (inp) {
    inp.addEventListener('keydown', function(e) {
      if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); window.neuronDemoSend(); }
    });
  }
})()")
}
