// Settings — tabbed view: 계정 / 구독 / 환경 / 데이터

function SettingsView() {
  const { state, dispatch } = useApp();
  const tab = state.view.tab || "account";
  const setTab = (t) => dispatch({ type: "GO", view: { type: "settings", tab: t } });

  const tabs = [
    { id: "account",      label: "계정",     icon: "👤" },
    { id: "subscription", label: "구독",     icon: "✦" },
    { id: "preferences",  label: "환경",     icon: "⚙" },
    { id: "data",         label: "데이터",   icon: "⤓" },
  ];

  return (
    <>
      <Topbar
        mobileTitle="설정"
        onBack={() => dispatch({ type: "GO_BACK" })}
        left={
          <Crumb>
            <button onClick={() => dispatch({ type: "GO_BACK" })} className="hover:text-ink transition flex items-center gap-1">
              <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M9 3 4 7l5 4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/></svg>
              뒤로
            </button>
            <span className="text-dim mx-1">·</span>
            <span className="text-ink font-medium">설정</span>
          </Crumb>
        }
      />

      <div className="flex-1 flex min-h-0 flex-col md:flex-row">
        {/* Tabs — sidebar on desktop, horizontal scroll on mobile */}
        <nav className="md:w-[200px] shrink-0 border-b md:border-b-0 md:border-r border-ruleSoft md:bg-parch2 px-3 md:px-4 py-3 md:py-5">
          <div className="flex md:flex-col gap-1 overflow-x-auto scroll-paper">
            {tabs.map(t => (
              <button
                key={t.id}
                onClick={() => setTab(t.id)}
                className={cn(
                  "px-3 py-2 rounded-md text-left text-[13.5px] transition flex items-center gap-2.5 shrink-0",
                  tab === t.id ? "bg-paper text-ink font-medium border border-rule md:border-rule" : "text-[#5C5347] hover:bg-cream md:hover:bg-paper"
                )}
              >
                <span className="text-[14px] text-mute w-4 text-center">{t.icon}</span>
                {t.label}
              </button>
            ))}
          </div>
        </nav>

        <div className="flex-1 overflow-y-auto scroll-paper px-4 sm:px-8 py-7">
          <div className="mx-auto w-full max-w-[640px]">
            {tab === "account"      && <AccountTab />}
            {tab === "subscription" && <SubscriptionTab />}
            {tab === "preferences"  && <PreferencesTab />}
            {tab === "data"         && <DataTab />}
          </div>
        </div>
      </div>
    </>
  );
}

function SettingsSection({ title, hint, children }) {
  return (
    <section className="mb-9">
      <div className="mb-3">
        <div className="text-[15px] font-semibold text-ink tracking-tight1">{title}</div>
        {hint && <div className="text-[12.5px] text-mute mt-1 leading-[1.55]">{hint}</div>}
      </div>
      <div className="bg-paper border border-rule rounded-xl divide-y divide-ruleSoft">
        {children}
      </div>
    </section>
  );
}

function SettingsRow({ label, hint, control, danger }) {
  return (
    <div className="flex items-start justify-between gap-4 px-4 py-3.5">
      <div className="min-w-0 flex-1">
        <div className={cn("text-[13.5px]", danger ? "text-[#C5524C]" : "text-ink2")}>{label}</div>
        {hint && <div className="text-[11.5px] text-dim mt-0.5 leading-[1.5]">{hint}</div>}
      </div>
      <div className="shrink-0">{control}</div>
    </div>
  );
}

// ─── 계정 ────────────────────────────────────────────────────
function AccountTab() {
  const { state, dispatch } = useApp();
  const [name, setName] = React.useState(state.user.name);
  const [email, setEmail] = React.useState(state.user.email);
  const save = () => dispatch({ type: "UPDATE_USER", patch: { name: name.trim() || state.user.name, email: email.trim() || state.user.email, initial: (name.trim() || state.user.name).charAt(0) } });

  return (
    <>
      <SettingsSection title="프로필">
        <div className="flex items-center gap-4 px-4 py-4">
          <Avatar char={state.user.initial} size={56} />
          <div className="flex flex-col gap-0.5">
            <div className="text-[15px] text-ink font-medium">{state.user.name}</div>
            <div className="text-[12.5px] text-dim">{state.user.email}</div>
          </div>
          <button onClick={() => dispatch({ type: "OPEN_MODAL", modal: { type: "avatar" } })} className="ml-auto text-[12px] text-mute hover:text-ink underline decoration-dotted">아바타 변경</button>
        </div>
        <div className="px-4 py-3.5 flex flex-col gap-3">
          <label className="flex flex-col gap-1.5">
            <span className="text-[12px] text-mute">이름</span>
            <input value={name} onChange={e => setName(e.target.value)} className="bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink outline-none focus:border-ink2" />
          </label>
          <label className="flex flex-col gap-1.5">
            <span className="text-[12px] text-mute">이메일</span>
            <input value={email} onChange={e => setEmail(e.target.value)} className="bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink outline-none focus:border-ink2" />
          </label>
          <div className="flex justify-end mt-1">
            <Btn kind="primary" size="md" onClick={save}>저장</Btn>
          </div>
        </div>
      </SettingsSection>

      <SettingsSection title="보안">
        <SettingsRow label="비밀번호 변경" hint="최근 변경: 90일 이상 전"
          control={<Btn kind="ghost" size="sm" onClick={() => dispatch({ type: "OPEN_MODAL", modal: { type: "change-password" } })}>변경</Btn>} />
        <SettingsRow label="2단계 인증" hint="OTP 앱 또는 SMS로 추가 확인"
          control={<Btn kind="ghost" size="sm" onClick={() => dispatch({ type: "OPEN_MODAL", modal: { type: "twofa" } })}>설정</Btn>} />
      </SettingsSection>

      <SettingsSection title="계정 작업" hint="이 작업은 되돌릴 수 없어요.">
        <SettingsRow
          label="로그아웃"
          control={<Btn kind="ghost" size="sm" onClick={() => dispatch({ type: "LOGOUT" })}>로그아웃</Btn>}
        />
        <SettingsRow
          danger
          label="계정 삭제"
          hint="모든 공간·문서·세션이 삭제되며 복구되지 않습니다."
          control={<Btn kind="ghost" size="sm" className="!text-[#C5524C] !border-[#E8C6C2]" onClick={() => dispatch({ type: "OPEN_MODAL", modal: { type: "delete-account" } })}>삭제 요청</Btn>}
        />
      </SettingsSection>
    </>
  );
}

// ─── 구독 ────────────────────────────────────────────────────
function SubscriptionTab() {
  const { state, dispatch } = useApp();
  const plan = state.user.plan;

  const PLANS = [
    { id: "free", name: "Free",   price: "₩0",        period: "/월",  desc: "개인 노트 정리용", features: ["공간 5개", "Haiku 4.5 무제한", "Sonnet/Opus 월 50회", "마크다운 내보내기"] },
    { id: "pro",  name: "Pro",    price: "₩12,000",   period: "/월",  desc: "본격적인 글·기록 작업", features: ["공간 무제한", "Haiku 4.5 무제한", "Sonnet 무제한 · Opus 월 500회", "협업 공유 (곧)", "백업 보관 12개월"], highlight: true },
    { id: "team", name: "Team",   price: "₩24,000",   period: "/인·월", desc: "팀 단위 위키",     features: ["공간·문서 공유", "역할별 권한", "감사 로그", "고급 모델 우선 접근"] },
  ];

  return (
    <>
      <SettingsSection title="현재 요금제" hint={plan === "free" ? "필요한 만큼 천천히 쓰면서, 늘어나면 Pro로." : "유료 사용 감사합니다."}>
        <div className="px-4 py-4 flex items-center justify-between gap-4">
          <div>
            <div className="flex items-center gap-2">
              <span className="text-[16px] font-semibold text-ink">{(PLANS.find(p => p.id === plan) || PLANS[0]).name}</span>
              {plan === "pro" && <span className="text-[10.5px] text-accent bg-warnSoft rounded px-1.5 py-px">활성</span>}
            </div>
            <div className="text-[12.5px] text-mute mt-0.5">{(PLANS.find(p => p.id === plan) || PLANS[0]).desc}</div>
          </div>
          {plan !== "free" && <Btn kind="ghost" size="sm" onClick={() => dispatch({ type: "SET_PLAN", plan: "free" })}>구독 취소</Btn>}
        </div>
      </SettingsSection>

      <SettingsSection title="이번 달 사용량">
        <SettingsRow label="Haiku 4.5"  hint="빠른 응답 / 무제한"           control={<UsageBar used={1284} total={Infinity} />} />
        <SettingsRow label="Sonnet 4.5" hint={plan === "free" ? "월 50회 한도" : "무제한"} control={<UsageBar used={37} total={plan === "free" ? 50 : Infinity} />} />
        <SettingsRow label="Opus 4.1"   hint={plan === "free" ? "월 0회 한도 — Pro 필요" : (plan === "pro" ? "월 500회 한도" : "무제한")}
          control={<UsageBar used={plan === "free" ? 0 : 18} total={plan === "free" ? 0 : (plan === "pro" ? 500 : Infinity)} />}
        />
      </SettingsSection>

      <SettingsSection title="요금제 선택">
        <div className="px-3 py-3 grid grid-cols-1 sm:grid-cols-3 gap-2.5">
          {PLANS.map(p => {
            const current = p.id === plan;
            return (
              <div key={p.id} className={cn(
                "rounded-lg p-3.5 flex flex-col gap-2 border transition",
                current ? "bg-chipBg border-rule" : "border-ruleSoft hover:border-rule",
                p.highlight && !current && "ring-1 ring-accent/30"
              )}>
                <div className="flex items-baseline justify-between">
                  <span className="text-[14.5px] font-semibold text-ink">{p.name}</span>
                  {p.highlight && !current && <span className="text-[9.5px] text-accent uppercase tracking-wider font-medium">추천</span>}
                </div>
                <div className="text-ink"><span className="text-[20px] font-semibold tracking-tight2">{p.price}</span><span className="text-[12px] text-mute ml-0.5">{p.period}</span></div>
                <div className="text-[11.5px] text-mute -mt-1">{p.desc}</div>
                <ul className="text-[12px] text-body leading-[1.55] space-y-0.5 mt-1 mb-1">
                  {p.features.map(f => <li key={f} className="flex gap-1.5"><span className="text-[#3E9E72]">✓</span>{f}</li>)}
                </ul>
                <Btn
                  kind={current ? "soft" : "primary"} size="sm"
                  disabled={current}
                  onClick={() => {
                    if (p.id === "free") dispatch({ type: "SET_PLAN", plan: "free" });
                    else dispatch({ type: "OPEN_MODAL", modal: { type: "checkout", planId: p.id } });
                  }}
                >{current ? "사용 중" : (p.id === "free" ? "다운그레이드" : "선택")}</Btn>
              </div>
            );
          })}
        </div>
      </SettingsSection>

      {plan !== "free" && (
        <SettingsSection title="결제">
          <SettingsRow label="결제 수단" hint="•••• 1234 · 만료 12/27"
            control={<Btn kind="ghost" size="sm" onClick={() => dispatch({ type: "OPEN_MODAL", modal: { type: "payment-method" } })}>변경</Btn>} />
          <SettingsRow label="청구 내역" hint="PDF 영수증 다운로드"
            control={<Btn kind="ghost" size="sm" onClick={() => dispatch({ type: "OPEN_MODAL", modal: { type: "billing-history" } })}>보기</Btn>} />
          <SettingsRow label="다음 결제일" hint="2026년 6월 27일 · ₩12,000" control={<span className="text-[12px] text-mute">자동 갱신</span>} />
        </SettingsSection>
      )}
    </>
  );
}

function UsageBar({ used, total }) {
  const unlimited = total === Infinity;
  const pct = unlimited ? null : (total === 0 ? 0 : Math.min(100, Math.round(used / total * 100)));
  return (
    <div className="text-right min-w-[120px]">
      <div className="text-[12px] text-ink tabular-nums">
        {unlimited ? <>{used.toLocaleString()}<span className="text-dim"> · 무제한</span></> :
         total === 0 ? <span className="text-dim">사용 불가</span> :
         <>{used} <span className="text-dim">/ {total}</span></>}
      </div>
      {pct !== null && total > 0 && (
        <div className="h-1.5 w-[120px] mt-1 ml-auto rounded-full bg-ruleSoft overflow-hidden">
          <div className={cn("h-full rounded-full", pct >= 90 ? "bg-[#C5524C]" : pct >= 60 ? "bg-accent" : "bg-ok")} style={{ width: pct + "%" }} />
        </div>
      )}
    </div>
  );
}

// ─── 환경 ────────────────────────────────────────────────────
function PreferencesTab() {
  const [defaultModel, setDefaultModel] = React.useState(() => {
    try { return localStorage.getItem("mywiki:default-model") || "haiku"; } catch { return "haiku"; }
  });
  const [theme, setTheme] = React.useState(() => {
    try { return localStorage.getItem("mywiki:theme") || "paper"; } catch { return "paper"; }
  });
  const [autoOrganize, setAutoOrganize] = React.useState(true);
  const [notifyAuto, setNotifyAuto] = React.useState(true);
  const [notifyLock, setNotifyLock] = React.useState(true);

  const saveTheme = (v) => { setTheme(v); try { localStorage.setItem("mywiki:theme", v); } catch {} };
  const saveModel = (v) => { setDefaultModel(v); try { localStorage.setItem("mywiki:default-model", v); } catch {} };

  return (
    <>
      <SettingsSection title="모양">
        <SettingsRow
          label="테마"
          hint="다크 모드는 곧 지원됩니다."
          control={
            <div className="flex gap-1.5">
              {[
                { id: "paper", label: "종이" },
                { id: "dark",  label: "어둠", disabled: true },
                { id: "system",label: "시스템 따라", disabled: true },
              ].map(t => (
                <button key={t.id}
                  disabled={t.disabled}
                  onClick={() => saveTheme(t.id)}
                  className={cn(
                    "px-2.5 py-1 rounded-md text-[12px] border transition",
                    theme === t.id ? "bg-chipBg border-rule text-ink font-medium" : "border-rule text-mute hover:text-ink",
                    t.disabled && "opacity-50 cursor-not-allowed"
                  )}
                >{t.label}</button>
              ))}
            </div>
          }
        />
        <SettingsRow
          label="언어"
          control={<span className="text-[12px] text-mute">한국어</span>}
        />
      </SettingsSection>

      <SettingsSection title="대화 / 편집">
        <SettingsRow
          label="기본 대화 모델"
          hint="새 세션을 시작할 때 기본으로 쓰는 모델"
          control={
            <select value={defaultModel} onChange={e => saveModel(e.target.value)} className="bg-cream border border-rule rounded-md px-2 py-1 text-[12.5px] text-ink outline-none">
              <option value="haiku">Haiku 4.5</option>
              <option value="sonnet">Sonnet 4.5</option>
              <option value="opus">Opus 4.1</option>
            </select>
          }
        />
        <SettingsRow
          label="새 세션 — 자동 정리 기본값"
          hint="공간 세션을 새로 시작할 때 자동 정리를 켜둘지"
          control={<Toggle on={autoOrganize} onChange={() => setAutoOrganize(v => !v)} />}
        />
      </SettingsSection>

      <SettingsSection title="알림">
        <SettingsRow
          label="자동 정리가 일어났을 때"
          hint="새 문서 생성 / 큰 변경이 있을 때"
          control={<Toggle on={notifyAuto} onChange={() => setNotifyAuto(v => !v)} />}
        />
        <SettingsRow
          label="잠금 문서 변경 시도"
          hint="잠긴 문서를 누군가 또는 자동 정리가 건드리려 했을 때"
          control={<Toggle on={notifyLock} onChange={() => setNotifyLock(v => !v)} />}
        />
      </SettingsSection>

      <SettingsSection title="단축키">
        <Shortcut keys={["⌘", "K"]} label="검색 열기" />
        <Shortcut keys={["Esc"]}     label="모달·드로어·검색 닫기" />
        <Shortcut keys={["Enter"]}   label="채팅 보내기 (Shift+Enter 줄바꿈)" />
      </SettingsSection>
    </>
  );
}

function Toggle({ on, onChange }) {
  return (
    <button
      onClick={onChange}
      aria-pressed={on}
      className={cn(
        "relative inline-block w-9 h-5 rounded-full transition",
        on ? "bg-ok" : "bg-[#D5CAB1]"
      )}
    >
      <span className={cn("absolute top-0.5 w-4 h-4 bg-paper rounded-full shadow-paper transition", on ? "left-[18px]" : "left-0.5")} />
    </button>
  );
}

function Shortcut({ keys, label }) {
  return (
    <div className="flex items-center justify-between gap-4 px-4 py-2.5">
      <span className="text-[13px] text-ink2">{label}</span>
      <span className="flex gap-1">
        {keys.map((k, i) => <span key={i} className="kbd !min-w-[24px] !h-[22px] !text-[11px]">{k}</span>)}
      </span>
    </div>
  );
}

// ─── 데이터 ──────────────────────────────────────────────────
function DataTab() {
  const { state, dispatch } = useApp();
  return (
    <>
      <SettingsSection title="내보내기" hint="문서는 마크다운(.md), 채팅 세션은 JSON으로 받을 수 있어요.">
        <SettingsRow
          label="전체 문서 .md 묶음 다운로드"
          hint={`${state.docs.length}개 문서 · 공간 ${state.spaces.length}개`}
          control={<Btn kind="ghost" size="sm" onClick={() => dispatch({ type: "OPEN_MODAL", modal: { type: "export", kind: "docs" } })}>내보내기</Btn>}
        />
        <SettingsRow
          label="모든 세션 — JSON"
          hint="기본 채팅 + 공간 세션 메시지 전체"
          control={<Btn kind="ghost" size="sm" onClick={() => dispatch({ type: "OPEN_MODAL", modal: { type: "export", kind: "sessions" } })}>내보내기</Btn>}
        />
        <SettingsRow
          label="자동 정리 이력 — CSV"
          hint={`이력 ${state.history.length}건`}
          control={<Btn kind="ghost" size="sm" onClick={() => dispatch({ type: "OPEN_MODAL", modal: { type: "export", kind: "history" } })}>내보내기</Btn>}
        />
      </SettingsSection>

      <SettingsSection title="가져오기" hint="다른 도구에서 옮겨오시는 분은 이쪽으로.">
        <SettingsRow label="마크다운 파일 / 폴더" hint="공간 단위로 묶어 가져옵니다"
          control={<Btn kind="ghost" size="sm" onClick={() => dispatch({ type: "OPEN_MODAL", modal: { type: "import" } })}>파일 선택</Btn>} />
        <SettingsRow label="Notion / Obsidian" hint="곧 지원" control={<Btn kind="ghost" size="sm" disabled>준비 중</Btn>} />
      </SettingsSection>

      <SettingsSection title="저장 공간">
        <SettingsRow
          label="사용량"
          hint="이미지·첨부 포함"
          control={<div className="text-right">
            <div className="text-[13px] text-ink tabular-nums">2.4 MB <span className="text-dim">/ 100 MB</span></div>
            <div className="h-1.5 w-[120px] mt-1 ml-auto rounded-full bg-ruleSoft overflow-hidden">
              <div className="h-full rounded-full bg-ok" style={{ width: "2.4%" }} />
            </div>
          </div>}
        />
      </SettingsSection>
    </>
  );
}

// ─── Modals: account ─────────────────────────────────────────
function AvatarModal({ onClose }) {
  const { state, dispatch } = useApp();
  const [picked, setPicked] = React.useState(state.user.initial);
  const presets = ["준", "수", "J", "M", "🐈", "🌿", "📚", "✦", "♥", "☼", "△", "○"];
  const colors = ["#D5CAB1", "#B6CDE3", "#C6DEC9", "#E3C0B6", "#D2C6E0", "#E0D6B6"];
  const [color, setColor] = React.useState(colors[0]);
  const save = () => {
    dispatch({ type: "UPDATE_USER", patch: { initial: picked } });
    onClose?.();
  };
  return (
    <div className="p-6 flex flex-col gap-5">
      <div>
        <div className="text-[11.5px] text-mute uppercase tracking-[0.08em] font-medium mb-1">아바타</div>
        <div className="text-[20px] font-semibold text-ink tracking-tight2">새 아바타 고르기</div>
        <div className="text-[13px] text-mute mt-1.5 leading-[1.6]">
          한 글자나 이모지로 시작하세요. 이미지 업로드는 곧 지원됩니다.
        </div>
      </div>
      <div className="flex justify-center">
        <div className="rounded-full inline-flex items-center justify-center" style={{ width: 80, height: 80, background: color, fontSize: 36, fontWeight: 600, color: "#5C5347" }}>{picked}</div>
      </div>
      <div className="flex flex-col gap-2">
        <div className="text-[12px] text-mute">글자 / 기호</div>
        <div className="flex gap-2 flex-wrap">
          {presets.map(p => (
            <button key={p} onClick={() => setPicked(p)}
              className={cn("w-10 h-10 rounded-full text-[15px] font-medium border-2 transition", picked === p ? "border-ink" : "border-transparent hover:border-rule")}
              style={{ background: color }}>{p}</button>
          ))}
        </div>
      </div>
      <div className="flex flex-col gap-2">
        <div className="text-[12px] text-mute">배경색</div>
        <div className="flex gap-2 flex-wrap">
          {colors.map(c => (
            <button key={c} onClick={() => setColor(c)}
              className={cn("w-7 h-7 rounded-full border-2 transition", color === c ? "border-ink" : "border-transparent hover:border-rule")}
              style={{ background: c }} />
          ))}
        </div>
      </div>
      <div className="border-t border-ruleSoft pt-3">
        <button className="text-[12.5px] text-mute hover:text-ink flex items-center gap-1.5">
          <svg width="13" height="13" viewBox="0 0 13 13" fill="none"><path d="M6.5 9V3M3.5 5.5 6.5 2.5 9.5 5.5M2.5 10.5h8" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/></svg>
          이미지 업로드 — <span className="text-dim">곧 지원</span>
        </button>
      </div>
      <div className="flex justify-end gap-2 pt-1">
        <Btn kind="ghost" size="md" onClick={onClose}>취소</Btn>
        <Btn kind="primary" size="md" onClick={save}>저장</Btn>
      </div>
    </div>
  );
}

function ChangePasswordModal({ onClose }) {
  const [cur, setCur] = React.useState("");
  const [next, setNext] = React.useState("");
  const [conf, setConf] = React.useState("");
  const ok = cur.length >= 4 && next.length >= 8 && next === conf;
  const score = passwordScore(next);
  return (
    <div className="p-6 flex flex-col gap-4">
      <div>
        <div className="text-[20px] font-semibold text-ink tracking-tight2">비밀번호 변경</div>
        <div className="text-[13px] text-mute mt-1.5">최소 8자 이상, 다른 사이트와 다른 비밀번호를 권장합니다.</div>
      </div>
      <label className="flex flex-col gap-1.5">
        <span className="text-[12px] text-mute">현재 비밀번호</span>
        <input type="password" autoComplete="current-password" value={cur} onChange={e => setCur(e.target.value)}
          className="bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink outline-none focus:border-ink2" />
      </label>
      <label className="flex flex-col gap-1.5">
        <span className="text-[12px] text-mute">새 비밀번호</span>
        <input type="password" autoComplete="new-password" value={next} onChange={e => setNext(e.target.value)}
          className="bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink outline-none focus:border-ink2" />
        {next && (
          <div className="flex items-center gap-2 mt-1">
            <div className="flex gap-1 flex-1">
              {[0,1,2,3].map(i => (
                <div key={i} className={cn("flex-1 h-1 rounded-full", i < score ? (score < 2 ? "bg-[#C5524C]" : score < 3 ? "bg-accent" : "bg-ok") : "bg-ruleSoft")} />
              ))}
            </div>
            <span className="text-[11px] text-mute">{["매우 약함", "약함", "보통", "강함", "매우 강함"][score]}</span>
          </div>
        )}
      </label>
      <label className="flex flex-col gap-1.5">
        <span className="text-[12px] text-mute">새 비밀번호 확인</span>
        <input type="password" autoComplete="new-password" value={conf} onChange={e => setConf(e.target.value)}
          className={cn("bg-cream border rounded-md px-3 py-2 text-[14px] text-ink outline-none focus:border-ink2",
            conf && conf !== next ? "border-[#C5524C]" : "border-rule")} />
        {conf && conf !== next && <span className="text-[11px] text-[#C5524C]">비밀번호가 일치하지 않아요.</span>}
      </label>
      <div className="flex justify-end gap-2 pt-2">
        <Btn kind="ghost" size="md" onClick={onClose}>취소</Btn>
        <Btn kind="primary" size="md" disabled={!ok} onClick={onClose}>변경</Btn>
      </div>
    </div>
  );
}
function passwordScore(s) {
  if (!s) return 0;
  let n = 0;
  if (s.length >= 8) n++;
  if (/[A-Z]/.test(s) && /[a-z]/.test(s)) n++;
  if (/\d/.test(s)) n++;
  if (/[^A-Za-z0-9]/.test(s)) n++;
  return n;
}

function TwoFAModal({ onClose }) {
  const [step, setStep] = React.useState(1); // 1: QR, 2: code, 3: backup
  const [code, setCode] = React.useState("");
  const next = () => setStep(s => Math.min(3, s + 1));
  const codeOk = /^\d{6}$/.test(code);
  return (
    <div className="p-6 flex flex-col gap-4">
      <div className="flex items-baseline justify-between">
        <div className="text-[20px] font-semibold text-ink tracking-tight2">2단계 인증 설정</div>
        <div className="text-[11.5px] text-dim">{step}/3</div>
      </div>

      {step === 1 && (
        <>
          <div className="text-[13px] text-mute leading-[1.6]">인증 앱(Google Authenticator, 1Password 등)으로 아래 QR 코드를 스캔하세요.</div>
          <div className="bg-cream border border-rule rounded-lg p-4 flex items-center gap-4">
            <FakeQR />
            <div className="flex-1 text-[12px]">
              <div className="text-mute mb-1">또는 키 직접 입력:</div>
              <div className="font-mono text-ink2 text-[11.5px] bg-paper px-2 py-1 rounded border border-rule break-all">JBSWY3DPEHPK3PXP</div>
            </div>
          </div>
        </>
      )}

      {step === 2 && (
        <>
          <div className="text-[13px] text-mute leading-[1.6]">앱에서 표시되는 6자리 코드를 입력하세요.</div>
          <input
            value={code} onChange={e => setCode(e.target.value.replace(/[^0-9]/g, "").slice(0, 6))}
            inputMode="numeric" placeholder="000000"
            className="bg-cream border border-rule rounded-md px-3 py-3 text-[20px] text-ink font-mono tracking-[0.5em] text-center outline-none focus:border-ink2"
          />
        </>
      )}

      {step === 3 && (
        <>
          <div className="text-[13px] text-mute leading-[1.6]">백업 코드를 안전한 곳에 저장하세요. 인증 앱을 사용할 수 없을 때 한 번씩만 쓸 수 있어요.</div>
          <div className="bg-cream border border-rule rounded-lg p-4 grid grid-cols-2 gap-1.5 font-mono text-[12.5px] text-ink2">
            {["4F8K-2N9P", "X7QM-LB3W", "T29A-FK5C", "9P3Z-XHN8", "B7VK-Q2RM", "C5LX-8DT4", "G9NB-3PJK", "MD7W-X4LP"].map(c => <div key={c}>{c}</div>)}
          </div>
          <button className="text-[12.5px] text-ink underline decoration-dotted self-start">백업 코드 다운로드</button>
        </>
      )}

      <div className="flex justify-end gap-2 pt-3">
        <Btn kind="ghost" size="md" onClick={onClose}>{step === 3 ? "완료" : "취소"}</Btn>
        {step < 3 && <Btn kind="primary" size="md" onClick={next} disabled={step === 2 && !codeOk}>{step === 1 ? "다음" : "확인"}</Btn>}
      </div>
    </div>
  );
}
function FakeQR() {
  // Decorative 8x8 mock QR; not a real code.
  const cells = "1111111-1000001-1011101-1011101-1011101-1000001-1111111".split("-");
  const noise = ["10101010", "01010101", "10100101", "01101010", "10010110", "11001100"];
  const grid = [...cells, ...noise];
  return (
    <div className="grid bg-paper" style={{ width: 112, height: 112, gridTemplateColumns: "repeat(13, 1fr)", padding: 4 }}>
      {Array.from({ length: 169 }, (_, i) => {
        const r = Math.floor(i / 13), c = i % 13;
        const row = grid[r] || "0000000000000";
        const on = row[c % row.length] === "1";
        return <div key={i} style={{ background: on ? "#1F1B16" : "#FFFDF7" }} />;
      })}
    </div>
  );
}

function DeleteAccountModal({ onClose }) {
  const { state, dispatch } = useApp();
  const [typed, setTyped] = React.useState("");
  const ok = typed === "삭제";
  return (
    <div className="p-6 flex flex-col gap-4">
      <div>
        <div className="text-[20px] font-semibold text-[#C5524C] tracking-tight2">계정 삭제</div>
        <div className="text-[13px] text-body mt-1.5 leading-[1.6]">
          계정을 삭제하면 공간 <span className="text-ink font-medium">{state.spaces.length}개</span>, 문서 <span className="text-ink font-medium">{state.docs.length}개</span>, 모든 채팅 세션이 영구적으로 사라집니다.
          <br />복구할 수 없어요.
        </div>
      </div>
      <div className="bg-[#FBEEEC] border border-[#E8C6C2] rounded-lg px-3.5 py-3 text-[12.5px] text-[#8E322D] leading-[1.55]">
        먼저 <span className="font-medium">데이터 내보내기</span>로 백업해두는 걸 권장합니다.
        <button onClick={() => { dispatch({ type: "OPEN_MODAL", modal: { type: "export" } }); }} className="ml-1 underline">지금 백업하기</button>
      </div>
      <label className="flex flex-col gap-1.5">
        <span className="text-[12px] text-mute">확인을 위해 <span className="text-ink font-medium">삭제</span>라고 입력하세요</span>
        <input value={typed} onChange={e => setTyped(e.target.value)}
          className="bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink outline-none focus:border-[#C5524C]" />
      </label>
      <div className="flex justify-end gap-2 pt-1">
        <Btn kind="ghost" size="md" onClick={onClose}>취소</Btn>
        <Btn kind="danger" size="md" disabled={!ok} onClick={() => dispatch({ type: "LOGOUT" })}>영구 삭제</Btn>
      </div>
    </div>
  );
}

// ─── Modals: subscription ────────────────────────────────────
function PaymentMethodModal({ onClose }) {
  const [num, setNum] = React.useState("");
  const [exp, setExp] = React.useState("");
  const [cvc, setCvc] = React.useState("");
  const [name, setName] = React.useState("");
  const fmtNum = (v) => v.replace(/\D/g, "").slice(0, 16).replace(/(.{4})/g, "$1 ").trim();
  const fmtExp = (v) => {
    const d = v.replace(/\D/g, "").slice(0, 4);
    return d.length > 2 ? d.slice(0, 2) + "/" + d.slice(2) : d;
  };
  const ok = num.replace(/\s/g, "").length >= 14 && exp.length === 5 && cvc.length >= 3 && name.trim();
  return (
    <div className="p-6 flex flex-col gap-4">
      <div>
        <div className="text-[20px] font-semibold text-ink tracking-tight2">결제 수단</div>
        <div className="text-[13px] text-mute mt-1.5">카드 정보는 외부 결제 처리사에 안전하게 저장됩니다.</div>
      </div>
      <CardPreview num={num} exp={exp} name={name} />
      <label className="flex flex-col gap-1.5">
        <span className="text-[12px] text-mute">카드 번호</span>
        <input value={num} onChange={e => setNum(fmtNum(e.target.value))} inputMode="numeric" placeholder="1234 5678 9012 3456"
          className="bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink font-mono outline-none focus:border-ink2" />
      </label>
      <div className="grid grid-cols-2 gap-3">
        <label className="flex flex-col gap-1.5">
          <span className="text-[12px] text-mute">유효기간</span>
          <input value={exp} onChange={e => setExp(fmtExp(e.target.value))} placeholder="MM/YY"
            className="bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink font-mono outline-none focus:border-ink2" />
        </label>
        <label className="flex flex-col gap-1.5">
          <span className="text-[12px] text-mute">CVC</span>
          <input value={cvc} onChange={e => setCvc(e.target.value.replace(/\D/g, "").slice(0, 4))} placeholder="123"
            className="bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink font-mono outline-none focus:border-ink2" />
        </label>
      </div>
      <label className="flex flex-col gap-1.5">
        <span className="text-[12px] text-mute">카드 소유자</span>
        <input value={name} onChange={e => setName(e.target.value)}
          className="bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink outline-none focus:border-ink2" />
      </label>
      <div className="flex justify-end gap-2 pt-1">
        <Btn kind="ghost" size="md" onClick={onClose}>취소</Btn>
        <Btn kind="primary" size="md" disabled={!ok} onClick={onClose}>저장</Btn>
      </div>
    </div>
  );
}
function CardPreview({ num, exp, name }) {
  return (
    <div className="rounded-xl p-4 text-cream shadow-paper" style={{ background: "linear-gradient(135deg, #2A2620 0%, #1F1B16 100%)" }}>
      <div className="flex items-center justify-between">
        <div className="text-[10.5px] uppercase tracking-[0.08em] opacity-70">신용카드</div>
        <div className="font-semibold tracking-tight2">VISA</div>
      </div>
      <div className="mt-6 font-mono text-[15px] tracking-[0.12em]">{num || "•••• •••• •••• ••••"}</div>
      <div className="mt-4 flex items-end justify-between text-[10.5px]">
        <div>
          <div className="opacity-60 uppercase">소유자</div>
          <div className="font-medium tracking-wider mt-0.5 text-[12px]">{name || "이름"}</div>
        </div>
        <div className="text-right">
          <div className="opacity-60 uppercase">만료</div>
          <div className="font-mono mt-0.5 text-[12px]">{exp || "MM/YY"}</div>
        </div>
      </div>
    </div>
  );
}

function BillingHistoryModal({ onClose }) {
  const rows = [
    { date: "2026-05-27", desc: "Pro 월간 구독", amount: "₩12,000", status: "결제 완료", id: "INV-2026-0527" },
    { date: "2026-04-27", desc: "Pro 월간 구독", amount: "₩12,000", status: "결제 완료", id: "INV-2026-0427" },
    { date: "2026-03-27", desc: "Pro 월간 구독", amount: "₩12,000", status: "결제 완료", id: "INV-2026-0327" },
    { date: "2026-02-27", desc: "Pro 월간 구독", amount: "₩12,000", status: "결제 완료", id: "INV-2026-0227" },
    { date: "2026-01-27", desc: "Pro 월간 구독", amount: "₩12,000", status: "결제 완료", id: "INV-2026-0127" },
  ];
  return (
    <div className="p-6 flex flex-col gap-4">
      <div>
        <div className="text-[20px] font-semibold text-ink tracking-tight2">청구 내역</div>
        <div className="text-[13px] text-mute mt-1.5">최근 12개월간의 결제 기록입니다.</div>
      </div>
      <div className="border border-rule rounded-lg overflow-hidden">
        <table className="w-full text-[12.5px]">
          <thead className="bg-cream text-mute uppercase tracking-[0.06em] text-[10.5px]">
            <tr>
              <th className="text-left px-3 py-2.5 font-medium">날짜</th>
              <th className="text-left px-3 py-2.5 font-medium">항목</th>
              <th className="text-right px-3 py-2.5 font-medium">금액</th>
              <th className="text-left px-3 py-2.5 font-medium">상태</th>
              <th className="px-3 py-2.5"></th>
            </tr>
          </thead>
          <tbody className="divide-y divide-ruleSoft">
            {rows.map(r => (
              <tr key={r.id} className="text-ink2">
                <td className="px-3 py-2.5 tabular-nums">{r.date}</td>
                <td className="px-3 py-2.5">{r.desc}</td>
                <td className="px-3 py-2.5 text-right tabular-nums">{r.amount}</td>
                <td className="px-3 py-2.5"><Pill tone="ok">{r.status}</Pill></td>
                <td className="px-3 py-2.5 text-right">
                  <button className="text-[12px] text-mute hover:text-ink underline decoration-dotted">PDF</button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <div className="flex justify-end pt-1">
        <Btn kind="ghost" size="md" onClick={onClose}>닫기</Btn>
      </div>
    </div>
  );
}

function CheckoutModal({ planId, onClose }) {
  const { dispatch } = useApp();
  const PLAN_INFO = {
    pro:  { name: "Pro",  price: 12000, desc: "본격적인 글·기록 작업" },
    team: { name: "Team", price: 24000, desc: "팀 단위 위키" },
  };
  const plan = PLAN_INFO[planId] || PLAN_INFO.pro;
  const [step, setStep] = React.useState("review"); // review | done
  const confirm = () => {
    setStep("done");
    setTimeout(() => {
      dispatch({ type: "SET_PLAN", plan: planId });
      onClose?.();
    }, 1500);
  };
  return (
    <div className="p-6 flex flex-col gap-4">
      {step === "review" ? (
        <>
          <div>
            <div className="text-[11.5px] text-mute uppercase tracking-[0.08em] font-medium mb-1">결제 확인</div>
            <div className="text-[22px] font-semibold text-ink tracking-tight2">{plan.name} 요금제로 업그레이드</div>
          </div>
          <div className="bg-paper border border-rule rounded-lg">
            <div className="flex items-center justify-between px-4 py-3 border-b border-ruleSoft">
              <span className="text-[13px] text-mute">{plan.name} 월간 구독</span>
              <span className="text-[14px] text-ink tabular-nums">₩{plan.price.toLocaleString()}</span>
            </div>
            <div className="flex items-center justify-between px-4 py-3 border-b border-ruleSoft">
              <span className="text-[13px] text-mute">부가세 (10%)</span>
              <span className="text-[14px] text-ink tabular-nums">₩{Math.round(plan.price * 0.1).toLocaleString()}</span>
            </div>
            <div className="flex items-center justify-between px-4 py-3 bg-cream">
              <span className="text-[13.5px] text-ink font-medium">오늘 결제 금액</span>
              <span className="text-[18px] text-ink font-semibold tabular-nums">₩{Math.round(plan.price * 1.1).toLocaleString()}</span>
            </div>
          </div>
          <div className="text-[12px] text-mute leading-[1.6]">
            매월 같은 날짜에 자동으로 갱신됩니다. 언제든 설정에서 취소할 수 있어요.<br />
            결제 수단: <span className="text-ink">•••• 1234 · 만료 12/27</span>
          </div>
          <div className="flex justify-end gap-2 pt-1">
            <Btn kind="ghost" size="md" onClick={onClose}>취소</Btn>
            <Btn kind="primary" size="md" onClick={confirm}>결제하고 시작</Btn>
          </div>
        </>
      ) : (
        <div className="py-8 flex flex-col items-center gap-3 text-center">
          <div className="w-12 h-12 rounded-full bg-okSoft border border-okBord inline-flex items-center justify-center text-[#3E7C5C] text-[24px]">✓</div>
          <div className="text-[18px] font-semibold text-ink">결제 완료</div>
          <div className="text-[13px] text-mute">{plan.name} 요금제가 활성화됐어요.</div>
        </div>
      )}
    </div>
  );
}

// ─── Modals: data ────────────────────────────────────────────
function ExportModal({ kind, onClose }) {
  const { state } = useApp();
  // kind: 'docs' | 'sessions' | 'history' | undefined
  const types = [
    { id: "docs",     label: "전체 문서 (.md zip)", desc: `${state.docs.length}개 파일을 공간 폴더로 묶어 zip으로` },
    { id: "sessions", label: "채팅 세션 (.json)",   desc: `기본 + 공간 세션 메시지 ${state.spaces.length + 1}개 공간` },
    { id: "history",  label: "자동 정리 이력 (.csv)", desc: `이력 ${state.history.length}건` },
  ];
  const [sel, setSel] = React.useState(() => new Set([kind || "docs"]));
  const [step, setStep] = React.useState("pick"); // pick | running | done
  const [progress, setProgress] = React.useState(0);

  const start = () => {
    setStep("running");
    setProgress(0);
    let p = 0;
    const tick = () => {
      p += 8 + Math.random() * 16;
      if (p >= 100) { setProgress(100); setTimeout(() => setStep("done"), 350); return; }
      setProgress(p); setTimeout(tick, 120);
    };
    tick();
  };

  const toggle = (id) => {
    const s = new Set(sel); s.has(id) ? s.delete(id) : s.add(id); setSel(s);
  };

  return (
    <div className="p-6 flex flex-col gap-4">
      {step === "pick" && (
        <>
          <div>
            <div className="text-[20px] font-semibold text-ink tracking-tight2">내보내기</div>
            <div className="text-[13px] text-mute mt-1.5">필요한 항목을 골라 내려받으세요. 모든 형식은 표준 텍스트 기반입니다.</div>
          </div>
          <div className="flex flex-col gap-1">
            {types.map(t => (
              <label key={t.id} className="flex items-start gap-3 px-3 py-2.5 rounded-md hover:bg-cream cursor-pointer">
                <input type="checkbox" checked={sel.has(t.id)} onChange={() => toggle(t.id)} className="accent-ink w-4 h-4 mt-0.5" />
                <span className="flex-1">
                  <span className="block text-[13.5px] text-ink font-medium">{t.label}</span>
                  <span className="block text-[11.5px] text-dim mt-0.5">{t.desc}</span>
                </span>
              </label>
            ))}
          </div>
          <div className="text-[11.5px] text-dim border-t border-ruleSoft pt-3 leading-[1.55]">
            대용량은 시간이 좀 걸려요. 진행 중에도 다른 작업 계속할 수 있어요.
          </div>
          <div className="flex justify-end gap-2">
            <Btn kind="ghost" size="md" onClick={onClose}>취소</Btn>
            <Btn kind="primary" size="md" onClick={start} disabled={!sel.size}>내보내기 시작</Btn>
          </div>
        </>
      )}
      {step === "running" && (
        <div className="py-6 flex flex-col items-center gap-3 text-center">
          <div className="text-[14px] text-ink font-medium">내보내는 중…</div>
          <div className="w-full max-w-[280px] h-2 rounded-full bg-ruleSoft overflow-hidden">
            <div className="h-full bg-ink transition-all" style={{ width: progress + "%" }} />
          </div>
          <div className="text-[12px] text-dim tabular-nums">{Math.round(progress)}%</div>
        </div>
      )}
      {step === "done" && (
        <div className="py-6 flex flex-col items-center gap-3 text-center">
          <div className="w-12 h-12 rounded-full bg-okSoft border border-okBord inline-flex items-center justify-center text-[#3E7C5C] text-[24px]">↓</div>
          <div className="text-[16px] font-semibold text-ink">내보내기 완료</div>
          <div className="text-[12.5px] text-mute">파일이 다운로드 폴더에 저장됐어요.</div>
          <Btn kind="primary" size="md" onClick={onClose}>확인</Btn>
        </div>
      )}
    </div>
  );
}

function ImportModal({ onClose }) {
  const [dragOver, setDragOver] = React.useState(false);
  const [files, setFiles] = React.useState([]); // {name, size}
  const [targetSpace, setTargetSpace] = React.useState("new");
  const [newSpaceName, setNewSpaceName] = React.useState("");
  const [step, setStep] = React.useState("pick"); // pick | done

  const onFileInput = (e) => {
    const fs = [...(e.target.files || [])].filter(f => /\.(md|markdown|txt)$/i.test(f.name)).map(f => ({ name: f.name, size: f.size }));
    setFiles(fs);
  };
  const onDrop = (e) => {
    e.preventDefault(); setDragOver(false);
    const fs = [...(e.dataTransfer?.files || [])].filter(f => /\.(md|markdown|txt)$/i.test(f.name)).map(f => ({ name: f.name, size: f.size }));
    setFiles(fs);
  };

  return (
    <div className="p-6 flex flex-col gap-4">
      {step === "pick" ? (
        <>
          <div>
            <div className="text-[20px] font-semibold text-ink tracking-tight2">가져오기</div>
            <div className="text-[13px] text-mute mt-1.5">마크다운(.md) 파일을 공간으로 가져옵니다. 폴더를 통째로 드래그해도 돼요.</div>
          </div>

          <label
            onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
            onDragLeave={() => setDragOver(false)}
            onDrop={onDrop}
            className={cn("flex flex-col items-center justify-center gap-2 px-6 py-10 rounded-xl border-2 border-dashed transition cursor-pointer",
              dragOver ? "border-ink bg-cream" : "border-rule bg-cream hover:bg-paper")}
          >
            <div className="text-[28px] text-mute">⤓</div>
            <div className="text-[13.5px] text-ink2 font-medium">파일을 끌어다 놓거나 클릭해서 선택</div>
            <div className="text-[11.5px] text-dim">.md, .markdown, .txt</div>
            <input type="file" multiple accept=".md,.markdown,.txt,text/markdown" onChange={onFileInput} className="hidden" />
          </label>

          {files.length > 0 && (
            <div className="bg-paper border border-rule rounded-lg max-h-[160px] overflow-y-auto scroll-paper">
              {files.slice(0, 30).map((f, i) => (
                <div key={i} className="flex items-center justify-between px-3 py-1.5 text-[12.5px] border-b border-ruleSoft last:border-0">
                  <span className="text-ink truncate">{f.name}</span>
                  <span className="text-dim tabular-nums shrink-0 ml-3">{(f.size / 1024).toFixed(1)} KB</span>
                </div>
              ))}
              {files.length > 30 && <div className="px-3 py-1.5 text-[11.5px] text-dim">외 {files.length - 30}개</div>}
            </div>
          )}

          <div className="flex flex-col gap-1.5 mt-1">
            <span className="text-[12px] text-mute">어느 공간으로?</span>
            <ImportTarget value={targetSpace} onChange={setTargetSpace} />
            {targetSpace === "new" && (
              <input value={newSpaceName} onChange={e => setNewSpaceName(e.target.value)} placeholder="새 공간 이름"
                className="bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink outline-none focus:border-ink2 mt-1" />
            )}
          </div>

          <div className="flex justify-end gap-2 pt-1">
            <Btn kind="ghost" size="md" onClick={onClose}>취소</Btn>
            <Btn kind="primary" size="md" disabled={!files.length} onClick={() => setStep("done")}>{files.length}개 가져오기</Btn>
          </div>
        </>
      ) : (
        <div className="py-6 flex flex-col items-center gap-3 text-center">
          <div className="w-12 h-12 rounded-full bg-okSoft border border-okBord inline-flex items-center justify-center text-[#3E7C5C] text-[24px]">✓</div>
          <div className="text-[16px] font-semibold text-ink">{files.length}개 문서를 가져왔어요</div>
          <div className="text-[12.5px] text-mute">새로 만든 공간에서 바로 확인할 수 있습니다.</div>
          <Btn kind="primary" size="md" onClick={onClose}>닫기</Btn>
        </div>
      )}
    </div>
  );
}
function ImportTarget({ value, onChange }) {
  const { state } = useApp();
  return (
    <select value={value} onChange={e => onChange(e.target.value)}
      className="bg-cream border border-rule rounded-md px-3 py-2 text-[14px] text-ink outline-none focus:border-ink2">
      <option value="new">+ 새 공간 만들기</option>
      {state.spaces.map(s => <option key={s.id} value={s.id}>{s.name}</option>)}
    </select>
  );
}

Object.assign(window, {
  SettingsView,
  AvatarModal, ChangePasswordModal, TwoFAModal, DeleteAccountModal,
  PaymentMethodModal, BillingHistoryModal, CheckoutModal,
  ExportModal, ImportModal,
});
