<script>
  // Phase E.2 — detail 페이지 inline 편집.
  // 기존 read-only 메타 패널(L138–201)을 editors/* 스택으로 교체.
  // + E.3 관련 문서 stub, + 헤더 affordance row.
  import { onMount } from 'svelte';
  import { page } from '$app/stores';
  import { goto } from '$app/navigation';
  import { api, getAccessToken } from '$lib/api';
  import { isMdSuccess } from '$lib/utils/mdStatus';
  import { resolveAnchorMap } from '$lib/utils/resolveAnchorMap';
  import { addToast } from '$lib/stores/toast';
  import { marked } from 'marked';
  import DOMPurify from 'dompurify';
  import { ExternalLink, Download, Link2, FileText, PenLine, X, ChevronLeft, ChevronRight, Check } from 'lucide-svelte';
  import Button from '$lib/components/ui/Button.svelte';
  import Card from '$lib/components/ui/Card.svelte';
  import EmptyState from '$lib/components/ui/EmptyState.svelte';
  import Skeleton from '$lib/components/ui/Skeleton.svelte';
  import HandwriteCanvas from '$lib/components/HandwriteCanvas.svelte';
  import MarkdownDoc from '$lib/components/MarkdownDoc.svelte';
  import MarkdownStatusBadge from '$lib/components/MarkdownStatusBadge.svelte';
  import NoteEditor from '$lib/components/editors/NoteEditor.svelte';
  import EditUrlEditor from '$lib/components/editors/EditUrlEditor.svelte';
  import TagsEditor from '$lib/components/editors/TagsEditor.svelte';
  import AIClassificationEditor from '$lib/components/editors/AIClassificationEditor.svelte';
  import FileInfoView from '$lib/components/editors/FileInfoView.svelte';
  import ProcessingStatusView from '$lib/components/editors/ProcessingStatusView.svelte';
  import LibraryPathEditor from '$lib/components/editors/LibraryPathEditor.svelte';
  import DocumentDangerZone from '$lib/components/editors/DocumentDangerZone.svelte';
  import AnalysisPanel from '$lib/components/AnalysisPanel.svelte';
  import ReadCounter from '$lib/components/ReadCounter.svelte';
  import SectionOutline from '$lib/components/SectionOutline.svelte';
  import Tabs from '$lib/components/ui/Tabs.svelte';

  marked.use({ mangle: false, headerIds: false });
  function renderMd(text) {
    return DOMPurify.sanitize(marked(text), {
      USE_PROFILES: { html: true },
      FORBID_TAGS: ['style', 'script'],
      FORBID_ATTR: ['onerror', 'onclick'],
      ALLOW_UNKNOWN_PROTOCOLS: false,
    });
  }

  let doc = $state(null);
  let loading = $state(true);
  let error = $state(null); // 'not_found' | 'network' | null
  let rawMarkdown = $state(''); // fallback: extracted_text 없을 때 원본 .md

  let docId = $derived($page.params.id);

  // 손글씨 노트 (자료별 1:1) — "필기" 토글 시 사이드 캔버스 띄움.
  let noteOpen = $state(false);
  let noteStrokes = $state(null); // { version, strokes }
  let noteLoaded = $state(false);
  async function ensureNoteLoaded() {
    if (noteLoaded) return;
    try {
      const r = await api(`/documents/${docId}/note`);
      noteStrokes = r.strokes_json && r.strokes_json.strokes ? r.strokes_json : { version: 1, strokes: [] };
    } catch {
      noteStrokes = { version: 1, strokes: [] };
    }
    noteLoaded = true;
  }
  async function saveNote(strokesJson) {
    try {
      await api(`/documents/${docId}/note`, {
        method: 'PUT',
        body: JSON.stringify({ strokes_json: strokesJson }),
      });
    } catch (err) {
      console.warn('필기 저장 실패', err);
    }
  }
  async function toggleNote() {
    if (!noteOpen) await ensureNoteLoaded();
    noteOpen = !noteOpen;
  }

  // 인접 자료 (같은 library_path 내 이전/다음) — 학습 흐름 네비게이션
  let neighbors = $state({ prev: null, next: null });
  async function loadNeighbors() {
    try {
      neighbors = await api(`/documents/${docId}/library-neighbors`);
    } catch {
      neighbors = { prev: null, next: null };
    }
  }

  // 절(hier section) 목차 — 본문 로드와 독립, 실패(404 포함) 무해.
  // reqId guard: 문서 전환 race 시 stale 결과가 새 문서에 붙지 않게.
  let sections = $state([]);
  let hasSections = $derived(sections.length > 0);
  async function loadSections() {
    const reqId = docId;
    try {
      const r = await api(`/documents/${reqId}/sections`);
      if (reqId === docId) sections = r?.sections ?? [];
    } catch {
      if (reqId === docId) sections = []; // Phase 1 미배포 시 404 → 목차 숨김(graceful)
    }
  }

  // "1회독 완료 + 다음 자료로" 한 번에
  async function readAndGoNext() {
    try {
      await api(`/documents/${docId}/read`, { method: 'POST' });
      addToast('success', '1회독 완료');
    } catch (err) {
      addToast('error', err?.detail || '회독 기록 실패');
      return;
    }
    if (neighbors.next) {
      goto(`/documents/${neighbors.next.id}`);
    }
  }

  onMount(async () => {
    try {
      doc = await api(`/documents/${docId}`);
      const vt = doc.source_channel === 'news' ? 'article' : getViewerType(doc.file_format);
      if ((vt === 'markdown' || vt === 'hwp-markdown') && !doc.extracted_text) {
        try {
          const resp = await fetch(`/api/documents/${docId}/file?token=${getAccessToken()}`);
          if (resp.ok) rawMarkdown = await resp.text();
        } catch (e) {
          rawMarkdown = '';
        }
      }
    } catch (err) {
      error = err?.status === 404 ? 'not_found' : 'network';
    } finally {
      loading = false;
    }
    // 자료실 자료면 인접 자료 미리 fetch (학습 흐름 네비)
    if (doc && doc.category === 'library') loadNeighbors();
    if (doc) loadSections();
  });

  let viewerType = $derived(
    doc ? (doc.source_channel === 'news' ? 'article' : getViewerType(doc.file_format)) : 'none'
  );

  // PDF 분기 전용: marker_worker 가 만든 canonical markdown 이 있으면 기본으로 그것을 보여줌.
  // Phase 1B 산출물의 95% 가 PDF 라 1D pilot 평가가 실사용 화면 기반이 되도록 markdown-first.
  // 사용자가 "PDF 원본" 토글하면 iframe. lastDocId 로 문서 전환만 감지해서 사용자 토글이
  // reactive cycle 에 덮이지 않도록 보호.
  let pdfViewMode = $state('markdown'); // 'markdown' | 'pdf'
  let lastDocId = $state(null);
  let canShowMarkdown = $derived(
    !!(isMdSuccess(doc?.md_status) && doc?.md_content?.trim())
  );

  $effect(() => {
    if (!doc) return;
    if (doc.id !== lastDocId) {
      lastDocId = doc.id;
      pdfViewMode = canShowMarkdown ? 'markdown' : 'pdf';
    }
    // 같은 문서 안에서 markdown 이 사라지면 (success → failed 재처리 등) PDF 로 보호.
    if (!canShowMarkdown && pdfViewMode === 'markdown') {
      pdfViewMode = 'pdf';
    }
  });

  // ── 개요 점프 (경로 B: BE char_start primary + string-match 폴백) ──
  // 이 사이트는 항상 md_content basis(canShowMarkdown && doc.md_content) → trustBE=true.
  // BE char_start 가 있으면 채택, 비면(non-PASS/미백필) resolveAnchorMap 내부에서 buildAnchorMap 로 폴백.
  let anchorMap = $derived(
    hasSections && canShowMarkdown && doc?.md_content
      ? resolveAnchorMap(doc.md_content, sections, { trustBE: true }).anchors
      : {}
  );
  let activeKey = $state(null);
  function jumpToSection(chunkId) {
    const el = document.getElementById(`sec-${chunkId}`);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  }
  // scroll-spy: 화면 상단(120px)을 지난 마지막 .md-anchor = 현재 절. [id] 는 window 스크롤.
  $effect(() => {
    void anchorMap; // 문서/섹션 변화 시 재바인딩
    if (typeof window === 'undefined') return;
    let raf = 0;
    const onScroll = () => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        raf = 0;
        let cur = null;
        document.querySelectorAll('.md-anchor').forEach((a) => {
          if (a.getBoundingClientRect().top <= 120) cur = a;
        });
        if (cur) {
          const m = cur.id.match(/^sec-(\d+)$/);
          if (m) activeKey = Number(m[1]);
        }
      });
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => {
      window.removeEventListener('scroll', onScroll);
      if (raf) cancelAnimationFrame(raf);
    };
  });

  function getViewerType(format) {
    if (['md', 'txt', 'csv', 'html'].includes(format)) return 'markdown';
    if (format === 'pdf') return 'pdf';
    if (['hwp', 'hwpx'].includes(format)) return 'hwp-markdown';
    if (['odoc', 'osheet'].includes(format)) return 'synology';
    if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(format)) return 'image';
    return 'unsupported';
  }

  // E.2 affordance row 핸들러
  function copyLink() {
    const url = `${window.location.origin}/documents/${docId}`;
    navigator.clipboard
      .writeText(url)
      .then(() => addToast('success', '링크 복사됨'))
      .catch(() => addToast('error', '복사 실패'));
  }

  function downloadOriginal() {
    window.open(`/api/documents/${docId}/file?token=${getAccessToken()}&download=true`);
  }

  function downloadPdf() {
    window.open(`/api/documents/${docId}/preview?token=${getAccessToken()}&download=true`);
  }

  function handleDocDelete() {
    addToast('success', '문서가 삭제되어 목록으로 이동합니다.');
    goto('/documents');
  }
</script>

<div class="p-4 lg:p-6">
  <!-- breadcrumb -->
  <div class="flex items-center gap-2 text-sm mb-4 text-dim">
    <a href="/documents" class="hover:text-text">문서</a>
    <span class="text-faint">/</span>
    <span class="truncate max-w-md text-text">{doc?.title || '로딩...'}</span>
  </div>

  {#if loading}
    <div class="max-w-6xl mx-auto">
      <Skeleton h="h-96" rounded="card" />
    </div>
  {:else if error === 'not_found'}
    <EmptyState
      icon={FileText}
      title="문서를 찾을 수 없습니다"
      description="삭제되었거나 접근 권한이 없을 수 있습니다."
    >
      <Button variant="ghost" size="sm" href="/documents">목록으로 돌아가기</Button>
    </EmptyState>
  {:else if error === 'network'}
    <EmptyState
      icon={FileText}
      title="문서를 불러올 수 없습니다"
      description="네트워크 오류가 발생했습니다."
    >
      <Button variant="secondary" size="sm" onclick={() => location.reload()}>다시 시도</Button>
    </EmptyState>
  {:else if doc}
    <div class="mx-auto grid grid-cols-1 gap-6 {hasSections ? 'max-w-7xl xl:grid-cols-[18rem_minmax(0,1fr)_20rem]' : 'max-w-6xl lg:grid-cols-3'}">
      {#if hasSections}
        <!-- 좌측 절 목차 — xl+ sticky rail (그 아래 viewport 는 본문 상단 collapsible) -->
        <aside class="hidden xl:block xl:sticky xl:top-6 xl:self-start xl:max-h-[calc(100vh-3rem)] xl:overflow-y-auto">
          <Card>
            <SectionOutline {sections} onJump={jumpToSection} {activeKey} />
          </Card>
        </aside>
      {/if}

      <!-- 본문 (좌측 목차 없을 때 lg 2/3) -->
      <div class="{hasSections ? '' : 'lg:col-span-2'} space-y-4">
        {#if hasSections}
          <!-- xl 미만: 절 목차 접이식 -->
          <details class="xl:hidden">
            <summary class="cursor-pointer text-sm text-dim px-1 py-2 select-none">절 목차 ({sections.length})</summary>
            <Card class="mt-2"><SectionOutline {sections} onJump={jumpToSection} {activeKey} /></Card>
          </details>
        {/if}
        <!-- Affordance row -->
        <div class="flex flex-wrap items-center gap-2">
          {#if doc.edit_url}
            <Button
              variant="secondary"
              size="sm"
              icon={ExternalLink}
              href={doc.edit_url}
              target="_blank"
            >
              Synology 편집
            </Button>
          {/if}
          <Button variant="secondary" size="sm" icon={Download} onclick={downloadOriginal}>
            원본 다운로드
          </Button>
          {#if doc.preview_status === 'ready'}
            <Button variant="secondary" size="sm" icon={FileText} onclick={downloadPdf}>
              PDF 다운로드
            </Button>
          {/if}
          <Button variant="secondary" size="sm" icon={Link2} onclick={copyLink}>
            링크 복사
          </Button>
          {#if doc.category === 'library'}
            <Button
              variant={noteOpen ? 'primary' : 'secondary'}
              size="sm"
              icon={noteOpen ? X : PenLine}
              onclick={toggleNote}
            >
              {noteOpen ? '필기 닫기' : '필기'}
            </Button>
          {/if}
        </div>

        <!-- 뷰어 — 모바일 가독성: 본문 폰트 키우고 line-height 늘림 -->
        <Card class="min-h-[500px]">
          {#if viewerType === 'markdown' || viewerType === 'hwp-markdown'}
            <MarkdownDoc
              documentId={doc.id}
              mdContent={doc.md_content}
              mdFrontmatter={doc.md_frontmatter}
              mdStatus={doc.md_status}
              mdExtractionError={doc.md_extraction_error}
              mdExtractionQuality={doc.md_extraction_quality}
              anchorMap={anchorMap}
              extractedText={doc.extracted_text || rawMarkdown}
              class="prose prose-invert prose-base lg:prose-sm max-w-none"
            />
          {:else if viewerType === 'pdf'}
            <div class="mb-2 flex items-center gap-2">
              <MarkdownStatusBadge
                mdStatus={doc.md_status}
                mdExtractionError={doc.md_extraction_error}
                mdExtractionQuality={doc.md_extraction_quality}
              />
              {#if canShowMarkdown}
                <Button
                  size="sm"
                  variant={pdfViewMode === 'markdown' ? 'primary' : 'secondary'}
                  onclick={() => (pdfViewMode = 'markdown')}
                >
                  Markdown
                </Button>
                <Button
                  size="sm"
                  variant={pdfViewMode === 'pdf' ? 'primary' : 'secondary'}
                  onclick={() => (pdfViewMode = 'pdf')}
                >
                  PDF 원본
                </Button>
              {/if}
            </div>
            {#if pdfViewMode === 'markdown' && canShowMarkdown}
              <MarkdownDoc
                documentId={doc.id}
                mdContent={doc.md_content}
                mdFrontmatter={doc.md_frontmatter}
                mdStatus={doc.md_status}
                mdExtractionError={doc.md_extraction_error}
                mdExtractionQuality={doc.md_extraction_quality}
                extractedText={doc.extracted_text}
                class="prose prose-invert prose-base lg:prose-sm max-w-none"
              />
            {:else}
              <iframe
                src="/api/documents/{doc.id}/file?token={getAccessToken()}"
                class="w-full h-[80vh] rounded"
                title={doc.title}
              ></iframe>
            {/if}
          {:else if viewerType === 'image'}
            <img
              src="/api/documents/{doc.id}/file?token={getAccessToken()}"
              alt={doc.title}
              class="max-w-full rounded"
            />
          {:else if viewerType === 'synology'}
            <EmptyState
              icon={ExternalLink}
              title="Synology Office 문서"
              description="외부 편집기에서 열어야 합니다."
            >
              <Button
                variant="primary"
                size="sm"
                href={doc.edit_url || 'https://link.hyungi.net'}
                target="_blank"
              >
                새 창에서 열기
              </Button>
            </EmptyState>
          {:else if viewerType === 'article'}
            <div>
              <h1 class="text-xl font-bold text-text mb-3">{doc.title}</h1>
              <div class="flex items-center gap-2 mb-4 text-xs text-dim">
                <span>출처: {doc.source_channel}</span>
                <span class="text-faint">·</span>
                <span>
                  {new Date(doc.created_at).toLocaleDateString('ko-KR', {
                    year: 'numeric',
                    month: 'short',
                    day: 'numeric',
                  })}
                </span>
              </div>
              {#if doc.md_content || doc.extracted_text}
                <!-- article = 텍스트 네이티브(markdown 변환 비대상). md_status='skipped' 라도
                     "Markdown 제외" badge 를 띄우지 않도록 mdStatus 미전달(badge 는 mdStatus 로만 구동). -->
                <MarkdownDoc
                  documentId={doc.id}
                  mdContent={doc.md_content}
                  mdFrontmatter={doc.md_frontmatter}
                  mdStatus={null}
                  mdExtractionError={doc.md_extraction_error}
                  mdExtractionQuality={doc.md_extraction_quality}
                  extractedText={doc.extracted_text}
                  class="mb-6"
                />
              {/if}
              {#if doc.edit_url}
                <Button
                  variant="primary"
                  size="sm"
                  icon={ExternalLink}
                  href={doc.edit_url}
                  target="_blank"
                >
                  원문 보기
                </Button>
              {/if}
            </div>
          {:else}
            <EmptyState
              icon={FileText}
              title="인앱 미리보기 미지원"
              description="포맷: {doc.file_format}"
            />
          {/if}
        </Card>

        <!-- 손글씨 노트 패드 (자료실 자료, "필기" 토글 시) -->
        {#if noteOpen && doc.category === 'library' && noteLoaded}
          <Card class="overflow-hidden p-0">
            <div class="h-[60vh] min-h-[400px] flex flex-col">
              <HandwriteCanvas
                sessionId={doc.id}
                initialStrokes={noteStrokes}
                onChange={(strokes) => saveNote(strokes)}
              />
            </div>
          </Card>
        {/if}
      </div>

      <!-- 오른쪽 — 메타 Tabs [정보 | AI | 관리] (카드 11개 수직 스프롤 해소) -->
      <aside class="min-w-0">
        <Card>
          <Tabs
            tabs={[
              { id: 'info', label: '정보' },
              { id: 'ai', label: 'AI' },
              { id: 'manage', label: '관리' },
            ]}
          >
            {#snippet children(tab)}
              <div class="pt-3 space-y-4">
                {#if tab === 'info'}
                  {#if doc.category === 'library'}
                    <ReadCounter
                      documentId={doc.id}
                      initialCount={doc.read_count ?? 0}
                      initialLastReadAt={doc.last_read_at ?? null}
                    />
                  {/if}
                  <FileInfoView {doc} />
                  <ProcessingStatusView {doc} />
                {:else if tab === 'ai'}
                  <AnalysisPanel docId={doc.id} doc={doc} />
                  <AIClassificationEditor {doc} />
                  <div>
                    <h4 class="text-xs font-semibold text-dim uppercase mb-1.5">관련 문서</h4>
                    <!-- TODO(backend): GET /documents/{id}/related?limit=10 (벡터 유사도) -->
                    <EmptyState
                      icon={FileText}
                      title="추후 지원"
                      description="관련 문서 추천은 backend 연동 후 제공됩니다."
                    />
                  </div>
                {:else}
                  <LibraryPathEditor {doc} />
                  <NoteEditor {doc} />
                  <EditUrlEditor {doc} />
                  <TagsEditor {doc} />
                  <div class="pt-2 border-t border-default">
                    <DocumentDangerZone {doc} ondelete={handleDocDelete} />
                  </div>
                {/if}
              </div>
            {/snippet}
          </Tabs>
        </Card>
      </aside>
    </div>

    <!-- 모바일 sticky 하단 바 — 자료실 자료의 학습 흐름 네비게이션 -->
    {#if doc.category === 'library'}
      <div class="lg:hidden fixed bottom-0 inset-x-0 z-30 bg-surface border-t border-default px-3 py-2 flex items-center gap-2 shadow-lg">
        <button
          type="button"
          onclick={() => neighbors.prev && goto(`/documents/${neighbors.prev.id}`)}
          disabled={!neighbors.prev}
          class="px-2 py-2 rounded text-dim disabled:opacity-30 disabled:cursor-not-allowed"
          aria-label="이전 자료"
        ><ChevronLeft size={20} /></button>

        <button
          type="button"
          onclick={readAndGoNext}
          disabled={!neighbors.next}
          class="flex-1 flex items-center justify-center gap-1.5 px-3 py-2.5 rounded-lg bg-accent text-white text-sm font-medium disabled:opacity-50"
        >
          <Check size={16} />
          {#if neighbors.next}
            1회독 완료 + 다음
          {:else}
            1회독 완료 (마지막 자료)
          {/if}
        </button>

        <button
          type="button"
          onclick={() => neighbors.next && goto(`/documents/${neighbors.next.id}`)}
          disabled={!neighbors.next}
          class="px-2 py-2 rounded text-dim disabled:opacity-30 disabled:cursor-not-allowed"
          aria-label="다음 자료 (회독 카운트 안 함)"
        ><ChevronRight size={20} /></button>
      </div>
      <!-- 본문이 sticky 바 뒤에 가리지 않도록 패딩 -->
      <div class="lg:hidden h-20"></div>
    {/if}
  {/if}
</div>
