/* chem8_glossary.js — глоссарий учебника «Химия 8».
 * Самодостаточный drop-in: словарь терминов + плавающая кнопка + модалка с поиском
 * + авто-подсветка терминов в .card-body (tooltip с определением). Стили инжектятся.
 * Подключается одним тегом <script src="/js/chem8_glossary.js" defer></script>.
 */
(function (W) {
  'use strict';
  var D = W.document;

  /* словарь: термин → {d: определение, see: [связанные]} */
  var G = {
    'атом': { d: 'Мельчайшая химически неделимая частица вещества: ядро (протоны и нейтроны) + электроны.', see: ['химический элемент', 'нуклид'] },
    'химический элемент': { d: 'Вид атомов с одинаковым зарядом ядра (числом протонов).', see: ['атом'] },
    'относительная атомная масса': { d: 'Безразмерная величина $A_r$ — во сколько раз масса атома больше 1/12 массы атома углерода-12.', see: ['относительная молекулярная масса'] },
    'относительная молекулярная масса': { d: 'Сумма относительных атомных масс всех атомов в формуле ($M_r$).', see: ['молярная масса'] },
    'простое вещество': { d: 'Вещество из атомов одного элемента (O₂, Fe).', see: ['сложное вещество'] },
    'сложное вещество': { d: 'Вещество из атомов разных элементов (H₂O, CaCO₃).', see: ['простое вещество'] },
    'химическая формула': { d: 'Запись состава вещества символами элементов с индексами.', see: [] },
    'химическое количество': { d: 'Физическая величина $n$ (порция вещества), измеряется в молях.', see: ['моль', 'постоянная Авогадро'] },
    'моль': { d: 'Единица химического количества: содержит $6{,}02\\cdot10^{23}$ частиц (число Авогадро).', see: ['постоянная Авогадро'] },
    'постоянная Авогадро': { d: '$N_A = 6{,}02\\cdot10^{23}$ частиц/моль — число частиц в 1 моль.', see: ['моль'] },
    'молярная масса': { d: 'Масса 1 моль вещества $M$ (г/моль); численно равна $M_r$.', see: ['относительная молекулярная масса'] },
    'молярный объём': { d: 'Объём 1 моль газа; при н.у. $V_m = 22{,}4$ л/моль.', see: [] },
    'оксид': { d: 'Сложное вещество из элемента и кислорода (с.о. −2): основный, кислотный, амфотерный, несолеобразующий.', see: ['основный оксид', 'кислотный оксид'] },
    'основный оксид': { d: 'Оксид металла, реагирует с кислотами (CaO, Na₂O).', see: ['оксид'] },
    'кислотный оксид': { d: 'Оксид неметалла, реагирует со щелочами (CO₂, SO₃).', see: ['оксид'] },
    'амфотерность': { d: 'Способность вещества проявлять и кислотные, и основные свойства (Zn(OH)₂, Al(OH)₃).', see: ['оксид', 'основание'] },
    'кислота': { d: 'Вещество с атомами водорода, способными замещаться металлом, и кислотным остатком.', see: ['основность'] },
    'основность': { d: 'Число атомов водорода в кислоте, способных замещаться металлом.', see: ['кислота'] },
    'основание': { d: 'Вещество из металла и гидроксогрупп OH; растворимые — щёлочи.', see: ['щёлочь', 'нейтрализация'] },
    'щёлочь': { d: 'Растворимое в воде основание (NaOH, KOH, Ba(OH)₂).', see: ['основание'] },
    'соль': { d: 'Вещество из катионов металла и анионов кислотного остатка (NaCl, CaCO₃).', see: ['реакция ионного обмена'] },
    'нейтрализация': { d: 'Реакция кислоты с основанием: соль + вода.', see: ['кислота', 'основание'] },
    'индикатор': { d: 'Вещество, меняющее окраску в зависимости от среды (лакмус, фенолфталеин, метилоранж).', see: [] },
    'реакция ионного обмена': { d: 'Реакция между растворами, идущая до конца при образовании осадка ↓, газа ↑ или воды.', see: ['соль', 'растворимость'] },
    'ряд активности металлов': { d: 'Ряд металлов по убыванию химической активности; металл вытесняет менее активные.', see: [] },
    'генетическая связь': { d: 'Связь между классами веществ через цепочки превращений (металл→оксид→основание→соль).', see: [] },
    'периодический закон': { d: 'Свойства элементов периодически зависят от заряда ядра их атомов (Д. И. Менделеев, 1869).', see: ['периодическая система'] },
    'периодическая система': { d: 'Таблица элементов: периоды (строки) и группы (столбцы).', see: ['период', 'группа'] },
    'период': { d: 'Горизонтальный ряд в ПСХЭ; номер = число электронных слоёв.', see: ['периодическая система'] },
    'группа': { d: 'Вертикальный столбец ПСХЭ; номер = число внешних электронов.', see: ['периодическая система'] },
    'нуклид': { d: 'Вид атомов с определёнными Z (протоны) и N (нейтроны).', see: ['изотопы', 'массовое число'] },
    'массовое число': { d: 'Число протонов и нейтронов в ядре: $A = Z + N$.', see: ['нуклид'] },
    'изотопы': { d: 'Атомы одного элемента с разным числом нейтронов (одинаковый Z, разный A).', see: ['нуклид'] },
    'электронное облако': { d: 'Область вокруг ядра, где электрон бывает чаще всего.', see: ['орбиталь'] },
    'орбиталь': { d: 'Форма электронного облака: s — сфера, p — гантель.', see: ['электронное облако'] },
    'электроотрицательность': { d: 'Способность атома притягивать к себе общие электроны.', see: ['ковалентная связь'] },
    'ковалентная связь': { d: 'Связь за счёт общих электронных пар (между неметаллами).', see: ['электроотрицательность', 'ионная связь'] },
    'ионная связь': { d: 'Связь за счёт полной передачи электронов от металла к неметаллу; образуются ионы.', see: ['ковалентная связь'] },
    'металлическая связь': { d: 'Связь ион-остовов металла «электронным газом» из общих электронов.', see: [] },
    'кристаллическая решётка': { d: 'Упорядоченное расположение частиц в кристалле: ионная, атомная, молекулярная, металлическая.', see: [] },
    'степень окисления': { d: 'Условный заряд атома в соединении (H +1, O −2, сумма = 0).', see: ['окисление', 'восстановление'] },
    'окисление': { d: 'Процесс отдачи электронов (степень окисления повышается).', see: ['восстановление', 'степень окисления'] },
    'восстановление': { d: 'Процесс приёма электронов (степень окисления понижается).', see: ['окисление'] },
    'окислитель': { d: 'Частица, принимающая электроны (сама восстанавливается).', see: ['восстановитель'] },
    'восстановитель': { d: 'Частица, отдающая электроны (сама окисляется).', see: ['окислитель'] },
    'окислительно-восстановительная реакция': { d: 'Реакция с изменением степеней окисления (переход электронов).', see: ['степень окисления'] },
    'смесь': { d: 'Несколько веществ вместе: однородная (раствор) или неоднородная.', see: ['раствор'] },
    'раствор': { d: 'Однородная смесь растворителя и растворённого вещества.', see: ['растворимость', 'массовая доля'] },
    'растворимость': { d: 'Масса вещества, растворяющаяся в 100 г воды при данной температуре.', see: ['раствор'] },
    'насыщенный раствор': { d: 'Раствор, в котором вещество больше не растворяется при данной температуре.', see: ['раствор'] },
    'массовая доля': { d: 'Отношение массы растворённого вещества к массе раствора: $w = m_{в-ва}/m_{р-ра}$.', see: ['раствор'] },
    'молярная концентрация': { d: 'Химическое количество вещества в 1 л раствора: $c = n/V$ (моль/л).', see: ['раствор'] }
  };

  var TERMS = Object.keys(G).sort(function (a, b) { return b.length - a.length; }); // длинные раньше

  function injectCSS() {
    if (D.getElementById('chem8-gloss-css')) return;
    var s = D.createElement('style'); s.id = 'chem8-gloss-css';
    s.textContent =
      '.gloss{border-bottom:1.5px dotted var(--pri,#d97706);cursor:help;text-decoration:none}'
      + '.gl-fab{position:fixed;left:16px;bottom:16px;z-index:55;display:inline-flex;align-items:center;gap:7px;padding:9px 14px;border:none;border-radius:99px;background:var(--pri,#d97706);color:#fff;font-weight:700;font-size:.84rem;cursor:pointer;box-shadow:0 6px 18px rgba(0,0,0,.18);font-family:inherit}'
      + '.gl-fab:hover{filter:brightness(1.08)}.gl-fab svg{width:16px;height:16px;stroke:#fff;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}'
      + '.gl-modal{position:fixed;inset:0;z-index:80;background:rgba(0,0,0,.45);display:none;align-items:flex-start;justify-content:center;padding:40px 16px;overflow:auto}'
      + '.gl-modal.show{display:flex}'
      + '.gl-box{background:var(--card,#fff);color:var(--text,#1c1917);border-radius:16px;max-width:600px;width:100%;padding:20px;box-shadow:0 20px 60px rgba(0,0,0,.3)}'
      + '.gl-h{display:flex;align-items:center;gap:10px;margin-bottom:12px}.gl-h h3{font-family:Outfit,sans-serif;font-size:1.15rem;font-weight:800;flex:1}'
      + '.gl-close{border:none;background:transparent;font-size:1.4rem;cursor:pointer;color:var(--muted,#888);line-height:1}'
      + '.gl-search{width:100%;padding:10px 13px;border:1.5px solid var(--border,#ddd);border-radius:10px;background:var(--card,#fff);color:var(--text,#1c1917);font-family:inherit;font-size:.95rem;margin-bottom:12px}'
      + '.gl-list{max-height:60vh;overflow:auto}'
      + '.gl-item{padding:10px 12px;border-bottom:1px solid var(--border,#eee)}.gl-item:last-child{border-bottom:0}'
      + '.gl-term{font-weight:800;color:var(--pri-d,#b45309);text-transform:capitalize}'
      + '.gl-def{font-size:.9rem;margin-top:3px;line-height:1.5}'
      + '.gl-see{font-size:.8rem;color:var(--muted,#888);margin-top:4px}'
      + '.gl-pop{position:absolute;z-index:90;max-width:280px;background:var(--card,#fff);color:var(--text,#1c1917);border:1.5px solid var(--pri,#d97706);border-radius:10px;padding:10px 13px;font-size:.86rem;line-height:1.5;box-shadow:0 8px 24px rgba(0,0,0,.2);display:none}'
      + '.gl-pop.show{display:block}.gl-pop b{color:var(--pri-d,#b45309);text-transform:capitalize}';
    D.head.appendChild(s);
  }

  function esc(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }

  /* авто-подсветка терминов в .card-body (первое вхождение каждого, в текстовых узлах) */
  function decorate(root) {
    if (!root) return;
    var bodies = root.matches && root.matches('.card-body') ? [root] : root.querySelectorAll ? root.querySelectorAll('.card-body') : [];
    Array.prototype.forEach.call(bodies, function (body) {
      if (body._glossed) return; body._glossed = 1;
      var used = {};
      TERMS.forEach(function (term) {
        if (used[term]) return;
        var walker = D.createTreeWalker(body, W.NodeFilter.SHOW_TEXT, null);
        var node, re = new RegExp('(^|[^а-яёА-ЯЁ-])(' + esc(term) + ')(?![а-яёА-ЯЁ])', 'i');
        while ((node = walker.nextNode())) {
          if (node.parentNode && (node.parentNode.classList && (node.parentNode.classList.contains('gloss') || node.parentNode.closest('.gloss,abbr,a,.ph-formula,.main-f,code')))) continue;
          var m = node.nodeValue.match(re);
          if (m) {
            var idx = m.index + m[1].length;
            var before = node.nodeValue.slice(0, idx), word = node.nodeValue.slice(idx, idx + term.length), after = node.nodeValue.slice(idx + term.length);
            var ab = D.createElement('abbr'); ab.className = 'gloss'; ab.setAttribute('data-term', term.toLowerCase()); ab.textContent = word;
            var frag = D.createDocumentFragment();
            frag.appendChild(D.createTextNode(before)); frag.appendChild(ab); frag.appendChild(D.createTextNode(after));
            node.parentNode.replaceChild(frag, node);
            used[term] = 1; break;
          }
        }
      });
    });
  }

  /* popover при наведении/клике на .gloss */
  var pop;
  function showPop(ab) {
    var term = ab.getAttribute('data-term'); var g = G[term]; if (!g) return;
    if (!pop) { pop = D.createElement('div'); pop.className = 'gl-pop'; D.body.appendChild(pop); }
    pop.innerHTML = '<b>' + term + '</b><br>' + g.d + (g.see && g.see.length ? '<div class="gl-see">См.: ' + g.see.join(', ') + '</div>' : '');
    var r = ab.getBoundingClientRect();
    pop.style.left = Math.min(r.left, W.innerWidth - 300) + 'px';
    pop.style.top = (r.bottom + W.scrollY + 6) + 'px';
    pop.classList.add('show');
    renderMath(pop);
  }
  function hidePop() { if (pop) pop.classList.remove('show'); }
  function renderMath(el) { if (typeof W.renderMathInElement === 'function') { try { W.renderMathInElement(el, { delimiters: [{ left: '$', right: '$', display: false }], throwOnError: false }); } catch (e) {} } }

  /* модалка */
  var modal;
  function buildModal() {
    modal = D.createElement('div'); modal.className = 'gl-modal';
    modal.innerHTML = '<div class="gl-box"><div class="gl-h"><h3>Глоссарий — Химия 8</h3><button class="gl-close" aria-label="Закрыть">&times;</button></div>'
      + '<input class="gl-search" placeholder="Поиск термина...">'
      + '<div class="gl-list"></div></div>';
    D.body.appendChild(modal);
    var list = modal.querySelector('.gl-list'), search = modal.querySelector('.gl-search');
    function render(q) {
      q = (q || '').toLowerCase().trim();
      var keys = Object.keys(G).sort();
      list.innerHTML = keys.filter(function (t) { return !q || t.indexOf(q) >= 0 || G[t].d.toLowerCase().indexOf(q) >= 0; })
        .map(function (t) { return '<div class="gl-item"><div class="gl-term">' + t + '</div><div class="gl-def">' + G[t].d + '</div>' + (G[t].see && G[t].see.length ? '<div class="gl-see">См.: ' + G[t].see.join(', ') + '</div>' : '') + '</div>'; }).join('') || '<div class="gl-item">Ничего не найдено.</div>';
      renderMath(list);
    }
    search.addEventListener('input', function () { render(search.value); });
    modal.querySelector('.gl-close').addEventListener('click', close);
    modal.addEventListener('click', function (e) { if (e.target === modal) close(); });
    render('');
  }
  function open() { if (!modal) buildModal(); modal.classList.add('show'); var s = modal.querySelector('.gl-search'); if (s) setTimeout(function () { s.focus(); }, 50); }
  function close() { if (modal) modal.classList.remove('show'); }

  function init() {
    injectCSS();
    var fab = D.createElement('button'); fab.className = 'gl-fab';
    fab.innerHTML = '<svg viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg> Глоссарий';
    fab.addEventListener('click', open);
    D.body.appendChild(fab);
    D.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });
    // авто-подсветка терминов: при наведении/клике — popover
    D.body.addEventListener('mouseover', function (e) { if (e.target.classList && e.target.classList.contains('gloss')) showPop(e.target); });
    D.body.addEventListener('mouseout', function (e) { if (e.target.classList && e.target.classList.contains('gloss')) hidePop(); });
    D.body.addEventListener('click', function (e) { if (e.target.classList && e.target.classList.contains('gloss')) { e.preventDefault(); showPop(e.target); } });
    // первичная декорация + наблюдение за лениво строящимися §
    decorate(D.body);
    try {
      var obs = new W.MutationObserver(function (muts) {
        muts.forEach(function (m) { Array.prototype.forEach.call(m.addedNodes, function (n) { if (n.nodeType === 1) decorate(n); }); });
      });
      obs.observe(D.body, { childList: true, subtree: true });
    } catch (e) {}
  }

  W.Chem8Glossary = { open: open, decorate: decorate, terms: G };
  if (D.readyState === 'loading') D.addEventListener('DOMContentLoaded', init); else init();
})(window);
