// Search — local + global

function SearchView() {
  const { state, dispatch, getSpace } = useApp();
  const [q, setQ] = React.useState("");
  // scope: "all" (default) | <spaceId>
  const [scope, setScope] = React.useState(() => state.view.spaceId || "all");
  const inputRef = React.useRef();
  React.useEffect(() => { inputRef.current?.focus(); }, []);

  const matches = (text) => q && (text || "").toLowerCase().includes(q.toLowerCase());

  const ranked = state.docs.map(d => {
    const md = docMarkdown(d).toLowerCase();
    let score = 0;
    if (matches(d.title)) score += 5;
    if (q) {
      const needle = q.toLowerCase();
      let idx = -1; while ((idx = md.indexOf(needle, idx + 1)) !== -1) score += 1;
    }
    return { doc: d, score };
  }).filter(x => x.score > 0)
    .filter(x => scope === "all" ? true : x.doc.spaceId === scope)
    .sort((a, b) => b.score - a.score);

  // Per-scope hit counts for the scope chips
  const countsByScope = React.useMemo(() => {
    const allHits = state.docs.map(d => {
      let s = 0;
      if (matches(d.title)) s += 5;
      if (q) {
        const md = docMarkdown(d).toLowerCase(), needle = q.toLowerCase();
        let idx = -1; while ((idx = md.indexOf(needle, idx + 1)) !== -1) s += 1;
      }
      return { d, s };
    }).filter(x => x.s > 0);
    const map = { all: allHits.length };
    state.spaces.forEach(sp => { map[sp.id] = allHits.filter(x => x.d.spaceId === sp.id).length; });
    return map;
  }, [q, state.docs, state.spaces]);

  const excerptFor = (d) => {
    const md = docMarkdown(d);
    if (!q) return md.slice(0, 120);
    const needle = q.toLowerCase(); const idx = md.toLowerCase().indexOf(needle);
    if (idx < 0) return md.slice(0, 120);
    const start = Math.max(0, idx - 30);
    const end = Math.min(md.length, idx + needle.length + 80);
    return (start > 0 ? "…" : "") + md.slice(start, end).replace(/\n+/g, " ") + (end < md.length ? "…" : "");
  };

  const scopeLabel = scope === "all" ? "전체 공간" : (getSpace(scope)?.name || "전체 공간");
  const isCrossSpaceMode = scope === "all";

  return (
    <>
      <Topbar
        mobileTitle="검색"
        onBack={() => dispatch({ type: "GO_BACK" })}
        left={
          <Crumb>
            <button
              onClick={() => dispatch({ type: "GO_BACK" })}
              aria-label="뒤로"
              className="w-7 h-7 -ml-1.5 inline-flex items-center justify-center rounded-md text-mute hover:text-ink hover:bg-cream transition shrink-0"
            >
              <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3 5 8l5 5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/></svg>
            </button>
            <span className="text-ink font-medium">검색</span>
            <span className="text-dim">· {scopeLabel}</span>
            {isCrossSpaceMode && <Pill tone="lock" className="ml-1">결과는 열람 전용</Pill>}
          </Crumb>
        }
      />

      <div className="flex-1 overflow-y-auto scroll-paper">
        <div className="mx-auto w-full max-w-[720px] px-4 sm:px-8 py-7 flex flex-col gap-4">
          <div className="bg-paper border border-rule rounded-xl px-4 py-3 flex items-center gap-3 shadow-paper">
            <span className="text-[18px] text-mute">⌕</span>
            <input
              ref={inputRef}
              value={q}
              onChange={e => setQ(e.target.value)}
              placeholder={scope === "all" ? "모든 공간에서 검색…" : `${scopeLabel}에서 검색…`}
              className="flex-1 bg-transparent text-[15.5px] text-ink placeholder:text-dim outline-none"
            />
          </div>

          {/* Scope chips — 전체 + each space */}
          <div className="flex gap-1.5 flex-wrap items-center">
            <button
              onClick={() => setScope("all")}
              className={cn(
                "px-3 py-1 rounded-full text-[12px] transition flex items-center gap-1.5",
                scope === "all" ? "bg-ink text-cream font-medium" : "bg-paper border border-rule text-[#5C5347] hover:bg-cream"
              )}
            >
              전체
              {q.trim() && <span className={cn("tabular-nums", scope === "all" ? "text-cream/70" : "text-dim")}>{countsByScope.all || 0}</span>}
            </button>
            {state.spaces.map(sp => {
              const active = scope === sp.id;
              const n = countsByScope[sp.id] || 0;
              return (
                <button
                  key={sp.id}
                  onClick={() => setScope(sp.id)}
                  className={cn(
                    "px-3 py-1 rounded-full text-[12px] transition flex items-center gap-1.5",
                    active ? "bg-ink text-cream font-medium" : "bg-paper border border-rule text-[#5C5347] hover:bg-cream",
                    q.trim() && n === 0 && !active && "opacity-50"
                  )}
                >
                  <Dot color={sp.dot} size={6} />
                  {sp.name}
                  {q.trim() && <span className={cn("tabular-nums", active ? "text-cream/70" : "text-dim")}>{n}</span>}
                </button>
              );
            })}
          </div>

          {q.trim() === "" ? (
            <div className="text-[12.5px] text-dim leading-[1.7] px-1">
              <div className="font-medium text-mute uppercase tracking-[0.08em] text-[11.5px] mb-2">팁</div>
              <ul className="list-disc pl-5 space-y-0.5">
                <li>기본은 전체 공간 검색. 위 칩으로 특정 공간만 좁혀서 볼 수 있어요.</li>
                <li>다른 공간의 문서는 <span className="text-ink">열람 전용</span>으로 열려요 — 자동 정리·편집은 잠깁니다.</li>
                <li>세션 텍스트는 검색에 잡히지 않아요. 문서만 색인됩니다.</li>
              </ul>
            </div>
          ) : ranked.length === 0 ? (
            <div className="text-center text-[13px] text-dim py-12">검색 결과가 없어요.</div>
          ) : (
            <div className="text-[11.5px] text-mute uppercase tracking-[0.06em] font-medium px-1">결과 {ranked.length}건</div>
          )}

          <div className="flex flex-col gap-2">
            {ranked.map(({ doc: d }) => {
              const sp = getSpace(d.spaceId);
              const ex = excerptFor(d);
              const hl = (s) => {
                if (!q.trim() || !s) return s;
                const re = new RegExp(`(${q.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")})`, "gi");
                const parts = s.split(re);
                return parts.map((p, i) => p.toLowerCase() === q.toLowerCase()
                  ? <mark key={i} className="bg-warnSoft text-ink rounded-[2px] px-0.5">{p}</mark>
                  : <span key={i}>{p}</span>);
              };
              const isCross = scope === "all";
              return (
                <button
                  key={d.id}
                  onClick={() => dispatch({ type: "GO", view: { type: "doc", docId: d.id, fromCrossSpace: isCross } })}
                  className="text-left bg-paper border border-rule rounded-lg px-4 py-3 hover:bg-cream transition"
                >
                  <div className="flex items-center gap-2 mb-1">
                    <Dot color={sp?.dot} />
                    <span className="text-[12px] text-mute">{sp?.name}</span>
                    {isCross && <Pill tone="lock" className="text-[10.5px]">열람 전용</Pill>}
                    {d.locked && <span className="text-[10.5px] text-dim">잠금</span>}
                    <span className="text-[11px] text-dim ml-auto">{d.updated}</span>
                  </div>
                  <div className="text-[15px] font-medium text-ink tracking-tight1">{hl(d.title)}</div>
                  <div className="text-[13px] text-body mt-1 line-clamp-2 leading-[1.55]">{hl(ex)}</div>
                </button>
              );
            })}
          </div>
        </div>
      </div>
    </>
  );
}

Object.assign(window, { SearchView });
