// Doc view + edit (markdown-based)

// Configure marked once. GFM + line breaks suit chat-style notes.
if (typeof marked !== "undefined") {
  marked.use({ gfm: true, breaks: false, async: false });
}

function MarkdownPreview({ md, className = "" }) {
  const { dispatch } = useApp();
  const html = React.useMemo(() => {
    if (typeof marked === "undefined") return md;
    try { return marked.parse(md || ""); } catch (e) { return md; }
  }, [md]);
  const onClick = (e) => {
    const a = e.target.closest("a");
    if (!a) return;
    const h = a.getAttribute("href") || "";
    if (h.startsWith("#doc:")) {
      e.preventDefault();
      dispatch({ type: "GO", view: { type: "doc", docId: h.slice(5) } });
    }
  };
  return <div onClick={onClick} className={cn("md-prose", className)} dangerouslySetInnerHTML={{ __html: html }} />;
}

function DocView() {
  const { state, dispatch, getDoc, getSpace } = useApp();
  const doc = getDoc(state.view.docId);
  const editing = !!state.view.edit;
  if (!doc) return (
    <>
      <Topbar mobileTitle="문서 없음" left={<Crumb>문서를 찾을 수 없어요.</Crumb>} />
      <div className="flex-1 flex items-center justify-center text-[13px] text-dim">존재하지 않는 문서입니다.</div>
    </>
  );
  const space = getSpace(doc.spaceId);
  const bp = useBreakpoint();
  const md = docMarkdown(doc);
  const reflectionCount = (md.match(/^> ✻ 방금 자동 반영/gm) || []).length;

  // Back-links derived: docs that mention this doc's title (simple)
  const backlinks = state.docs.filter(d => d.id !== doc.id && docMarkdown(d).includes(doc.title.split(" — ")[0].slice(0, 5))).slice(0, 3);

  return (
    <>
      <Topbar
        mobileTitle={doc.title}
        onBack={() => space ? dispatch({ type: "GO", view: { type: "explore", spaceId: space.id } }) : dispatch({ type: "GO", view: { type: "default" } })}
        left={
          <Crumb>
            <button onClick={() => space && dispatch({ type: "GO", view: { type: "explore", spaceId: space.id } })} className="flex items-center gap-2 hover:text-ink transition">
              <Dot color={space?.dot || "#8B7F6C"} />
              <span>{space?.name || "—"}</span>
            </button>
            <span className="text-dim mx-1">›</span>
            <span className="text-ink font-medium truncate max-w-[40vw]">{doc.title}</span>
            {editing && <Pill tone="ok" className="ml-2">편집 중</Pill>}
            {doc.locked && (
              <Pill tone="lock" className="ml-2">
                <span className="w-2 h-2 rounded-[2px] bg-[#7A6F5C]" />잠김
              </Pill>
            )}
          </Crumb>
        }
        mobileRight={
          editing
            ? <button
                onClick={() => dispatch({ type: "GO", view: { type: "doc", docId: doc.id } })}
                aria-label="완료"
                title="완료"
                className="w-10 h-10 inline-flex items-center justify-center text-ink2"
              >
                <svg width="17" height="17" viewBox="0 0 17 17" fill="none"><path d="m3.5 8.5 3.5 3.5 7-7" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>
              </button>
            : <>
                <button
                  onClick={() => dispatch({ type: "TOGGLE_LOCK", docId: doc.id })}
                  aria-label={doc.locked ? "잠금 해제" : "잠금"}
                  title={doc.locked ? "잠금 해제" : "잠금"}
                  className="w-10 h-10 inline-flex items-center justify-center text-ink2"
                >
                  {doc.locked
                    ? <svg width="17" height="17" viewBox="0 0 17 17" fill="none"><rect x="3.5" y="7.5" width="10" height="7" rx="1.2" stroke="currentColor" strokeWidth="1.4"/><path d="M5.5 7.5V5a3 3 0 0 1 6 0v2.5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>
                    : <svg width="17" height="17" viewBox="0 0 17 17" fill="none"><rect x="3.5" y="7.5" width="10" height="7" rx="1.2" stroke="currentColor" strokeWidth="1.4"/><path d="M5.5 7.5V5a3 3 0 0 1 5.5-1.6" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>
                  }
                </button>
                {!doc.locked && (
                  <button
                    onClick={() => dispatch({ type: "GO", view: { type: "doc", docId: doc.id, edit: true } })}
                    aria-label="편집"
                    title="편집"
                    className="w-10 h-10 inline-flex items-center justify-center text-ink2"
                  >
                    <svg width="17" height="17" viewBox="0 0 17 17" fill="none"><path d="M12 2.5 14.5 5 5.5 14 2.5 14.5 3 11.5Z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round"/></svg>
                  </button>
                )}
              </>
        }
        right={
          <>
            <button onClick={() => dispatch({ type: "GO", view: { type: "history", docId: doc.id } })} className="hover:text-ink transition hidden md:inline">이력</button>
            {editing
              ? <Btn size="sm" kind="primary" onClick={() => dispatch({ type: "GO", view: { type: "doc", docId: doc.id } })}>완료</Btn>
              : (
                <div className="flex items-center gap-2">
                  <Btn size="sm" kind="ghost" onClick={() => dispatch({ type: "TOGGLE_LOCK", docId: doc.id })}>{doc.locked ? "잠금 해제" : "잠금"}</Btn>
                  {!doc.locked && <Btn size="sm" kind="primary" onClick={() => dispatch({ type: "GO", view: { type: "doc", docId: doc.id, edit: true } })}>편집</Btn>}
                </div>
              )
            }
          </>
        }
      />

      <div className="flex-1 flex min-h-0">
        <div className="flex-1 min-w-0 overflow-y-auto scroll-paper px-4 sm:px-8 py-7">
          <div className="mx-auto w-full max-w-[720px] flex flex-col">
          {/* Header */}
          <div className="flex items-start justify-between gap-4 mb-4">
            <div className="min-w-0 flex-1">
              <div className="text-[11.5px] text-mute mb-2 flex flex-wrap items-center gap-x-2 gap-y-1">
                <span>{space?.name}</span><span>·</span>
                <span>{doc.updated} 업데이트</span>
                {doc.size && <><span>·</span><span>{doc.size}</span></>}
                {doc.autoReflected && reflectionCount > 0 && (
                  <><span>·</span>
                    <span className="inline-flex items-center gap-1.5 text-[#3E7C5C]">
                      <Pulse tone="ok" /> 자동 반영 {reflectionCount}건
                    </span>
                  </>
                )}
              </div>
              <h1 className="text-[24px] sm:text-[28px] font-semibold text-ink tracking-tight2 leading-[1.25]">{doc.title}</h1>
            </div>
          </div>

          {/* Locked notice */}
          {doc.locked && (
            <div className="flex items-start gap-2.5 px-3.5 py-3 rounded-lg bg-lockBg border border-lockBord mb-5 text-[13px] text-[#5C5347] leading-[1.55]">
              <span className="w-3.5 h-3.5 rounded-[3px] bg-[#7A6F5C] mt-0.5 shrink-0" />
              <span className="flex-1">
                <span className="font-medium text-ink">잠긴 문서</span> — 채팅이나 자동 정리가 이 문서를 수정하지 않아요. 잠금을 풀거나 직접 편집하면 바뀝니다.
              </span>
              <button
                onClick={() => dispatch({ type: "TOGGLE_LOCK", docId: doc.id })}
                className="shrink-0 text-[12px] text-ink font-medium px-2.5 py-1 rounded-md border border-[#7A6F5C]/30 hover:bg-[#7A6F5C]/10"
              >잠금 해제</button>
            </div>
          )}

          {/* Edit-mode auto-reflection notice */}
          {editing && reflectionCount > 0 && (
            <div className="flex items-center gap-2.5 px-3 py-2.5 rounded-lg bg-okSoft border border-okBord mb-5 text-[12.5px] text-[#3E7C5C]">
              <Pulse tone="ok" />
              <span className="flex-1">
                방금 채팅에서 <span className="text-ink font-medium">{reflectionCount}건</span>의 변경이 자동 반영됐어요.
              </span>
              <button onClick={() => {
                // remove appended "방금 자동 반영" quote lines
                const cleaned = md.replace(/\n+> ✻ 방금 자동 반영[^\n]*/g, "");
                dispatch({ type: "EDIT_DOC", docId: doc.id, markdown: cleaned });
              }} className="underline decoration-dotted">되돌리기</button>
              <span className="text-dim">·</span>
              <button onClick={() => dispatch({ type: "GO", view: { type: "history", docId: doc.id } })} className="underline decoration-dotted">이력 보기</button>
            </div>
          )}

          {/* Body */}
          <div className={cn("flex-1", doc.locked ? "opacity-90 select-text" : "")}>
            {editing ? <MarkdownEditor doc={doc} /> : <MarkdownPreview md={md} />}
          </div>

          {/* Back-links */}
          {!editing && backlinks.length > 0 && (
            <div className="mt-10 pt-5 border-t border-ruleSoft">
              <div className="text-[11.5px] text-mute uppercase tracking-[0.08em] font-medium mb-2">이 문서를 참고하는 문서</div>
              <div className="flex flex-col gap-1">
                {backlinks.map(b => (
                  <button
                    key={b.id}
                    onClick={() => dispatch({ type: "GO", view: { type: "doc", docId: b.id } })}
                    className="flex items-center gap-2 text-[13px] text-ink hover:underline text-left"
                  >
                    <Dot color={getSpace(b.spaceId)?.dot} size={6} />
                    {b.title}
                    <span className="text-[11px] text-dim ml-2">{b.updated}</span>
                  </button>
                ))}
              </div>
            </div>
          )}
        </div>
        </div>
        {bp === "desktop" && space && <DocSpaceRail doc={doc} space={space} />}
      </div>
    </>
  );
}

// ─── Doc right rail (desktop) — sibling docs in same space ────────────
function DocSpaceRail({ doc, space }) {
  const { state, dispatch, docsForSpace } = useApp();
  const docs = docsForSpace(space.id);
  // sort: keep natural document order, just highlight the current one
  const sorted = docs;
  return (
    <aside className="w-[260px] shrink-0 border-l border-ruleSoft bg-parch2 px-4 py-5 flex flex-col gap-1 overflow-hidden">
      <div className="flex items-baseline justify-between px-1 pb-1.5">
        <div className="text-[11.5px] text-mute uppercase tracking-[0.06em] font-medium flex items-center gap-1.5">
          <Dot color={space.dot} size={6} />
          {space.name} 공간의 문서
        </div>
        <div className="text-[11.5px] text-dim">{docs.length}</div>
      </div>
      <div className="flex flex-col gap-0.5 overflow-auto scroll-paper -mx-1 px-1 flex-1">
        {sorted.map(d => {
          const isCurrent = d.id === doc.id;
          const isFlash = state.flashDocIds.has(d.id);
          return (
            <button
              key={d.id}
              onClick={() => !isCurrent && dispatch({ type: "GO", view: { type: "doc", docId: d.id } })}
              className={cn(
                "text-left rounded-md px-2.5 py-2 flex flex-col gap-0.5 transition border",
                isCurrent ? "bg-chipBg border-rule" :
                (d.autoReflected || isFlash) ? "bg-paper border-rule hover:bg-paper" :
                "border-transparent hover:bg-paper hover:border-ruleSoft"
              )}
            >
              <div className="flex items-center gap-1.5">
                {!isCurrent && (d.autoReflected || isFlash) && <Pulse tone={d.isNew ? "warn" : "ok"} />}
                {isCurrent && <span className="text-[10px] text-ink font-medium">●</span>}
                <div className={cn("text-[12.5px] truncate flex-1", isCurrent ? "text-ink font-semibold" : "text-ink2", (d.autoReflected || isFlash) && !isCurrent && "font-medium")}>
                  {d.title}
                </div>
                {d.locked && <span className="text-[10px] text-dim">잠금</span>}
              </div>
              <div className={cn("text-[11px] truncate", isCurrent ? "text-mute" : "text-dim")}>
                {isCurrent ? "지금 보고 있음" : d.updated}
              </div>
            </button>
          );
        })}
      </div>
      <div className="pt-2.5 mt-1 border-t border-rule flex flex-col gap-1.5 px-1">
        <button
          onClick={() => dispatch({ type: "OPEN_MODAL", modal: { type: "new-doc", spaceId: space.id } })}
          className="text-[12px] text-mute hover:text-ink text-left"
        >＋ 새 문서</button>
        <button
          onClick={() => dispatch({ type: "GO", view: { type: "explore", spaceId: space.id } })}
          className="text-[12px] text-mute hover:text-ink text-left"
        >공간 대시보드 →</button>
      </div>
    </aside>
  );
}

// ─── Markdown editor (single textarea + sticky toolbar) ──────────────
function MarkdownEditor({ doc }) {
  const { dispatch, state, getSpace } = useApp();
  const [md, setMd] = React.useState(() => docMarkdown(doc));
  const ref = React.useRef();
  const bp = useBreakpoint();
  const [pickerOpen, setPickerOpen] = React.useState(false);
  const [pickerQ, setPickerQ] = React.useState("");

  React.useEffect(() => { setMd(docMarkdown(doc)); /* eslint-disable-next-line */ }, [doc.id]);

  // Auto-resize textarea to its content
  React.useEffect(() => {
    if (!ref.current) return;
    ref.current.style.height = "auto";
    ref.current.style.height = ref.current.scrollHeight + "px";
  }, [md]);

  const commit = (v) => {
    setMd(v);
    dispatch({ type: "EDIT_DOC", docId: doc.id, markdown: v });
  };

  const focusAndRestore = (start, end) => {
    requestAnimationFrame(() => {
      const ta = ref.current; if (!ta) return;
      ta.focus(); ta.setSelectionRange(start, end);
    });
  };

  // Wrap selection with chars; if no selection insert placeholder.
  const wrap = (left, right = left, placeholder = "텍스트") => {
    const ta = ref.current; if (!ta) return;
    const s = ta.selectionStart, e = ta.selectionEnd;
    const sel = md.slice(s, e) || placeholder;
    const next = md.slice(0, s) + left + sel + right + md.slice(e);
    commit(next);
    focusAndRestore(s + left.length, s + left.length + sel.length);
  };

  // Prefix every selected line; toggle off if all lines already prefixed.
  const prefix = (p) => {
    const ta = ref.current; if (!ta) return;
    const s = ta.selectionStart, e = ta.selectionEnd;
    const lineStart = md.lastIndexOf("\n", s - 1) + 1;
    const lineEndIdx = md.indexOf("\n", e);
    const lineEnd = lineEndIdx === -1 ? md.length : lineEndIdx;
    const region = md.slice(lineStart, lineEnd);
    const lines = region.split("\n");
    const allHave = lines.length > 0 && lines.every(l => l.startsWith(p));
    const newLines = lines.map(l => allHave ? l.slice(p.length) : (p + l));
    const next = md.slice(0, lineStart) + newLines.join("\n") + md.slice(lineEnd);
    commit(next);
    focusAndRestore(lineStart, lineStart + newLines.join("\n").length);
  };

  // Toggle heading level on the current line(s): cycle # → ## → ### → none
  const toggleHeading = () => {
    const ta = ref.current; if (!ta) return;
    const s = ta.selectionStart;
    const lineStart = md.lastIndexOf("\n", s - 1) + 1;
    const lineEndIdx = md.indexOf("\n", lineStart);
    const lineEnd = lineEndIdx === -1 ? md.length : lineEndIdx;
    let line = md.slice(lineStart, lineEnd);
    let nextLine;
    if (line.startsWith("### ")) nextLine = line.slice(4);
    else if (line.startsWith("## ")) nextLine = "### " + line.slice(3);
    else if (line.startsWith("# ")) nextLine = "## " + line.slice(2);
    else nextLine = "## " + line;
    const next = md.slice(0, lineStart) + nextLine + md.slice(lineEnd);
    commit(next);
    focusAndRestore(lineStart + nextLine.length, lineStart + nextLine.length);
  };

  const insertLink = () => {
    const ta = ref.current; if (!ta) return;
    const s = ta.selectionStart, e = ta.selectionEnd;
    const sel = md.slice(s, e) || "링크 텍스트";
    const inserted = `[${sel}](https://)`;
    const next = md.slice(0, s) + inserted + md.slice(e);
    commit(next);
    // place caret inside (https://)
    const urlStart = s + sel.length + 3;
    focusAndRestore(urlStart, urlStart + 8);
  };

  const insertDocLink = (linked) => {
    const ta = ref.current; if (!ta) return;
    const s = ta.selectionStart, e = ta.selectionEnd;
    const sel = md.slice(s, e) || linked.title;
    const inserted = `[${sel}](#doc:${linked.id})`;
    const next = md.slice(0, s) + inserted + md.slice(e);
    commit(next);
    focusAndRestore(s + inserted.length, s + inserted.length);
    setPickerOpen(false);
    setPickerQ("");
  };

  // Smart shortcuts: Tab for indent. (Smart-Enter list continuation was
  // removed — it raced with React's onChange and could swallow/duplicate
  // the last character. The toolbar buttons + manual `- ` work safely.)
  const onKeyDown = (e) => {
    if (e.key === "Tab") {
      e.preventDefault();
      const ta = ref.current; if (!ta) return;
      const s = ta.selectionStart;
      const v = ta.value;
      const insert = "  ";
      const next = v.slice(0, s) + insert + v.slice(s);
      commit(next);
      focusAndRestore(s + insert.length, s + insert.length);
    }
  };

  // Toolbar definition (mobile-friendly, ~44px hit targets)
  const TOOLBAR = [
    { id: "h",    label: "H",  title: "제목 (## )",     fn: toggleHeading },
    { id: "b",    label: "B",  title: "굵게 (**)",      fn: () => wrap("**", "**", "굵게") },
    { id: "i",    label: "I",  title: "기울임 (*)",     fn: () => wrap("*", "*", "기울임") },
    { id: "ul",   label: "•",  title: "글머리표 (- )",  fn: () => prefix("- ") },
    { id: "ol",   label: "1.", title: "번호 매기기 (1. )", fn: () => prefix("1. ") },
    { id: "task", label: "☐",  title: "할 일 (- [ ] )", fn: () => prefix("- [ ] ") },
    { id: "q",    label: "❝",  title: "인용 (> )",      fn: () => prefix("> ") },
    { id: "code", label: "</>",title: "인라인 코드 (`)",fn: () => wrap("`", "`", "code") },
    { id: "link", label: "🔗", title: "외부 링크",      fn: insertLink },
    { id: "doc",  label: "[[", title: "다른 문서 연결",  fn: () => setPickerOpen(true) },
  ];

  return (
    <div className="flex flex-col -mx-1 sm:mx-0">
      <div className="sticky top-0 z-10 mb-2 px-1 sm:px-0 pt-1 pb-2 bg-cream/95 backdrop-blur-sm border-b border-ruleSoft flex items-center gap-0.5 flex-wrap">
        {TOOLBAR.map(t => (
          <button
            key={t.id}
            onMouseDown={(e) => { e.preventDefault(); t.fn(); }}
            title={t.title}
            aria-label={t.title}
            className="w-10 h-10 inline-flex items-center justify-center rounded-md border border-transparent hover:bg-paper hover:border-rule text-[14px] font-medium text-ink2 active:bg-chipBg select-none"
          >{t.label}</button>
        ))}
      </div>

      <textarea
        ref={ref}
        value={md}
        onChange={(e) => commit(e.target.value)}
        onKeyDown={onKeyDown}
        placeholder={"# 제목\n\n본문을 적어보세요.\n\n- 글머리표\n- [ ] 할 일\n> 인용\n**굵게** *기울임* `코드`"}
        spellCheck={false}
        className="w-full bg-transparent text-[15px] leading-[1.72] text-body outline-none min-h-[200px] resize-none placeholder:text-dim font-mono"
        style={{ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace, Pretendard" }}
      />

      {/* Preview (hidden on small screens to keep focus on the textarea) */}
      <div className="mt-6 pt-4 border-t border-dashed border-rule hidden md:block">
        <div className="text-[11.5px] text-mute uppercase tracking-[0.08em] font-medium mb-2">미리보기</div>
        <MarkdownPreview md={md} className="opacity-90" />
      </div>

      {pickerOpen && <DocLinkPicker
        currentDocId={doc.id}
        q={pickerQ} setQ={setPickerQ}
        docs={state.docs}
        getSpace={getSpace}
        onPick={insertDocLink}
        onClose={() => { setPickerOpen(false); setPickerQ(""); }}
      />}
    </div>
  );
}

// Searchable doc picker — used by the editor's "[[" toolbar button.
function DocLinkPicker({ currentDocId, q, setQ, docs, getSpace, onPick, onClose }) {
  const inputRef = React.useRef();
  React.useEffect(() => { inputRef.current?.focus(); }, []);
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose?.(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  const filtered = docs.filter(d => d.id !== currentDocId && d.title.toLowerCase().includes((q || "").toLowerCase())).slice(0, 30);
  // group by space for visual grouping
  const grouped = {};
  filtered.forEach(d => { (grouped[d.spaceId] = grouped[d.spaceId] || []).push(d); });

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center p-3 sm:p-6 om-fadeIn" onClick={onClose}>
      <div className="absolute inset-0 bg-ink/30 backdrop-blur-[2px]" />
      <div
        onClick={(e) => e.stopPropagation()}
        className="relative bg-paper border border-rule rounded-2xl shadow-pop w-full max-w-[480px] max-h-[70vh] flex flex-col om-slideUp"
      >
        <div className="p-4 border-b border-ruleSoft">
          <div className="text-[11.5px] text-mute uppercase tracking-[0.08em] font-medium mb-2">다른 문서 연결</div>
          <input
            ref={inputRef}
            value={q || ""}
            onChange={(e) => setQ(e.target.value)}
            placeholder="문서 제목으로 찾기…"
            className="w-full bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink outline-none focus:border-ink2 placeholder:text-dim"
            onKeyDown={(e) => {
              if (e.key === "Enter" && !e.nativeEvent.isComposing && filtered[0]) { e.preventDefault(); onPick(filtered[0]); }
            }}
          />
          <div className="text-[11px] text-dim mt-2 leading-[1.5]">
            선택하면 본문에 <span className="text-ink">[제목](#doc:id)</span> 형태로 들어가요. 클릭하면 그 문서로 이동합니다.
          </div>
        </div>
        <div className="overflow-y-auto scroll-paper flex-1">
          {Object.keys(grouped).length === 0 && (
            <div className="text-center text-[13px] text-dim py-10">맞는 문서가 없어요.</div>
          )}
          {Object.entries(grouped).map(([spaceId, ds]) => {
            const sp = getSpace(spaceId);
            return (
              <div key={spaceId}>
                <div className="px-4 pt-3 pb-1 text-[10.5px] text-mute uppercase tracking-[0.08em] font-medium flex items-center gap-1.5">
                  <Dot color={sp?.dot} size={6} />
                  {sp?.name || spaceId}
                </div>
                {ds.map(d => (
                  <button
                    key={d.id}
                    onClick={() => onPick(d)}
                    className="w-full px-4 py-2 hover:bg-cream text-left flex items-center gap-2 group"
                  >
                    <span className="text-[14px] text-ink truncate flex-1">{d.title}</span>
                    {d.locked && <span className="text-[10.5px] text-dim">잠금</span>}
                    <span className="text-[11px] text-dim ml-auto">{d.updated}</span>
                    <span className="text-[11px] text-mute opacity-0 group-hover:opacity-100">↵</span>
                  </button>
                ))}
              </div>
            );
          })}
        </div>
        <div className="px-4 py-2.5 border-t border-ruleSoft flex items-center justify-between text-[11.5px] text-dim">
          <span>{filtered.length}개 결과</span>
          <button onClick={onClose} className="hover:text-ink">취소</button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { DocView, MarkdownEditor, MarkdownPreview });
