// Sidebar + topbar + responsive Shell layout

function SidebarContent({ onPick }) {
  const { state, dispatch, spaceDocCount, getDoc, getSpace } = useApp();
  const view = state.view;
  const profileRef = React.useRef();
  React.useEffect(() => {
    if (!state.userMenuOpen) return;
    const onDoc = (e) => { if (profileRef.current && !profileRef.current.contains(e.target)) dispatch({ type: "CLOSE_USER_MENU" }); };
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, [state.userMenuOpen]);
  // For doc view, derive activeSpace from the doc's parent space so it stays highlighted.
  const docSpaceId = view.type === "doc" ? getDoc(view.docId)?.spaceId : null;
  const activeSpace = view.spaceId || docSpaceId;
  const activeRoute = view.type === "default" ? "default" :
                      view.type === "search"  ? "search"  :
                      view.type === "history" ? "history" : null;

  // ── Build a unified, recency-sorted session list ─────────────
  // Every space session + a synthetic 기본 채팅 entry.
  const recencyOrder = (when) => {
    if (!when) return 9999;
    if (when === "방금" || when === "지금") return 0;
    const m = when.match(/^(\d+)분 전$/); if (m) return 1 + parseInt(m[1], 10);
    if (when === "오늘") return 10;
    const h = when.match(/^(\d+)시간 전$/); if (h) return 60 + parseInt(h[1], 10);
    if (when === "어제") return 1500;
    if (when === "그제") return 2500;
    const d = when.match(/^(\d+)일 전$/); if (d) return 1000 + parseInt(d[1], 10) * 1000;
    if (when === "지난주") return 8000;
    if (when === "지난달") return 30000;
    return 5000;
  };

  const allSessions = [];
  // default chat sessions
  state.defaultSessions.forEach(s => {
    allSessions.push({
      _kind: "default",
      id: s.id,
      title: s.title,
      when: s.when,
      sortKey: recencyOrder(s.when),
      spaceId: null,
      active: s.active,
    });
  });
  state.spaces.forEach(sp => {
    (state.sessions[sp.id] || []).forEach(s => {
      allSessions.push({
        _kind: "space",
        id: s.id,
        title: s.title,
        when: s.when,
        sortKey: recencyOrder(s.when),
        spaceId: sp.id,
        space: sp,
        active: s.active,
        turns: s.turns,
      });
    });
  });
  allSessions.sort((a, b) => a.sortKey - b.sortKey);

  const onSessionClick = (s) => {
    if (s._kind === "default") {
      dispatch({ type: "PICK_DEFAULT_SESSION", sessionId: s.id });
    } else {
      dispatch({ type: "PICK_SESSION", spaceId: s.spaceId, sessionId: s.id });
    }
    onPick?.();
  };

  const isSessionActive = (s) => {
    if (s._kind === "default") {
      if (view.type !== "default") return false;
      const activeId = view.sessionId || state.defaultSessions.find(x => x.active)?.id;
      return activeId === s.id;
    }
    if (view.type !== "chat") return false;
    return view.spaceId === s.spaceId && view.sessionId === s.id;
  };

  const Row = ({ active, lead, label, count, kbd, onClick }) => (
    <button
      onClick={onClick}
      className={cn(
        "w-full flex items-center justify-between gap-2 rounded-md px-2.5 py-1.5 text-[13.5px] transition",
        active ? "bg-[#E6DFCC] text-ink font-medium" : "text-[#5C5347] hover:bg-[#EDE5D2]"
      )}
    >
      <span className="flex items-center gap-2.5 min-w-0 flex-1 text-left">
        <span className="w-5 inline-flex items-center justify-center shrink-0 text-mute text-[15px] leading-none">{lead}</span>
        <span className="truncate">{label}</span>
      </span>
      {kbd && <Kbd>{kbd}</Kbd>}
      {count !== undefined && <span className="text-[11.5px] text-dim tabular-nums">{count}</span>}
    </button>
  );

  return (
    <div className="h-full bg-parch border-r border-rule px-3.5 pt-5 pb-3.5 flex flex-col gap-5">
      <div className="px-1.5 pt-0.5 flex items-center gap-2.5">
        <span
          className="w-8 h-8 rounded-[7px] bg-ink text-cream inline-flex items-center justify-center shrink-0"
          style={{ fontFamily: "ui-serif, Georgia, 'Times New Roman', serif", fontWeight: 600, fontSize: 17, letterSpacing: "-0.02em" }}
          aria-hidden
        >M</span>
        <div className="min-w-0 flex-1">
          <div className="text-[17px] font-semibold text-ink2 tracking-tight2 leading-none">마이위키</div>
          <div className="text-[10.5px] text-mute mt-1 tracking-[0.06em] uppercase">My Wiki</div>
        </div>
        <button
          onClick={() => { dispatch({ type: "GO", view: { type: "search" } }); onPick?.(); }}
          aria-label="검색"
          title="검색 (⌘K)"
          className="w-8 h-8 inline-flex items-center justify-center rounded-md text-mute hover:text-ink hover:bg-[#EDE5D2] transition shrink-0"
        >
          <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="7" cy="7" r="4.5" stroke="currentColor" strokeWidth="1.4"/><path d="m10.5 10.5 2.5 2.5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>
        </button>
      </div>

      <div>
        <div className="px-2 pb-1 text-[11px] font-medium text-mute uppercase tracking-[0.08em]">공간</div>
        <div className="space-y-0.5 max-h-[36vh] overflow-auto scroll-paper -mx-1 px-1">
          {state.spaces.map(s => (
            <Row
              key={s.id}
              active={activeSpace === s.id && (view.type === "chat" || view.type === "explore" || view.type === "empty" || view.type === "doc")}
              lead={<Dot color={s.dot} size={10} />}
              label={s.name}
              count={spaceDocCount(s.id)}
              onClick={() => { dispatch({ type: "GO_SPACE", spaceId: s.id }); onPick?.(); }}
            />
          ))}
          <Row
            lead={"＋"}
            label="새 공간"
            onClick={() => { dispatch({ type: "OPEN_MODAL", modal: { type: "new-space" } }); onPick?.(); }}
          />
        </div>
      </div>

      <div className="flex-1 min-h-0 flex flex-col">
        <button
          onClick={() => {
            if (view.type === "chat" && view.spaceId) {
              dispatch({ type: "NEW_SESSION", spaceId: view.spaceId, title: "새 세션" });
            } else if ((view.type === "explore" || view.type === "doc" || view.type === "empty") && activeSpace) {
              dispatch({ type: "NEW_SESSION", spaceId: activeSpace, title: "새 세션" });
            } else {
              dispatch({ type: "NEW_DEFAULT_SESSION" });
            }
            onPick?.();
          }}
          className="flex items-center justify-center gap-1.5 mx-1 mb-2 px-2.5 py-1.5 rounded-md bg-paper border border-rule text-[12.5px] text-ink2 hover:bg-cream transition"
        >
          <svg width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M6 2v8M2 6h8" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>
          새 채팅
        </button>
        <div className="px-2 pb-1 text-[11px] font-medium text-mute uppercase tracking-[0.08em]">최근 채팅</div>
        <div className="overflow-y-auto scroll-paper -mx-1 px-1 flex-1">
          {allSessions.map(s => {
            const active = isSessionActive(s);
            const color = s._kind === "default" ? "#8B7F6C" : s.space?.dot;
            return (
              <button
                key={(s.spaceId || "_") + ":" + s.id}
                onClick={() => onSessionClick(s)}
                title={s._kind === "default" ? `기본 · ${s.title}` : `${s.space?.name} · ${s.title}`}
                className={cn(
                  "group w-full flex items-center gap-2 rounded-md px-2.5 py-[5px] text-left transition",
                  active ? "bg-[#E6DFCC] text-ink" : "text-[#5C5347] hover:bg-[#EDE5D2]"
                )}
              >
                <Dot color={s._kind === "default" ? "#8B7F6C" : s.space?.dot} size={7} className="shrink-0" />
                <span className={cn("min-w-0 flex-1 truncate text-[13px]", active && "font-medium")}>{s.title}</span>
                {s.active && (s._kind === "space" || s._kind === "default") && active && <Pulse tone="ok" className="shrink-0" />}
                <span className="hidden group-hover:inline-flex items-center shrink-0">
                  <span
                    role="button"
                    aria-label="이름 바꾸기"
                    tabIndex={0}
                    onClick={(e) => {
                      e.stopPropagation();
                      if (s._kind === "default") {
                        dispatch({ type: "OPEN_MODAL", modal: { type: "rename-session", kind: "default", sessionId: s.id, currentTitle: s.title } });
                      } else {
                        dispatch({ type: "OPEN_MODAL", modal: { type: "rename-session", kind: "space", spaceId: s.spaceId, sessionId: s.id, currentTitle: s.title } });
                      }
                    }}
                    className="w-5 h-5 inline-flex items-center justify-center rounded text-mute hover:text-ink hover:bg-paper transition"
                  >
                    <svg width="11" height="11" viewBox="0 0 11 11" fill="none"><path d="M7.5 1.5 9 3 3.5 8.5 1.5 9 2 7Z" stroke="currentColor" strokeWidth="1.1" strokeLinejoin="round"/></svg>
                  </span>
                  <span
                    role="button"
                    aria-label="세션 삭제"
                    tabIndex={0}
                    onClick={(e) => {
                      e.stopPropagation();
                      if (!confirm(`「${s.title}」 세션을 삭제할까요? 메시지 기록이 사라져요.`)) return;
                      if (s._kind === "default") {
                        dispatch({ type: "DELETE_SESSION", kind: "default", sessionId: s.id });
                      } else {
                        dispatch({ type: "DELETE_SESSION", kind: "space", spaceId: s.spaceId, sessionId: s.id });
                      }
                    }}
                    onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.stopPropagation(); e.currentTarget.click(); } }}
                    className="w-5 h-5 inline-flex items-center justify-center rounded text-mute hover:text-[#C5524C] hover:bg-paper transition"
                  >
                    <svg width="11" height="11" viewBox="0 0 11 11" fill="none"><path d="m2.5 2.5 6 6m0-6-6 6" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>
                  </span>
                </span>
              </button>
            );
          })}
        </div>
      </div>

      <div className="pt-3 border-t border-rule relative" ref={profileRef}>
        <button
          onClick={() => dispatch({ type: "TOGGLE_USER_MENU" })}
          className="w-full flex items-center gap-2.5 px-1.5 py-1.5 rounded-md hover:bg-[#EDE5D2] transition"
        >
          <Avatar char={state.user.initial} size={28} />
          <div className="flex-1 min-w-0 text-left">
            <div className="text-[12.5px] text-ink2 font-medium truncate">{state.user.name}</div>
            <div className="text-[10.5px] text-dim truncate">
              {state.user.plan === "free" ? "Free 요금제" : state.user.plan === "pro" ? "Pro 요금제" : "Team 요금제"}
            </div>
          </div>
          <span className="text-mute text-[10px]">▾</span>
        </button>
        {state.userMenuOpen && (
          <div className="absolute bottom-full left-1.5 right-1.5 mb-1.5 bg-paper border border-rule rounded-xl shadow-pop py-1 z-30">
            <button
              onClick={() => { dispatch({ type: "GO", view: { type: "settings", tab: "account" } }); onPick?.(); }}
              className="w-full flex items-center gap-2.5 px-3 py-2 text-left text-[13px] text-ink2 hover:bg-cream"
            >
              <span className="w-3.5 text-center text-mute">⚙</span>
              설정
            </button>
            <button
              onClick={() => { dispatch({ type: "GO", view: { type: "settings", tab: "subscription" } }); onPick?.(); }}
              className="w-full flex items-center gap-2.5 px-3 py-2 text-left text-[13px] text-ink2 hover:bg-cream"
            >
              <span className="w-3.5 text-center text-mute">✦</span>
              요금제 · 사용량
              {state.user.plan === "free" && <span className="ml-auto text-[10px] text-accent bg-warnSoft rounded px-1.5 py-px">업그레이드</span>}
            </button>
            <div className="h-px bg-rule my-1 mx-2" />
            <button
              onClick={() => dispatch({ type: "LOGOUT" })}
              className="w-full flex items-center gap-2.5 px-3 py-2 text-left text-[13px] text-ink2 hover:bg-cream"
            >
              <span className="w-3.5 text-center text-mute">↩</span>
              로그아웃
            </button>
          </div>
        )}
      </div>
    </div>
  );
}

// Topbar — actions and breadcrumb. Slots: left, right.
function Topbar({ left, right, mobileTitle, mobileRight, onBack }) {
  const { dispatch, state } = useApp();
  const bp = useBreakpoint();
  const onSearchView = state.view.type === "search";
  if (bp === "mobile") {
    // Centered title; mobileRight is an icon-version mirror of `right`.
    return (
      <div className="h-12 px-1 flex items-center border-b border-ruleSoft shrink-0 bg-cream gap-1">
        {onBack ? (
          <button
            onClick={onBack}
            aria-label="뒤로"
            className="w-10 h-10 inline-flex items-center justify-center text-ink2 shrink-0"
          >
            <svg width="18" height="18" viewBox="0 0 18 18" fill="none"><path d="M11 4 5 9l6 5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/></svg>
          </button>
        ) : (
          <button
            onClick={() => dispatch({ type: "OPEN_SIDEBAR" })}
            aria-label="메뉴 열기"
            className="w-10 h-10 inline-flex items-center justify-center text-ink2 shrink-0"
          >
            <svg width="18" height="18" viewBox="0 0 18 18" fill="none"><path d="M3 5h12M3 9h12M3 13h12" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></svg>
          </button>
        )}
        <div className="flex-1 min-w-0 text-center text-[14px] font-medium text-ink truncate px-1">{mobileTitle}</div>
        <div className="flex items-center gap-0.5 shrink-0">
          {mobileRight}
        </div>
      </div>
    );
  }
  return (
    <div className="h-12 px-4 sm:px-6 flex items-center justify-between gap-3 border-b border-ruleSoft shrink-0">
      <div className="flex items-center gap-2 min-w-0">{left}</div>
      <div className="flex items-center gap-3 text-[12.5px] text-mute shrink-0">{right}</div>
    </div>
  );
}

// Mobile sidebar drawer
function MobileSidebarDrawer() {
  const { state, dispatch } = useApp();
  if (!state.sidebarOpen) return null;
  return (
    <div className="fixed inset-0 z-40 sm:hidden om-fadeIn">
      <div className="absolute inset-0 bg-ink/35" onClick={() => dispatch({ type: "CLOSE_SIDEBAR" })} />
      <div className="absolute inset-y-0 left-0 w-[280px] max-w-[80%] shadow-pop om-slideR">
        <SidebarContent />
      </div>
    </div>
  );
}

// Shell wrapper: provides sidebar (or drawer), main area
function Shell({ children }) {
  const bp = useBreakpoint();
  return (
    <div className="w-full h-full flex bg-cream text-ink2 font-sans text-[14px] overflow-hidden">
      {bp !== "mobile" && (
        <aside className={cn("shrink-0", bp === "tablet" ? "w-[220px]" : "w-[248px]")}>
          <SidebarContent />
        </aside>
      )}
      <main className="flex-1 min-w-0 flex flex-col">
        {children}
      </main>
      <MobileSidebarDrawer />
    </div>
  );
}

Object.assign(window, { SidebarContent, Topbar, Shell, MobileSidebarDrawer });
