<script lang="ts">
  // 문서 상세 좌측 절(section) 목차 (PR-DocSrv-Hier-Section-UI-1).
  // - ASME 등 구조화 코드(buildPartOutline.hasParts): front-matter 단일 접이그룹 + PART 접이
  //   (기본 접힘, 1030 flat → ~14 top-level). scroll-spy/딥링크 진입 시 조상 PART auto-expand. (D8)
  // - 그 외(per-doc): groupOrFlat 폴백 — top-segment 1단 그룹 vs flat(5140/5186/비-ASME 무회귀).
  // - 항목 클릭 → 인라인 아코디언으로 요약/section_type/heading_path breadcrumb 표시.
  import { untrack } from 'svelte';
  import Badge from '$lib/components/ui/Badge.svelte';
  import {
    cleanHeading,
    pathSegments,
    groupOrFlat,
    buildPartOutline,
    partGroupViews,
    groupKeyByChunkId,
    sectionTypeLabel,
    type DocumentSection,
    type OutlineItem,
  } from '$lib/utils/headingPath';

  interface Props {
    sections: DocumentSection[];
    /** 항목 클릭 시 본문 점프 콜백(부모가 #sec-{chunkId} scrollIntoView). 없으면 아코디언만. */
    onJump?: (chunkId: number) => void;
    /** scroll-spy 현재 절(chunk_id) — 강조 + Part auto-expand. */
    activeKey?: number | null;
  }
  let { sections, onJump, activeKey = null }: Props = $props();

  let partOutline = $derived(buildPartOutline(sections));
  // hasParts(ASME 등): Part 접이 모드. 아니면 partViews=null → groupOrFlat 폴백.
  let partViews = $derived(partOutline.hasParts ? partGroupViews(partOutline) : null);
  let layout = $derived.by(() => (partOutline.hasParts ? null : groupOrFlat(sections)));
  let groupIndex = $derived(partViews ? groupKeyByChunkId(partViews) : null);
  let total = $derived(sections.length);

  let selectedId = $state<number | null>(null);
  // Part 그룹 접이 상태: key 없으면 접힘(기본 전부 접힘). $state Record = Svelte5 deep-proxy 반응형.
  let expanded = $state<Record<string, boolean>>({});
  function toggleGroup(key: string) {
    expanded[key] = !expanded[key];
  }
  // 문서 전환(DocumentViewer 가 sections prop 교체) 시 접이/선택 리셋 — 문서 간 PART 라벨/chunk_id 가
  // 우연히 겹쳐 이전 펼침/선택이 이월되는 것 차단(기본 전부 접힘 불변식 보존). untrack=쓰기 자기재발화 차단.
  $effect(() => {
    void sections;
    untrack(() => { expanded = {}; selectedId = null; });
  });
  // scroll-spy/딥링크 활성 절의 조상 Part 를 펼침(다른 그룹은 건드리지 않음). untrack=쓰기 자기재발화 차단.
  $effect(() => {
    const ak = activeKey;
    const idx = groupIndex;
    if (ak == null || !idx) return;
    const gk = idx.get(ak);
    if (gk) untrack(() => { expanded[gk] = true; });
  });

  function toggle(item: OutlineItem) {
    const id = item.section.chunk_id;
    selectedId = selectedId === id ? null : id;
  }
  function title(s: DocumentSection): string {
    return cleanHeading(s.section_title) || pathSegments(s.heading_path).at(-1) || '(제목 없음)';
  }
  function isLowConf(s: DocumentSection): boolean {
    return s.confidence != null && s.confidence < 0.5;
  }
</script>

{#snippet itemRow(item: OutlineItem)}
  {@const s = item.section}
  {@const open = selectedId === s.chunk_id}
  {@const active = activeKey != null && activeKey === s.chunk_id}
  {@const typeLabel = sectionTypeLabel(s.section_type)}
  {@const depth = Math.max(0, (s.level ?? 1) - 1)}
  <li>
    <button
      type="button"
      onclick={() => { toggle(item); onJump?.(s.chunk_id); }}
      aria-expanded={open}
      aria-current={active ? 'true' : undefined}
      style="padding-left:{8 + depth * 13}px"
      class={[
        'w-full text-left pr-2 py-1.5 rounded-md text-xs flex items-start gap-1.5 transition-colors border-l-2',
        depth > 0 ? 'text-[11px]' : '',
        open ? 'bg-surface-active text-text border-accent' : active ? 'bg-surface text-accent-hover border-accent' : 'text-dim hover:bg-surface hover:text-text border-transparent',
      ].join(' ')}
    >
      <span class="flex-1 min-w-0 leading-snug break-words">{title(s)}</span>
      <span class="flex items-center gap-1 shrink-0">
        {#if item.fragmentCount > 1}
          <Badge tone="neutral" size="sm">{item.fragmentCount}조각</Badge>
        {/if}
        {#if typeLabel}
          <Badge tone="accent" size="sm">{typeLabel}</Badge>
        {/if}
      </span>
    </button>
    {#if open}
      <div class="px-2 pb-2 pt-1 text-xs">
        {#if pathSegments(s.heading_path).length}
          <div class="text-faint mb-1 leading-snug break-words">
            {pathSegments(s.heading_path).join(' › ')}
          </div>
        {/if}
        {#if s.summary}
          <p class="text-text leading-relaxed whitespace-pre-line">{s.summary}</p>
          {#if isLowConf(s)}
            <div class="mt-1.5">
              <Badge tone="warning" size="sm">저신뢰 — 표 추출이 불완전할 수 있음</Badge>
            </div>
          {/if}
        {:else}
          <p class="text-faint italic">요약 없음 — 짧은 절이거나 아직 분석되지 않았습니다.</p>
        {/if}
      </div>
    {/if}
  </li>
{/snippet}

<div class="text-xs">
  <h3 class="text-xs font-semibold text-dim uppercase mb-2 flex items-center justify-between">
    <span>절 목차</span>
    <span class="text-faint font-normal">{total}</span>
  </h3>

  {#if partViews}
    <!-- Part 접이 모드 (ASME 등): front-matter 단일 그룹 + PART 접이, 기본 접힘 -->
    <div class="space-y-1">
      {#each partViews as g (g.key)}
        {@const isOpen = !!expanded[g.key]}
        <div>
          <button
            type="button"
            onclick={() => toggleGroup(g.key)}
            aria-expanded={isOpen}
            class={[
              'w-full flex items-center gap-1.5 px-2 py-1.5 rounded-md text-[11px] font-semibold uppercase tracking-wide transition-colors',
              g.isFrontMatter ? 'text-faint' : 'text-dim',
              'hover:bg-surface hover:text-text',
            ].join(' ')}
          >
            <span class="shrink-0 transition-transform duration-150 {isOpen ? 'rotate-90' : ''}">›</span>
            <span class="flex-1 min-w-0 text-left truncate normal-case">{g.label}</span>
            <span class="font-normal text-faint">{g.items.length}</span>
          </button>
          {#if isOpen}
            <ul class="space-y-0.5 mt-0.5">
              {#each g.items as item (item.section.chunk_id)}
                {@render itemRow(item)}
              {/each}
            </ul>
          {/if}
        </div>
      {/each}
    </div>
  {:else if layout?.mode === 'group'}
    <div class="space-y-3">
      {#each layout.groups as g (g.key)}
        <div>
          <div
            class={[
              'px-2 mb-1 text-[11px] font-semibold uppercase tracking-wide',
              g.isOther ? 'text-faint' : 'text-dim',
            ].join(' ')}
          >
            {g.key}
            <span class="font-normal text-faint">({g.items.length})</span>
          </div>
          <ul class="space-y-0.5">
            {#each g.items as item (item.section.chunk_id)}
              {@render itemRow(item)}
            {/each}
          </ul>
        </div>
      {/each}
    </div>
  {:else}
    <ul class="space-y-0.5">
      {#each layout?.items ?? [] as item (item.section.chunk_id)}
        {@render itemRow(item)}
      {/each}
    </ul>
  {/if}
</div>
