// help.jsx — Tab "Trợ giúp" trong mỗi module.
// Đọc TRỰC TIẾP docs/modules/module-<id>-spec.md lúc chạy → Trợ giúp tự đồng bộ với spec (1 nguồn duy nhất).
// Hiển thị phần HƯỚNG DẪN (mỗi "##" = 1 thẻ, lưới full màn hình); BỎ QUA "## Thay đổi" (chỉ dành cho dev).

// Inline markdown: **đậm**, `code`, [link](url).
function mdInlineHelp(s) {
  return s
    .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
    .replace(/`([^`]+)`/g, '<code>$1</code>')
    .replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
    .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener">$1</a>');
}
// Render khối nội dung (trong 1 thẻ): h3/h4, blockquote, danh sách (số/bullet, LỒNG theo mức thụt), đoạn văn.
// Danh sách dùng stack theo độ thụt: bullet thụt vào nằm LỒNG trong <li> cha → list số chạy liền 1,2,3… qua các bullet con.
function mdBodyToHtml(lines) {
  let html = '';
  const stack = []; // mỗi mức: {tag:'ul'|'ol', indent}; mỗi frame luôn có 1 <li> đang mở
  const closeOne = () => { html += '</li></' + stack[stack.length - 1].tag + '>'; stack.pop(); };
  const closeAll = () => { while (stack.length) closeOne(); };
  const openList = (tag, startN) => {
    html += '<' + tag + (tag === 'ol' && startN !== 1 ? ' start="' + startN + '"' : '') + '>';
    stack.push({ tag, indent: undefined });
  };
  for (const raw of lines) {
    const line = raw.replace(/\s+$/, '');
    if (!line.trim()) { closeAll(); continue; }
    let m;
    if ((m = line.match(/^(#{3,4})\s+(.*)/))) { closeAll(); const lv = m[1].length; html += '<h' + lv + '>' + mdInlineHelp(m[2]) + '</h' + lv + '>'; continue; }
    if ((m = line.match(/^>\s?(.*)/))) { closeAll(); html += '<blockquote>' + mdInlineHelp(m[1]) + '</blockquote>'; continue; }
    const indent = line.match(/^(\s*)/)[1].length;
    let tag = null, content = null, startN = 1;
    if ((m = line.match(/^\s*(\d+)\.\s+(.*)/))) { tag = 'ol'; startN = +m[1]; content = m[2]; }
    else if ((m = line.match(/^\s*[-*]\s+(.*)/))) { tag = 'ul'; content = m[1]; }
    if (tag) {
      while (stack.length && stack[stack.length - 1].indent > indent) closeOne(); // đóng list con sâu hơn
      const top = stack[stack.length - 1];
      if (!top || top.indent < indent) { openList(tag, startN); stack[stack.length - 1].indent = indent; html += '<li>' + mdInlineHelp(content); } // mở list lồng trong <li> cha đang mở
      else if (top.tag === tag) { html += '</li><li>' + mdInlineHelp(content); } // item anh-em
      else { closeOne(); openList(tag, startN); stack[stack.length - 1].indent = indent; html += '<li>' + mdInlineHelp(content); } // cùng mức, khác loại list
      continue;
    }
    closeAll(); html += '<p>' + mdInlineHelp(line) + '</p>';
  }
  closeAll();
  return html;
}
// Tách spec → { title, intro, cards:[{title,html}] }. Dừng ở "## Thay đổi" (không cho user xem changelog).
function parseHelpDoc(md) {
  const lines = String(md || '').split(/\r?\n/);
  let title = '', intro = '';
  const sections = []; let cur = null;
  for (const raw of lines) {
    const line = raw.replace(/\s+$/, ''); let m;
    if ((m = line.match(/^#\s+(.*)/))) { title = m[1].replace(/^Module:\s*/i, '').replace(/\s*\(`[^`]*`\)\s*$/, '').trim(); continue; }
    if ((m = line.match(/^##\s+(.*)/))) { const h = m[1].trim(); if (/^Thay đổi/i.test(h)) break; cur = { title:h, lines:[] }; sections.push(cur); continue; }
    if (!cur) { if (/^>\s?/.test(line)) intro += (intro ? ' ' : '') + line.replace(/^>\s?/, ''); continue; }
    cur.lines.push(line);
  }
  return { title, intro, cards: sections.map(s => ({ title:s.title, html:mdBodyToHtml(s.lines) })) };
}

function ModuleHelp({ moduleId, app }) {
  const { tt, lang } = useLang();
  const [st, setSt] = React.useState({ loading: true, doc: null, err: false });
  const [active, setActive] = React.useState(0);
  const contentRef = React.useRef(null);
  const tocRef = React.useRef(null);
  React.useEffect(() => {
    let alive = true;
    setSt({ loading: true, doc: null, err: false });
    setActive(0);
    fetch('/docs/modules/module-' + moduleId + '-spec.md', { cache: 'no-cache' })
      .then(r => { if (!r.ok) throw new Error(r.status); return r.text(); })
      .then(txt => { if (alive) setSt({ loading: false, doc: parseHelpDoc(txt), err: false }); })
      .catch(() => { if (alive) setSt({ loading: false, doc: null, err: true }); });
    return () => { alive = false; };
  }, [moduleId]);

  // Scroll-spy: tô sáng mục đang xem ở cột nội dung (cuộn trong vùng .help-content).
  React.useEffect(() => {
    const root = contentRef.current;
    if (!root || !st.doc) return;
    let raf = 0;
    const recompute = () => {
      raf = 0;
      const secs = root.querySelectorAll('.help-sec');
      if (!secs.length) return;
      const trigger = root.scrollTop + 24;
      let idx = 0;
      for (let i = 0; i < secs.length; i++) {
        if (secs[i].offsetTop <= trigger) idx = i; else break;
      }
      if (root.scrollTop + root.clientHeight >= root.scrollHeight - 4) idx = secs.length - 1; // chạm đáy → mục cuối
      setActive(idx);
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(recompute); };
    root.addEventListener('scroll', onScroll, { passive: true });
    recompute();
    return () => { root.removeEventListener('scroll', onScroll); if (raf) cancelAnimationFrame(raf); };
  }, [st.doc]);

  // Giữ mục đang chọn luôn nhìn thấy trong cột mục lục.
  React.useEffect(() => {
    const t = tocRef.current; if (!t) return;
    const el = t.querySelector('button.is-active');
    if (el && el.scrollIntoView) el.scrollIntoView({ block: 'nearest' });
  }, [active]);

  const goTo = (i) => {
    const root = contentRef.current; if (!root) return;
    const sec = root.querySelectorAll('.help-sec')[i]; if (!sec) return;
    setActive(i);
    if (root.scrollHeight - root.clientHeight > 4) root.scrollTo({ top: Math.max(0, sec.offsetTop - 4), behavior: 'smooth' });
    else sec.scrollIntoView({ behavior: 'smooth', block: 'start' });
  };

  const heading = lang === 'vi' ? 'Hướng dẫn sử dụng' : 'User guide';
  const name = (st.doc && st.doc.title) || (app ? tt(app.name) : '');
  const accent = (app && app.color) || 'var(--primary)';
  const ready = st.doc && !st.loading && !st.err;
  return (
    <div className="page pagefade help-page">
      <div className="page-head"><div>
        <h1><i className="bi bi-life-preserver" style={{ marginRight: 8, color: app && app.color }}></i>{heading}{name ? ' · ' + name : ''}</h1>
        {st.doc && st.doc.intro && <div className="sub">{st.doc.intro}</div>}
      </div></div>
      {st.loading && <div className="card muted">{lang === 'vi' ? 'Đang tải hướng dẫn…' : 'Loading…'}</div>}
      {st.err && <div className="card"><i className="bi bi-exclamation-triangle" style={{ marginRight: 6 }}></i>{lang === 'vi' ? 'Chưa có hướng dẫn cho phần này (hoặc đang offline).' : 'No guide yet (or offline).'}</div>}
      {ready && st.doc.cards.length === 0 && (
        <div className="card muted">{lang === 'vi' ? 'Chưa có nội dung hướng dẫn.' : 'No guide content yet.'}</div>
      )}
      {ready && st.doc.cards.length > 0 && (
        <div className="help-doc" style={{ '--help-accent': accent }}>
          <nav className="help-toc" ref={tocRef} aria-label={lang === 'vi' ? 'Mục lục' : 'Contents'}>
            <div className="help-toc-label">{lang === 'vi' ? 'Mục lục' : 'Contents'}</div>
            <ol>
              {st.doc.cards.map((c, i) => (
                <li key={i}>
                  <button type="button" className={i === active ? 'is-active' : ''} onClick={() => goTo(i)}>{c.title}</button>
                </li>
              ))}
            </ol>
          </nav>
          <div className="help-content" ref={contentRef}>
            {st.doc.cards.map((c, i) => (
              <section key={i} className="help-sec">
                <h2>{c.title}</h2>
                <div className="help-body" dangerouslySetInnerHTML={{ __html: c.html }} />
              </section>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { ModuleHelp, parseHelpDoc, mdBodyToHtml });
