/* gl-core.jsx — 마크다운 렌더러, TOC 추출, useGlSession, 공통 스타일 */

const GL_MD_CSS = `
.gl-body { font-family:"Pretendard Variable",Pretendard,system-ui,sans-serif; padding:14px 15px 32px; }
.gl-h1 { font-size:15px;font-weight:800;color:#181c1a;margin:0 0 10px;line-height:1.35; }
.gl-h2 { font-size:13.5px;font-weight:800;color:#1a6c5b;margin:20px 0 7px;padding-bottom:5px;border-bottom:1.5px solid #d4ece5;scroll-margin-top:8px; }
.gl-h3 { font-size:13px;font-weight:700;color:#181c1a;margin:14px 0 5px;scroll-margin-top:8px; }
.gl-h4 { font-size:12px;font-weight:700;color:#5f6b66;margin:10px 0 4px; }
.gl-p  { font-size:12.5px;color:#2d3330;line-height:1.7;margin:0 0 7px;text-wrap:pretty; }
.gl-ul,.gl-ol { font-size:12.5px;color:#2d3330;line-height:1.68;margin:0 0 8px;padding-left:17px; }
.gl-ul li,.gl-ol li { margin:3px 0; }
.gl-li-sub { margin-left:14px;list-style:circle; }
.gl-quote { margin:9px 0;padding:9px 12px;background:#eef5f2;border-left:3px solid #1a6c5b;border-radius:0 8px 8px 0;font-size:12px;color:#14473b;line-height:1.6; }
.gl-quote strong { color:#1a6c5b; }
.gl-table-wrap { overflow-x:auto;margin:8px 0 12px;border-radius:9px;border:1px solid #dde0dc;-webkit-overflow-scrolling:touch; }
.gl-table { width:100%;border-collapse:collapse;font-size:11.5px; }
.gl-table th { background:#eef0ee;padding:7px 9px;text-align:left;font-weight:700;color:#181c1a;border-bottom:1px solid #d9dcd8;white-space:nowrap; }
.gl-table td { padding:6px 9px;border-bottom:1px solid #f0f0ee;color:#2d3330;vertical-align:top; }
.gl-table tr:last-child td { border-bottom:none; }
.gl-table tr:nth-child(even) td { background:#f7f9f7; }
.gl-hr { border:none;border-top:1px solid #e8ebe7;margin:18px 0; }
.gl-body code { font-family:monospace;font-size:11px;background:#f0f2f0;padding:1px 5px;border-radius:4px;color:#1a6c5b; }
`;

function injectGlStyles() {
  if (document.getElementById('gl-md-styles')) return;
  const s = document.createElement('style');
  s.id = 'gl-md-styles';
  s.textContent = GL_MD_CSS;
  document.head.appendChild(s);
}

function parseInline(text) {
  const parts = text.split(/(\*\*[^*]+?\*\*|\*[^*]+?\*|`[^`]+`)/g);
  return parts.map((p, i) => {
    if (p.startsWith('**') && p.endsWith('**')) return <strong key={i}>{p.slice(2, -2)}</strong>;
    if (p.startsWith('*') && p.endsWith('*') && p.length > 2) return <em key={i}>{p.slice(1, -1)}</em>;
    if (p.startsWith('`') && p.endsWith('`')) return <code key={i}>{p.slice(1, -1)}</code>;
    return p;
  });
}

function slugify(t) {
  return 'gl-' + t.replace(/\s+/g, '-').replace(/[^가-힣ᄀ-ᇿa-zA-Z0-9\-]/g, '').slice(0, 60);
}

function parseMarkdown(md) {
  if (!md) return [];
  const lines = md.split('\n');
  const out = [];
  let i = 0;

  while (i < lines.length) {
    const ln = lines[i];
    if (ln.trimStart().startsWith('<!--')) { i++; continue; }
    if (/^# [^#]/.test(ln)) {
      out.push(<h1 key={i} className="gl-h1">{parseInline(ln.slice(2).trim())}</h1>);
      i++; continue;
    }
    if (/^## [^#]/.test(ln)) {
      const t = ln.slice(3).trim();
      out.push(<h2 key={i} id={slugify(t)} className="gl-h2">{parseInline(t)}</h2>);
      i++; continue;
    }
    if (/^### [^#]/.test(ln)) {
      const t = ln.slice(4).trim();
      out.push(<h3 key={i} id={slugify(t)} className="gl-h3">{parseInline(t)}</h3>);
      i++; continue;
    }
    if (/^#### /.test(ln)) {
      out.push(<h4 key={i} className="gl-h4">{parseInline(ln.slice(5).trim())}</h4>);
      i++; continue;
    }
    if (ln.startsWith('> ') || ln === '>') {
      const bq = [];
      while (i < lines.length && (lines[i].startsWith('> ') || lines[i] === '>')) {
        bq.push(lines[i].startsWith('> ') ? lines[i].slice(2) : '');
        i++;
      }
      out.push(
        <blockquote key={`bq${i}`} className="gl-quote">
          {bq.map((l, li) => <React.Fragment key={li}>{li > 0 && <br />}{parseInline(l)}</React.Fragment>)}
        </blockquote>
      );
      continue;
    }
    if (ln.startsWith('|')) {
      const rows = [];
      while (i < lines.length && lines[i].startsWith('|')) { rows.push(lines[i]); i++; }
      if (rows.length >= 2) {
        const pr = (r) => r.split('|').map((c) => c.trim()).filter((_, j, a) => j > 0 && j < a.length - 1);
        const heads = pr(rows[0]);
        const body = rows.slice(2).map(pr).filter((r) => r.some((c) => c));
        out.push(
          <div key={`t${i}`} className="gl-table-wrap">
            <table className="gl-table">
              <thead><tr>{heads.map((h, hi) => <th key={hi}>{parseInline(h)}</th>)}</tr></thead>
              <tbody>{body.map((r, ri) => <tr key={ri}>{r.map((c, ci) => <td key={ci}>{parseInline(c)}</td>)}</tr>)}</tbody>
            </table>
          </div>
        );
      }
      continue;
    }
    if (/^-{3,}$/.test(ln.trim())) { out.push(<hr key={i} className="gl-hr" />); i++; continue; }
    if (/^(\s*)[-*+] /.test(ln)) {
      const items = [];
      while (i < lines.length && /^(\s*)[-*+] /.test(lines[i])) {
        const sub = /^\s+/.test(lines[i]);
        items.push({ t: lines[i].replace(/^\s*[-*+] /, ''), sub });
        i++;
      }
      out.push(<ul key={`ul${i}`} className="gl-ul">{items.map((it, idx) => <li key={idx} className={it.sub ? 'gl-li-sub' : ''}>{parseInline(it.t)}</li>)}</ul>);
      continue;
    }
    if (/^\d+\. /.test(ln)) {
      const items = [];
      while (i < lines.length && /^\d+\. /.test(lines[i])) { items.push(lines[i].replace(/^\d+\. /, '')); i++; }
      out.push(<ol key={`ol${i}`} className="gl-ol">{items.map((it, idx) => <li key={idx}>{parseInline(it)}</li>)}</ol>);
      continue;
    }
    if (!ln.trim()) { i++; continue; }
    out.push(<p key={i} className="gl-p">{parseInline(ln)}</p>);
    i++;
  }
  return out;
}

function extractTOC(md) {
  if (!md) return [];
  return md.split('\n')
    .filter((l) => /^#{2,3} [^#]/.test(l))
    .map((l) => {
      const lv = l.startsWith('### ') ? 3 : 2;
      const t = l.replace(/^#{2,3} /, '').trim();
      return { level: lv, text: t, id: slugify(t) };
    });
}

function useGlSession(initKey = 'CV_HF') {
  const [diseaseKey, setDiseaseKeyRaw] = React.useState(initKey);
  const [mode, setModeRaw] = React.useState('summary');
  const [glId, setGlIdRaw] = React.useState(null);
  const [mdContent, setMdContent] = React.useState('');
  const [loading, setLoading] = React.useState(false);
  const [activeId, setActiveId] = React.useState(null);

  const dis = GL_MANIFEST[diseaseKey];

  const effectiveGlId = React.useMemo(() => {
    if (mode !== 'individual') return null;
    if (glId && dis.guidelines.find((g) => g.id === glId)) return glId;
    return dis.guidelines[0] ? dis.guidelines[0].id : null;
  }, [mode, glId, diseaseKey]);

  const selectedGl = effectiveGlId ? dis.guidelines.find((g) => g.id === effectiveGlId) : null;
  const fileToFetch = mode === 'summary' ? dis.summaryFile : selectedGl ? selectedGl.file : null;

  React.useEffect(() => {
    if (!fileToFetch) return;
    let alive = true;
    setLoading(true); setMdContent('');
    fetch(fileToFetch)
      .then((r) => { if (!r.ok) throw new Error(r.status); return r.text(); })
      .then((txt) => { if (alive) { setMdContent(txt); setLoading(false); setActiveId(null); } })
      .catch(() => { if (alive) { setMdContent('파일을 불러오지 못했습니다.'); setLoading(false); } });
    return () => { alive = false; };
  }, [fileToFetch]);

  const toc = React.useMemo(() => extractTOC(mdContent), [mdContent]);

  const setDisease = (k) => { setDiseaseKeyRaw(k); setGlIdRaw(null); setModeRaw('summary'); setActiveId(null); };
  const setMode = (m) => {
    setModeRaw(m);
    if (m === 'individual' && !glId) setGlIdRaw(GL_MANIFEST[diseaseKey].guidelines[0]?.id || null);
    setActiveId(null);
  };
  const setGlId = (id) => { setGlIdRaw(id); setActiveId(null); };

  return { diseaseKey, dis, setDisease, mode, setMode, glId: effectiveGlId, setGlId, selectedGl, mdContent, loading, toc, activeId, setActiveId };
}

function GlGuidelineChips({ guidelines, activeId, onSelect }) {
  if (!guidelines.length) return (
    <div style={{ padding: '10px 14px', fontSize: 11.5, color: RX.faint, fontStyle: 'italic' }}>
      개별 가이드라인 파일 준비 중
    </div>
  );
  return (
    <div style={{ display: 'flex', gap: 6, overflowX: 'auto', padding: '6px 12px', scrollbarWidth: 'none' }}>
      {guidelines.map((g) => {
        const on = g.id === activeId;
        return (
          <button key={g.id} onClick={() => onSelect(g.id)} style={{
            flexShrink: 0, display: 'inline-flex', alignItems: 'center', gap: 5,
            padding: '6px 11px', borderRadius: 8, border: `1px solid ${on ? RX.teal : RX.line}`,
            background: on ? RX.tealTint : '#fff', cursor: 'pointer', font: 'inherit',
            fontSize: 11.5, fontWeight: 700, color: on ? RX.teal : RX.sub,
            whiteSpace: 'nowrap',
          }}>
            <span>{COUNTRY_FLAG[g.country] || '🌍'}</span>
            <span>{g.org}</span>
            <span style={{ fontSize: 10, fontWeight: 600, color: on ? RX.teal : RX.faint }}>{g.year}</span>
          </button>
        );
      })}
    </div>
  );
}

function GlMdContent({ mdContent, loading, toc, activeId, setActiveId, style }) {
  const ref = React.useRef(null);
  React.useLayoutEffect(() => injectGlStyles(), []);

  React.useEffect(() => {
    if (!ref.current || !toc.length) return;
    const root = ref.current;
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) setActiveId(e.target.id); });
    }, { root, rootMargin: '-5% 0px -75% 0px', threshold: 0 });
    root.querySelectorAll('h2,h3').forEach((el) => obs.observe(el));
    return () => obs.disconnect();
  }, [toc]);

  if (loading) return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1, color: RX.faint, fontSize: 13, gap: 8, padding: 40, ...style }}>
      <svg width="20" height="20" viewBox="0 0 24 24" fill="none" style={{ animation: 'spin 1s linear infinite' }}>
        <circle cx="12" cy="12" r="9" stroke={RX.line} strokeWidth="2" />
        <path d="M12 3a9 9 0 019 9" stroke={RX.teal} strokeWidth="2.2" strokeLinecap="round" />
      </svg>
      불러오는 중…
    </div>
  );

  return (
    <div ref={ref} style={{ overflowY: 'auto', flex: 1, ...style }}>
      <div className="gl-body">{parseMarkdown(mdContent)}</div>
      <style>{`@keyframes spin{to{transform:rotate(360deg)}}`}</style>
    </div>
  );
}

window.useGlSession = useGlSession;
window.GlGuidelineChips = GlGuidelineChips;
window.GlMdContent = GlMdContent;
