// Learn-code: reveal/hide explanations inline (line notes `+` and section
// tabs), plus a "code only" mode that strips all annotations to bare code.
// Inert on any page without `.learn-code` markup.

(function () {
  'use strict';

  // The notes for a toggle are the `.lc-note` siblings immediately following
  // its container (a `.lc-line` for `+`, a `.lc-section` for a section tab).
  function notesAfter(container) {
    var out = [];
    var el = container && container.nextElementSibling;
    while (el && el.classList.contains('lc-note')) {
      out.push(el);
      el = el.nextElementSibling;
    }
    return out;
  }

  function containerFor(toggle) {
    return toggle.closest('.lc-line') || toggle.closest('.lc-section');
  }

  function setOpen(toggle, open) {
    toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
    if (toggle.classList.contains('lc-toggle')) {
      toggle.textContent = open ? '−' : '+'; // − / +
    }
    notesAfter(containerFor(toggle)).forEach(function (n) { n.hidden = !open; });
  }

  function toggles(root) {
    return root.querySelectorAll('.lc-toggle, .lc-section__tab');
  }

  // Keep the reveal-all button's icon/label in step with whether anything is closed.
  function syncRevealAll(root) {
    var allBtn = root.querySelector('.lc-all');
    if (!allBtn) return;
    var anyClosed = Array.prototype.some.call(toggles(root), function (t) {
      return t.getAttribute('aria-expanded') !== 'true';
    });
    allBtn.setAttribute('aria-expanded', anyClosed ? 'false' : 'true');
    var icon = allBtn.querySelector('i');
    if (icon) icon.className = anyClosed ? 'ph ph-caret-double-down' : 'ph ph-caret-double-up';
    var label = (anyClosed ? 'Reveal all notes' : 'Hide all notes') + ' (R)';
    allBtn.setAttribute('title', label);
    allBtn.setAttribute('aria-label', label);
  }

  // Reveal or hide every note at once (reveal-all button, hint link, or `R`).
  function revealAll(root) {
    var allBtn = root.querySelector('.lc-all');
    var open = allBtn ? allBtn.getAttribute('aria-expanded') !== 'true' : true;
    Array.prototype.forEach.call(toggles(root), function (t) { setOpen(t, open); });
    syncRevealAll(root);
  }

  // Toggle "code only" mode (the </> button or `C`).
  function codeOnly(root) {
    var on = !root.classList.contains('is-codeonly');
    root.classList.toggle('is-codeonly', on);
    var btn = root.querySelector('.lc-codeonly');
    if (btn) {
      btn.setAttribute('aria-pressed', on ? 'true' : 'false');
      var label = (on ? 'Show explanations' : 'Show code only') + ' (C)';
      btn.setAttribute('title', label);
      btn.setAttribute('aria-label', label);
    }
  }

  // The block the pointer is currently over — keyboard shortcuts act on it only.
  var hovered = null;

  // Don't hijack keys while the user is typing in a field.
  function isTyping() {
    var el = document.activeElement;
    if (!el) return false;
    var tag = el.tagName;
    return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || el.isContentEditable;
  }

  function initBlock(root) {
    root.addEventListener('mouseenter', function () { hovered = root; });
    root.addEventListener('mouseleave', function () { if (hovered === root) hovered = null; });

    root.addEventListener('click', function (e) {
      var toggle = e.target.closest('.lc-toggle, .lc-section__tab');
      if (toggle && root.contains(toggle)) {
        setOpen(toggle, toggle.getAttribute('aria-expanded') !== 'true');
        syncRevealAll(root);
        return;
      }

      // The reveal-all icon and the hint's "Reveal all" link both toggle everything.
      var allBtn = e.target.closest('.lc-all, .lc-all-link');
      if (allBtn && root.contains(allBtn)) {
        revealAll(root);
        return;
      }

      var codeBtn = e.target.closest('.lc-codeonly');
      if (codeBtn && root.contains(codeBtn)) {
        codeOnly(root);
      }
    });
  }

  // Hover-scoped shortcuts: plain `R` (reveal all) and `C` (code only). No
  // modifiers, so they can't collide with browser/OS shortcuts (which all use
  // Ctrl/Cmd/Alt); ignored while typing or when no block is hovered.
  function onKeydown(e) {
    if (!hovered) return;
    if (e.ctrlKey || e.metaKey || e.altKey) return;
    if (isTyping()) return;
    var key = e.key ? e.key.toLowerCase() : '';
    if (key === 'r') {
      revealAll(hovered);
      e.preventDefault();
    } else if (key === 'c') {
      codeOnly(hovered);
      e.preventDefault();
    }
  }

  function init() {
    var blocks = document.querySelectorAll('.learn-code[data-learn-code]');
    if (!blocks.length) return;   // inert on pages without learn-code
    Array.prototype.forEach.call(blocks, initBlock);
    document.addEventListener('keydown', onKeydown);
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();
