<script>
  // ASME/법령 절-KB — 코드북·공부 리더 (r2). parent 표준/법령을 한 권의 책처럼.
  // 좌 인덱스(Part/章→절/조) · 중 본문(MarkdownDoc=공식·표·이미지) · breadcrumb·이전다음·양방향 백링크.
  import { onMount, tick } from 'svelte';
  import { page } from '$app/stores';
  import { goto } from '$app/navigation';
  import { api } from '$lib/api';
  import MarkdownDoc from '$lib/components/MarkdownDoc.svelte';

  let parentId = $state(null);
  let parentTitle = $state('');
  let clauses = $state([]);
  let selectedId = $state(null);
  let clauseDoc = $state(null);
  let links = $state(null);
  let expanded = $state({});
  let loading = $state(false);
  let q = $state('');

  // 공부도구 (노트/형광펜/암기카드) — clause_study
  let studyItems = $state([]);
  let studyOpen = $state(false);
  let noteDraft = $state('');
  const KLABEL = { note: '노트', highlight: '형광펜', card: '암기카드' };
  async function loadStudy(id) {
    try { const r = await api(`/documents/${id}/study`); studyItems = r?.items ?? []; }
    catch { studyItems = []; }
  }
  async function addStudy(kind, payload) {
    if (!selectedId) return;
    try { await api(`/documents/${selectedId}/study`, { method: 'POST', body: JSON.stringify({ kind, payload }) }); await loadStudy(selectedId); }
    catch (e) { console.warn(e); }
  }
  function selText() { return (typeof window !== 'undefined' && window.getSelection ? window.getSelection().toString() : '').trim(); }
  function addNote() { const t = noteDraft.trim(); if (!t) return; addStudy('note', { text: t }); noteDraft = ''; }
  function addHighlight() { const s = selText(); if (!s) { studyOpen = true; alert('본문에서 형광펜 칠할 부분을 먼저 드래그하세요'); return; } addStudy('highlight', { text: s }); studyOpen = true; }
  function addCard() {
    const s = selText();
    const code = links?.clause_code ?? selMeta?.clause_code ?? '';
    addStudy('card', { cue: `${code} ${strip(clauseDoc?.title, code)}`.trim(), fact: s || (clauseDoc?.md_content ?? clauseDoc?.extracted_text ?? '').replace(/[#*>]/g, '').slice(0, 280).trim() });
    studyOpen = true;
  }
  async function delStudy(id) {
    try { await api(`/documents/${selectedId}/study/${id}`, { method: 'DELETE' }); await loadStudy(selectedId); } catch {}
  }

  let parts = $derived.by(() => {
    const out = [], idx = {};
    for (const c of clauses) {
      const p = c.clause_part || '·';
      if (!(p in idx)) { idx[p] = out.length; out.push({ part: p, items: [] }); }
      out[idx[p]].items.push(c);
    }
    return out;
  });
  let visibleParts = $derived.by(() => {
    const term = q.trim().toLowerCase();
    if (!term) return parts;
    return parts.map(g => ({ part: g.part, items: g.items.filter(c =>
      (c.clause_code || '').toLowerCase().includes(term) || (c.title || '').toLowerCase().includes(term)) }))
      .filter(g => g.items.length);
  });
  let selMeta = $derived(clauses.find((c) => c.id === selectedId) || null);
  const strip = (t, c) => (t || '').replace(c || '', '').replace(/^[(\s)]+|[(\s)]+$/g, '').trim();

  async function loadBook() {
    const r = await api(`/documents/${parentId}/clauses`);
    parentTitle = r?.parent_title ?? '';
    clauses = r?.clauses ?? [];
    const e = {};
    for (const c of clauses) e[c.clause_part || '·'] = true;
    expanded = e;
  }
  async function loadClause(id) {
    if (!id) return;
    loading = true;
    selectedId = id;
    try {
      const [d, l] = await Promise.all([api(`/documents/${id}`), api(`/documents/${id}/backlinks`)]);
      clauseDoc = d; links = l;
      loadStudy(id);
      const sel = clauses.find((c) => c.id === id);
      if (sel) expanded = { ...expanded, [sel.clause_part || '·']: true };
      goto(`/book/${parentId}?c=${id}`, { replaceState: true, keepFocus: true, noScroll: true });
      await tick(); window.scrollTo({ top: 0 });
    } finally { loading = false; }
  }
  onMount(async () => {
    parentId = Number($page.params.id);
    await loadBook();
    const c = Number($page.url.searchParams.get('c'));
    await loadClause(c && clauses.find((x) => x.id === c) ? c : clauses[0]?.id);
  });
</script>

<div class="book">
  <!-- top bar -->
  <div class="bar">
    <span class="brand">절-KB</span>
    <span class="crumbs">{parentTitle} {#if selMeta}<b class="sep">›</b> {selMeta.clause_part} <b class="sep">›</b> <b>{links?.clause_code ?? selMeta.clause_code}</b>{/if}</span>
    <div class="search"><input placeholder="절·조 번호 또는 키워드" bind:value={q} /></div>
    <div class="tools"><span class="tool on">읽기</span><span class="tool">형광펜</span><span class="tool">노트</span><span class="tool">암기카드</span></div>
  </div>

  <div class="main">
    <!-- left index -->
    <aside class="idx">
      <a class="btitle" href={`/documents/${parentId}`}>{parentTitle || '표준'}</a>
      <div class="bmeta">절 {clauses.length} · 한 권의 책처럼 탐색</div>
      {#each visibleParts as g (g.part)}
        <div class="parttab" role="button" tabindex="0" onclick={() => (expanded = { ...expanded, [g.part]: !expanded[g.part] })}>
          <span class="bar2"></span><span class="pname">{g.part}</span><span class="ct">{g.items.length}</span>
        </div>
        {#if expanded[g.part] || q.trim()}
          {#each g.items as c (c.id)}
            <div class="ci" class:on={c.id === selectedId} role="button" tabindex="0" onclick={() => loadClause(c.id)}>
              <span class="no">{c.clause_code}</span><span class="tt">{strip(c.title, c.clause_code)}</span>
            </div>
          {/each}
        {/if}
      {/each}
    </aside>

    <!-- reader -->
    <section class="read">
      <div class="col">
        {#if clauseDoc}
          <div class="studybar">
            <button class="sbtn" title="선택 형광펜" onclick={addHighlight}>▰</button>
            <button class="sbtn" class:on={studyOpen} title="노트/공부" onclick={() => (studyOpen = !studyOpen)}>✎</button>
            <button class="sbtn" title="암기카드 추가" onclick={addCard}>＋</button>
            {#if studyItems.length}<span class="scount">{studyItems.length}</span>{/if}
          </div>
          <div class="kicker"><span class="pth">{selMeta?.clause_part}</span></div>
          <div class="h-no">{links?.clause_code ?? selMeta?.clause_code}</div>
          <h1 class="h-title">{strip(clauseDoc.title, links?.clause_code ?? '')}</h1>

          <div class="flow">
            <button class="fl" disabled={!links?.prev} onclick={() => loadClause(links?.prev?.id)}>← {links?.prev?.clause_code ?? ''}</button>
            <button class="fl next" disabled={!links?.next} onclick={() => loadClause(links?.next?.id)}>{links?.next?.clause_code ?? ''} →</button>
          </div>

          {#key clauseDoc.id}
            <div class="docbody">
              <MarkdownDoc documentId={clauseDoc.id} mdContent={clauseDoc.md_content ?? clauseDoc.extracted_text} mdStatus={null} class="prose prose-base max-w-none" />
            </div>
          {/key}

          {#if links && (links.forward.length || links.back.length)}
            <section class="conn">
              {#if links.forward.length}
                <div><h4>이 절이 참조 <span>{links.forward.length}</span></h4>
                  <div class="chiprow">{#each links.forward as f}
                    {#if f.doc_id}<button class="ref" onclick={() => loadClause(f.doc_id)}>{f.code}</button>
                    {:else}<span class="ref dg" title="외부/미분해">{f.code}</span>{/if}
                  {/each}</div></div>
              {/if}
              {#if links.back.length}
                <div><h4>이 절을 참조 <span>{links.back.length}</span></h4>
                  <div class="chiprow">{#each links.back as b}<button class="ref" onclick={() => loadClause(b.doc_id)}>{b.code}</button>{/each}</div></div>
              {/if}
            </section>
          {/if}

          {#if studyOpen}
            <section class="study">
              <div class="slab">공부 — 노트 · 형광펜 · 암기카드{#if studyItems.length} <span>{studyItems.length}</span>{/if}</div>
              <div class="noteadd">
                <textarea bind:value={noteDraft} placeholder="이 절에 노트…" rows="2"></textarea>
                <button class="nbtn" onclick={addNote}>노트 저장</button>
              </div>
              {#if studyItems.length}
                <ul class="slist">
                  {#each studyItems as it (it.id)}
                    <li class="sitem">
                      <span class="skind k-{it.kind}">{KLABEL[it.kind] ?? it.kind}</span>
                      <span class="stext">{it.payload?.text ?? it.payload?.cue ?? ''}</span>
                      <button class="sdel" title="삭제" onclick={() => delStudy(it.id)}>×</button>
                    </li>
                  {/each}
                </ul>
              {:else}
                <p class="shint">본문을 드래그한 뒤 형광펜(▰)/암기카드(＋), 또는 위에 노트를 적으세요.</p>
              {/if}
            </section>
          {/if}

          <div class="pager">
            <button class="pg" disabled={!links?.prev} onclick={() => loadClause(links?.prev?.id)}>
              <div class="d">← 이전</div><div class="t"><span class="pno">{links?.prev?.clause_code ?? '—'}</span> {strip(links?.prev?.title, links?.prev?.clause_code)}</div></button>
            <button class="pg next" disabled={!links?.next} onclick={() => loadClause(links?.next?.id)}>
              <div class="d">다음 →</div><div class="t"><span class="pno">{links?.next?.clause_code ?? '—'}</span> {strip(links?.next?.title, links?.next?.clause_code)}</div></button>
          </div>
        {:else}
          <p class="empty">{loading ? '불러오는 중…' : '왼쪽에서 절을 선택하세요'}</p>
        {/if}
      </div>
    </section>
  </div>
</div>

<style>
  :global(body) { background: var(--bg); }
  .book { --paper:#fbfcf9; --serif:"Iowan Old Style","Palatino Linotype","Noto Serif KR",Georgia,serif;
    display:flex; flex-direction:column; min-height:100vh; }
  .bar { display:flex; align-items:center; gap:14px; height:50px; padding:0 18px; background:var(--paper); border-bottom:1px solid var(--border); }
  .brand { font-weight:700; font-size:13.5px; color:var(--text); }
  .crumbs { color:var(--text-dim); font-size:12.5px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:46%; }
  .crumbs b { color:var(--text); font-weight:600; } .crumbs .sep { color:#c8d6c0; margin:0 5px; }
  .search { margin-left:auto; }
  .search input { width:280px; background:var(--surface); border:1px solid var(--border); border-radius:9px; padding:7px 12px; font-size:13px; color:var(--text); outline:none; }
  .search input:focus { border-color:var(--accent); }
  .tools { display:flex; gap:2px; }
  .tool { font-size:12px; color:var(--text-dim); padding:6px 10px; border-radius:8px; border:1px solid transparent; cursor:pointer; }
  .tool:hover { background:var(--surface); } .tool.on { background:#ecf0e8; border-color:var(--border); color:var(--accent-hover); font-weight:600; }

  .main { display:flex; align-items:flex-start; flex:1; }
  .idx { width:264px; flex-shrink:0; align-self:stretch; border-right:1px solid var(--border);
    background:linear-gradient(180deg,#f6f8f3,#f1f4ec); padding:16px 10px 30px 16px; position:sticky; top:0; max-height:100vh; overflow:auto; }
  .btitle { display:block; font-family:var(--serif); font-size:15.5px; font-weight:600; color:var(--text); text-decoration:none; line-height:1.32; }
  .btitle:hover { text-decoration:underline; }
  .bmeta { font-size:11px; color:#9aa090; margin:3px 0 14px; }
  .parttab { display:flex; align-items:center; gap:8px; margin:11px 0 4px; padding:3px 4px; border-radius:6px; cursor:pointer;
    font-size:11px; font-weight:700; letter-spacing:.5px; color:var(--text-dim); text-transform:uppercase; }
  .parttab:hover { background:#fff; } .parttab .bar2 { width:3px; height:12px; border-radius:2px; background:var(--domain-engineering); }
  .parttab .pname { flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; } .parttab .ct { color:#9aa090; font-weight:600; letter-spacing:0; }
  .ci { display:flex; gap:9px; align-items:baseline; padding:4px 9px; border-radius:7px; cursor:pointer; line-height:1.4; }
  .ci .no { font-family:ui-monospace,Menlo,monospace; font-size:11px; color:var(--accent); font-weight:600; min-width:52px; white-space:nowrap; }
  .ci .tt { font-size:12.5px; color:var(--text-dim); overflow:hidden; text-overflow:ellipsis; }
  .ci:hover { background:#fff; }
  .ci.on { background:#fff; box-shadow:inset 3px 0 0 var(--accent), 0 1px 2px rgba(35,41,31,.05); }
  .ci.on .no { color:var(--accent-hover); font-weight:700; } .ci.on .tt { color:var(--text); font-weight:600; }

  .read { flex:1; min-width:0; padding:34px 40px 80px; }
  .col { max-width:680px; margin:0 auto; position:relative; }
  .studybar { position:absolute; right:-30px; top:4px; display:flex; flex-direction:column; gap:6px; }
  .sbtn { width:34px; height:34px; border-radius:9px; border:1px solid var(--border); background:var(--paper); color:var(--text-dim); font-size:13px; cursor:pointer; }
  .sbtn:hover { background:var(--surface); color:var(--accent-hover); }
  .kicker { margin-bottom:5px; } .kicker .pth { font-size:11.5px; color:#9aa090; font-weight:600; letter-spacing:.3px; }
  .h-no { font-family:ui-monospace,Menlo,monospace; font-size:13px; color:var(--accent); font-weight:700; letter-spacing:.5px; }
  .h-title { font-family:var(--serif); font-size:26px; line-height:1.24; font-weight:600; margin:2px 0 14px; letter-spacing:-.2px; color:var(--text); }
  .flow { display:flex; justify-content:space-between; gap:8px; margin-bottom:18px; }
  .flow .fl { font-size:11.5px; color:var(--text-dim); background:var(--surface); border:1px solid var(--border); border-radius:8px; padding:5px 11px; cursor:pointer; }
  .flow .fl:hover:not(:disabled) { background:#ecf0e8; } .flow .fl:disabled { opacity:.35; cursor:default; }
  .docbody { font-size:15.5px; }
  .docbody :global(.prose) { color:#2a3024; line-height:1.78; }
  .docbody :global(.prose h1), .docbody :global(.prose h2), .docbody :global(.prose h3) { font-family:var(--serif); }
  .docbody :global(a) { color:var(--accent-hover); }
  .conn { margin-top:34px; padding-top:18px; border-top:1px solid var(--border); display:grid; grid-template-columns:1fr 1fr; gap:22px; }
  .conn h4 { font-size:11px; font-weight:700; color:var(--text-dim); letter-spacing:.4px; margin:0 0 9px; } .conn h4 span { color:#9aa090; font-weight:500; }
  .chiprow { display:flex; flex-wrap:wrap; gap:5px; }
  .ref { font-family:ui-monospace,Menlo,monospace; font-size:11.5px; font-weight:600; color:var(--accent-hover); background:#eef4ec; border:1px solid #d9e6d8; border-radius:6px; padding:2px 8px; cursor:pointer; }
  .ref:hover { background:#e2efe0; } .ref.dg { color:#9aa090; background:var(--surface); border-color:var(--border); cursor:default; }
  .pager { display:flex; gap:10px; margin-top:30px; }
  .pg { flex:1; text-align:left; border:1px solid var(--border); border-radius:11px; padding:11px 14px; background:var(--paper); cursor:pointer; }
  .pg.next { text-align:right; } .pg:hover:not(:disabled) { border-color:#cfd7c6; background:#fff; } .pg:disabled { opacity:.4; cursor:default; }
  .pg .d { font-size:10.5px; color:#9aa090; } .pg .t { font-size:12.5px; color:var(--text-dim); font-weight:600; margin-top:1px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .pg .pno { font-family:ui-monospace,Menlo,monospace; color:var(--accent); }
  .empty { color:#9aa090; text-align:center; padding:80px 0; }
  .sbtn.on { background:#ecf0e8; color:var(--accent-hover,#3d7256); border-color:var(--border); }
  .scount { font-size:9px; font-weight:700; color:#fff; background:var(--accent,#4f8a6b); border-radius:8px; padding:1px 5px; text-align:center; }
  .study { margin-top:24px; padding:14px; border:1px solid var(--border); border-radius:12px; background:var(--surface); }
  .slab { font-size:11px; font-weight:700; color:var(--text-dim); letter-spacing:.3px; margin-bottom:9px; }
  .slab span { color:var(--accent-hover,#3d7256); }
  .noteadd { display:flex; gap:8px; align-items:flex-end; margin-bottom:10px; }
  .noteadd textarea { flex:1; resize:vertical; border:1px solid var(--border); border-radius:8px; padding:7px 9px; font-size:12.5px; font-family:inherit; color:var(--text); background:var(--paper,#fbfcf9); outline:none; }
  .noteadd textarea:focus { border-color:var(--accent); }
  .nbtn { flex-shrink:0; font-size:12px; color:#fff; background:var(--accent,#4f8a6b); border:0; border-radius:8px; padding:8px 12px; cursor:pointer; }
  .nbtn:hover { background:var(--accent-hover,#3d7256); }
  .slist { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:5px; }
  .sitem { display:flex; align-items:baseline; gap:8px; padding:6px 8px; border-radius:8px; background:var(--paper,#fbfcf9); border:1px solid var(--border); }
  .skind { flex-shrink:0; font-size:9.5px; font-weight:700; border-radius:4px; padding:1px 6px; }
  .k-note { color:#3d7256; background:#e3efe2; border:1px solid #cfe3cd; }
  .k-highlight { color:#8a6306; background:#faf3e2; border:1px solid #ecdca3; }
  .k-card { color:#1d4ed8; background:#eef4fc; border:1px solid #d7e4f7; }
  .stext { flex:1; font-size:12px; line-height:1.5; color:var(--text); white-space:pre-wrap; word-break:break-word; }
  .sdel { flex-shrink:0; background:none; border:0; color:var(--faint,#9aa090); cursor:pointer; font-size:14px; }
  .sdel:hover { color:var(--error,#c0392b); }
  .shint { font-size:11.5px; color:var(--faint,#9aa090); margin:0; }
  @media(max-width:820px){ .idx{display:none} .read{padding:24px 18px} .conn{grid-template-columns:1fr} .studybar{position:static;flex-direction:row} .crumbs{max-width:30%} .search input{width:150px} }
</style>
