// Settings.jsx — Account + Settings detail pages.
// Wired panes: Profile (user from /auth/me), Defaults + Appearance (PUT /settings).
// Other panes remain mock demos since canon_lm_server has no backing endpoints
// (billing, key catalog, sessions, 2FA, notifications, shortcuts UI).
function SettingsShell({ initial = 'account-profile', onBack, user, setUser, onSignOut }) {
  const [sel, setSel] = React.useState(initial);
  const [modal, setModal] = React.useState(null);
  const [valEdit, setValEdit] = React.useState(null);
  const [settings, setSettings] = React.useState(null);
  const [savedAt, setSavedAt] = React.useState(null);
  React.useEffect(() => { window.__chOpenModal = setModal; window.__chOpenValueEdit = setValEdit; }, []);

  // Load /settings once
  React.useEffect(() => {
    let cancelled = false;
    window.API.getSettings()
      .then(s => { if (!cancelled) setSettings(s); })
      .catch(() => {});
    return () => { cancelled = true; };
  }, []);

  const updateSettings = async (patch) => {
    setSettings(s => ({ ...(s || {}), ...patch }));
    try {
      const updated = await window.API.putSettings(patch);
      setSettings(updated);
      setSavedAt(Date.now());
      setTimeout(() => setSavedAt(null), 1500);
    } catch (_) {}
  };
  const sections = [
    { group: '계정', items: [
      { id: 'account-profile', label: '프로필' },
      { id: 'account-plan', label: '요금제 · 결제' },
      { id: 'account-keys', label: 'API 키' },
      { id: 'account-sessions', label: '세션' },
      { id: 'account-security', label: '보안' },
    ]},
    { group: '설정', items: [
      { id: 'set-appearance', label: '외관' },
      { id: 'set-defaults', label: '채팅 기본값' },
      { id: 'set-notifications', label: '알림' },
      { id: 'set-shortcuts', label: '단축키' },
      { id: 'set-data', label: '데이터 · 개인정보' },
    ]},
  ];
  return (
    <>
    <div className="ch-settings" data-screen-label="Account & Settings">
      <aside className="sub">
        <div className="sub-head">
          <button onClick={onBack} title="채팅으로 돌아가기">←</button>
          <h2>계정 · 설정</h2>
        </div>
        {sections.map(s => <React.Fragment key={s.group}>
          <div className="sub-section">{s.group}</div>
          {s.items.map(it => (
            <div key={it.id} className={'sub-link' + (sel === it.id ? ' active' : '')} onClick={() => setSel(it.id)}>
              <span className="ico"></span>{it.label}
            </div>
          ))}
        </React.Fragment>)}
      </aside>
      <div className="pane">
        <div className="pane-inner">
          {sel === 'account-profile' && <ProfilePane user={user} setUser={setUser}/>}
          {sel === 'account-plan' && <PlanPane/>}
          {sel === 'account-keys' && <KeysPane/>}
          {sel === 'account-sessions' && <SessionsPane/>}
          {sel === 'account-security' && <SecurityPane onSignOut={onSignOut}/>}
          {sel === 'set-appearance' && <AppearancePane settings={settings} updateSettings={updateSettings} savedAt={savedAt}/>}
          {sel === 'set-defaults' && <DefaultsPane settings={settings} updateSettings={updateSettings} savedAt={savedAt}/>}
          {sel === 'set-notifications' && <NotificationsPane/>}
          {sel === 'set-shortcuts' && <ShortcutsPane/>}
          {sel === 'set-data' && <DataPane/>}
        </div>
      </div>
    </div>
    {modal === 'new-key' && <NewKeyModal onClose={() => setModal(null)}/>}
    {modal === 'recovery' && <RecoveryCodesModal onClose={() => setModal(null)}/>}
    {modal === 'change-pw' && <ChangePasswordModal onClose={() => setModal(null)}/>}
    {modal === 'totp' && <TotpModal onClose={() => setModal(null)}/>}
    {modal === 'upgrade' && <UpgradeModal onClose={() => setModal(null)}/>}
    {modal === 'photo' && <PhotoUploadModal onClose={() => setModal(null)}/>}
    {modal === 'export' && <ExportModal onClose={() => setModal(null)}/>}
    {modal === 'confirm-revoke-key' && <ConfirmModal eb="Account · API keys" title="Revoke this key?" desc="Any application using this key will start receiving 401 within seconds." confirmText="Revoke key" onClose={() => setModal(null)}/>}
    {modal === 'confirm-signout' && <ConfirmModal eb="Account · Sessions" title="Sign out of all other sessions?" desc="You'll remain signed in on this device." confirmText="Sign out everywhere" onClose={() => setModal(null)}/>}
    {modal === 'confirm-delete-account' && <ConfirmModal eb="Account · Profile" title="Delete your account?" desc="Your workspace will be retained for 30 days then permanently destroyed." confirmText="Delete account" requirePhrase="DELETE" onClose={() => setModal(null)}/>}
    {modal === 'confirm-delete-convos' && <ConfirmModal eb="Settings · Data & privacy" title="Delete all conversations?" desc="All threads and their messages will be removed. Certificates remain." confirmText="Delete conversations" onClose={() => setModal(null)}/>}
    {valEdit && <ValueEditModal presetKey={valEdit} onClose={() => setValEdit(null)}/>}
    </>
  );
}

/* ---- Account ---- */
function ProfilePane({ user, setUser }) {
  const initialName = (user && user.display_name) || '';
  const email = user ? user.email : '—';
  const [name, setName] = React.useState(initialName);
  const [busy, setBusy] = React.useState(false);
  const [msg, setMsg]   = React.useState(null);
  React.useEffect(() => { setName(initialName); }, [initialName]);

  const dirty = name.trim() !== (initialName || '').trim();
  const initial = ((name || email || '?')[0] || '?').toUpperCase();
  const role = user && user.is_admin ? '관리자 · 워크스페이스 소유자' : '일반 사용자';
  const joined = user && user.created_at ? new Date(user.created_at * 1000).toISOString().slice(0, 10) : '—';

  const save = async () => {
    if (!dirty || busy) return;
    setBusy(true); setMsg(null);
    try {
      const updated = await window.API.updateProfile({ display_name: name.trim() || null });
      if (setUser) setUser(updated);
      setMsg({ ok: true, text: '저장됨' });
      setTimeout(() => setMsg(null), 1500);
    } catch (e) {
      setMsg({ ok: false, text: e.message || '저장 실패' });
    } finally {
      setBusy(false);
    }
  };

  return <>
    <div className="pane-eb">계정 · 프로필</div>
    <h1>GBR 에서 보이는 신원.</h1>
    <p className="lede"><code>/auth/me</code> 응답 기반. 표시 이름은 즉시 저장됩니다. 이메일 변경은 별도 sprint 예정.</p>
    <div className="ch-card">
      <div className="ch-profile">
        <div className="pic">{initial}</div>
        <div className="who">
          <div className="n">{name || email}</div>
          <div className="e">{email}</div>
          <span className="role">{role}</span>
        </div>
      </div>
      <div className="ch-row">
        <div className="lbl">표시 이름 <small>이름이 비면 이메일이 표시됩니다</small></div>
        <div className="ctrl" style={{gap:8}}>
          <input
            value={name}
            maxLength={80}
            onChange={e => setName(e.target.value)}
            placeholder={email}
          />
          <button className={dirty ? 'primary' : 'ghost'} disabled={!dirty || busy} onClick={save}
                  style={{padding:'8px 14px', fontSize:13}}>
            {busy ? '저장 중…' : '저장'}
          </button>
        </div>
      </div>
      {msg && (
        <div className="ch-row" style={{paddingTop:0}}>
          <div className="lbl"></div>
          <div className="ctrl">
            <span style={{
              fontFamily: 'var(--font-mono)', fontSize: 11,
              color: msg.ok ? 'var(--zg-success,var(--fg-2))' : 'var(--zg-danger)',
            }}>{msg.text}</span>
          </div>
        </div>
      )}
      <div className="ch-row"><div className="lbl">이메일 <small>로그인 시 사용</small></div><div className="ctrl"><input type="text" value={email} readOnly/></div></div>
      <div className="ch-row"><div className="lbl">사용자 ID</div><div className="ctrl"><span className="v">{user ? '#' + user.id : '—'}</span></div></div>
      <div className="ch-row"><div className="lbl">가입일</div><div className="ctrl"><span className="v">{joined}</span></div></div>
      <div className="ch-row"><div className="lbl">관리자 권한</div><div className="ctrl"><span className="v">{user && user.is_admin ? '예' : '아니오'}</span></div></div>
    </div>
    <div className="ch-card">
      <h3>이 계정에서 로그아웃</h3>
      <p className="desc">현재 디바이스의 토큰을 무효화하고 로그인 화면으로 돌아갑니다.</p>
      <div className="ch-row">
        <div className="lbl">{user && (user.display_name || user.email)} 에서 로그아웃<small>다시 사용하려면 비밀번호 입력 필요</small></div>
        <div className="ctrl">
          <button
            className="danger"
            onClick={() => {
              if (window.confirm('로그아웃 하시겠어요?')) {
                window.API.clear();
                location.reload();
              }
            }}
            style={{padding: '8px 18px', fontSize: 13}}
          >로그아웃</button>
        </div>
      </div>
    </div>
  </>;
}

function PlanPane() {
  return <>
    <div className="pane-eb">계정 · 요금제 · 결제</div>
    <h1>요금제 · 사용량.</h1>
    <p className="lede">현재 <strong style={{color:'var(--accent)'}}>Lab</strong> 요금제 (예시 mockup) · 2026-12-12 갱신 예정. 우리는 byte 기반 과금을 검토 중입니다 (3 bytes ≈ 1 token, 한국어 차별 보정).</p>
    <div className="ch-card">
      <div className="ch-plan">
        <div className="item"><div className="lbl">사용 바이트</div><div className="v">1.24 MB</div><div className="sub">월 한도 50 MB</div></div>
        <div className="item"><div className="lbl">대화 수</div><div className="v">1,284</div><div className="sub">월 한도 5,000</div></div>
        <div className="item"><div className="lbl">예상 청구</div><div className="v">₩ 0</div><div className="sub">데모 기간 무료</div></div>
      </div>
      <div className="ch-row"><div className="lbl">요금제</div><div className="ctrl"><span className="v">Lab · ₩ 0/월 (데모)</span><button className="primary" onClick={() => window.__chOpenModal('upgrade')}>Atlas 로 업그레이드</button></div></div>
      <div className="ch-row"><div className="lbl">결제 수단 <small>준비 중 · 토스 연동 예정</small></div><div className="ctrl"><span className="v">미설정</span><button className="ghost" disabled>변경</button></div></div>
      <div className="ch-row"><div className="lbl">청구 이메일</div><div className="ctrl"><span className="v">billing@gbr.ai</span><button className="ghost" onClick={() => window.__chOpenValueEdit('billing-email')}>변경</button></div></div>
      <div className="ch-row"><div className="lbl">청구서 내역</div><div className="ctrl"><button className="ghost" onClick={() => window.__chOpenValueEdit('invoices')}>CSV 다운로드</button></div></div>
    </div>
  </>;
}

function KeysPane() {
  return <>
    <div className="pane-eb">계정 · API 키</div>
    <h1>API 키.</h1>
    <p className="lede">현재 서버에 API 키 발급/관리 기능이 없습니다. 곧 사용 가능합니다 (별 sprint 예정).</p>
    <div className="ch-card">
      <p className="desc" style={{margin:0}}>예정된 기능:</p>
      <ul style={{color:'var(--fg-3)',fontSize:13,lineHeight:1.7,paddingLeft:18,margin:'10px 0 0'}}>
        <li>키 발급 (scopes: read / write / admin)</li>
        <li>마지막 사용 시각 + IP 추적</li>
        <li>키 폐기 (revoke) — 즉시 401</li>
        <li>키당 rate limit 설정</li>
      </ul>
    </div>
  </>;
}

function SessionsPane() {
  return <>
    <div className="pane-eb">계정 · 세션</div>
    <h1>활성 세션.</h1>
    <p className="lede">현재 서버는 JWT stateless 인증만 사용해 세션 추적 기능이 없습니다. 별 sprint 예정.</p>
    <div className="ch-card">
      <p className="desc" style={{margin:0}}>예정된 기능:</p>
      <ul style={{color:'var(--fg-3)',fontSize:13,lineHeight:1.7,paddingLeft:18,margin:'10px 0 0'}}>
        <li>로그인 디바이스/위치/IP 목록</li>
        <li>개별 세션 폐기</li>
        <li>다른 모든 세션에서 로그아웃</li>
        <li>로그인 알림 (새 기기 감지)</li>
      </ul>
      <div className="ch-row" style={{marginTop:14}}>
        <div className="lbl">이 디바이스에서 로그아웃 <small>로컬 토큰 무효화</small></div>
        <div className="ctrl"><button className="ghost" onClick={() => { window.API.clear(); location.reload(); }}>로그아웃</button></div>
      </div>
    </div>
  </>;
}

function SecurityPane({ onSignOut }) {
  return <>
    <div className="pane-eb">계정 · 보안</div>
    <h1>보안.</h1>
    <p className="lede">비밀번호 해시는 PBKDF2-SHA256 (200k iterations) 사용 중. 2단계 인증/복구 코드/SSO 등은 별 sprint 예정.</p>
    <ChangePasswordCard/>
    <div className="ch-card">
      <div className="ch-row"><div className="lbl">2단계 인증 (TOTP)<small>준비 중</small></div><div className="ctrl"><span className="v" style={{color:'var(--fg-4)'}}>비활성</span><button className="ghost" disabled>설정</button></div></div>
      <div className="ch-row"><div className="lbl">복구 코드<small>준비 중</small></div><div className="ctrl"><button className="ghost" disabled>코드 보기</button></div></div>
      <div className="ch-row"><div className="lbl">SSO (SAML)<small>준비 중</small></div><div className="ctrl"><div className="ch-switch"></div></div></div>
      <div className="ch-row"><div className="lbl">로그인 알림<small>준비 중 · 새 기기 감지 시 이메일</small></div><div className="ctrl"><div className="ch-switch"></div></div></div>
    </div>
    <DeleteSelfCard onSignOut={onSignOut}/>
  </>;
}

function ChangePasswordCard() {
  const [cur, setCur] = React.useState('');
  const [nw, setNw]   = React.useState('');
  const [nw2, setNw2] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [msg, setMsg]   = React.useState(null);

  const valid = cur && nw.length >= 8 && nw === nw2;
  const submit = async (e) => {
    e.preventDefault();
    if (!valid || busy) return;
    setBusy(true); setMsg(null);
    try {
      await window.API.changePassword(cur, nw);
      setCur(''); setNw(''); setNw2('');
      setMsg({ ok: true, text: '비밀번호가 변경되었습니다.' });
      setTimeout(() => setMsg(null), 2500);
    } catch (e) {
      setMsg({ ok: false, text: e.message || '변경 실패' });
    } finally {
      setBusy(false);
    }
  };
  return (
    <form className="ch-card" onSubmit={submit}>
      <h3>비밀번호 변경</h3>
      <p className="desc">최소 8자. 변경해도 현재 세션은 유지됩니다 (다른 디바이스 강제 로그아웃은 별도 sprint 예정).</p>
      <div className="ch-row"><div className="lbl">현재 비밀번호</div>
        <div className="ctrl"><input type="password" value={cur} onChange={e => setCur(e.target.value)} autoComplete="current-password"/></div></div>
      <div className="ch-row"><div className="lbl">새 비밀번호<small>8자 이상</small></div>
        <div className="ctrl"><input type="password" value={nw} onChange={e => setNw(e.target.value)} autoComplete="new-password" minLength={8}/></div></div>
      <div className="ch-row"><div className="lbl">새 비밀번호 확인</div>
        <div className="ctrl">
          <input type="password" value={nw2} onChange={e => setNw2(e.target.value)} autoComplete="new-password" minLength={8}/>
        </div></div>
      {nw2 && nw !== nw2 && (
        <div className="ch-row"><div className="lbl"></div>
          <div className="ctrl"><span style={{color:'var(--zg-danger)', fontSize:11}}>비밀번호가 일치하지 않습니다.</span></div></div>
      )}
      {msg && (
        <div className="ch-row"><div className="lbl"></div>
          <div className="ctrl"><span style={{
            fontFamily:'var(--font-mono)', fontSize:11,
            color: msg.ok ? 'var(--zg-success,var(--fg-2))' : 'var(--zg-danger)',
          }}>{msg.text}</span></div></div>
      )}
      <div className="ch-row"><div className="lbl"></div>
        <div className="ctrl"><button type="submit" className={valid ? 'primary' : 'ghost'} disabled={!valid || busy}
                style={{padding:'8px 18px', fontSize:13}}>
          {busy ? '변경 중…' : '비밀번호 변경'}
        </button></div></div>
    </form>
  );
}

function DeleteSelfCard({ onSignOut }) {
  const [pw, setPw] = React.useState('');
  const [phrase, setPhrase] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const armed = phrase.trim() === 'DELETE' && pw.length > 0;

  const submit = async () => {
    if (!armed || busy) return;
    if (!window.confirm('정말로 계정을 삭제하시겠어요? 대화 기록도 함께 삭제됩니다. 되돌릴 수 없습니다.')) return;
    setBusy(true); setErr(null);
    try {
      await window.API.deleteSelf(pw);
      if (onSignOut) onSignOut();
      else location.reload();
    } catch (e) {
      setErr(e.message || '탈퇴 실패');
      setBusy(false);
    }
  };

  return (
    <div className="ch-card" style={{borderColor:'rgba(201,92,74,0.3)'}}>
      <h3 style={{color:'var(--zg-danger)'}}>위험 작업 · 회원 탈퇴</h3>
      <p className="desc">
        계정과 모든 대화 기록이 즉시 삭제됩니다. 되돌릴 수 없습니다. 관리자 계정인 경우
        마지막 관리자가 남아 있을 때는 탈퇴할 수 없습니다.
      </p>
      <div className="ch-row"><div className="lbl">비밀번호 확인</div>
        <div className="ctrl"><input type="password" value={pw} onChange={e => setPw(e.target.value)} autoComplete="current-password"/></div></div>
      <div className="ch-row"><div className="lbl"><code>DELETE</code> 입력</div>
        <div className="ctrl"><input type="text" value={phrase} onChange={e => setPhrase(e.target.value)} placeholder="DELETE" autoCapitalize="characters"/></div></div>
      {err && (
        <div className="ch-row"><div className="lbl"></div>
          <div className="ctrl"><span style={{fontFamily:'var(--font-mono)', fontSize:11, color:'var(--zg-danger)'}}>{err}</span></div></div>
      )}
      <div className="ch-row"><div className="lbl"></div>
        <div className="ctrl"><button className="danger" disabled={!armed || busy} onClick={submit}
                style={{padding:'8px 18px', fontSize:13}}>
          {busy ? '삭제 중…' : '회원 탈퇴'}
        </button></div></div>
    </div>
  );
}

/* ---- Settings ---- */
function SavedChip({ savedAt }) {
  if (!savedAt) return null;
  return <span style={{marginLeft:10, color:'var(--zg-success)', fontFamily:'var(--font-mono)', fontSize:10.5, letterSpacing:'0.08em'}}>SAVED</span>;
}

function AppearancePane({ settings, updateSettings, savedAt }) {
  const theme = settings && settings.theme ? settings.theme : 'dark';
  const pickTheme = (t) => {
    if (window.applyTheme) window.applyTheme(t);
    if (updateSettings) updateSettings({ theme: t });
  };
  const themes = [
    { id: 'dark',   label: '다크' },
    { id: 'light',  label: '라이트' },
    { id: 'system', label: '시스템' },
  ];
  return <>
    <div className="pane-eb">설정 · 외관</div>
    <h1>화면 테마.<SavedChip savedAt={savedAt}/></h1>
    <p className="lede">서버에 즉시 저장되며 다음 접속 시에도 유지됩니다. '시스템'은 OS 다크모드 설정을 따라갑니다.</p>
    <div className="ch-card">
      <div className="ch-row"><div className="lbl">테마</div><div className="ctrl"><div className="ch-radio-group">
        {themes.map(o => (
          <button key={o.id} className={theme===o.id?'on':''} onClick={() => pickTheme(o.id)}>{o.label}</button>
        ))}
      </div></div></div>
      <div className="ch-row"><div className="lbl">밀도 <small>준비 중</small></div><div className="ctrl"><div className="ch-radio-group">{['컴팩트','보통','넓게'].map((o,i) => <button key={i} className={i===1?'on':''} disabled>{o}</button>)}</div></div></div>
      <div className="ch-row"><div className="lbl">모션 줄이기 <small>준비 중 · 펄스/페이드 비활성화</small></div><div className="ctrl"><div className="ch-switch"></div></div></div>
    </div>
  </>;
}

function DefaultsPane({ settings, updateSettings, savedAt }) {
  const temp   = settings ? settings.default_temp : 0.2;
  const topP   = settings ? settings.default_top_p : 0.95;
  const maxTok = settings ? settings.default_max_tokens : 512;
  const sysPrompt = settings ? (settings.system_prompt || '') : '';
  const [localSys, setLocalSys] = React.useState(sysPrompt);
  React.useEffect(() => { setLocalSys(sysPrompt); }, [sysPrompt]);
  const set = (k, v) => updateSettings && updateSettings({ [k]: v });

  // Live model identity from the engine (/v1/models). The Rust proxy ignores
  // any client-supplied `model` and uses whatever the M3 sidecar reports, so
  // a static dropdown would be misleading — we surface the auto-detected name
  // read-only and let the LLM team swap it via CPN_VERSION on the M3 box.
  const [liveModel, setLiveModel] = React.useState(null);
  React.useEffect(() => {
    let cancelled = false;
    window.API.liveModel().then(id => { if (!cancelled) setLiveModel(id); });
    return () => { cancelled = true; };
  }, []);

  // Token guidance: 한국어는 byte-level (UTF-8 3 bytes/char) 이라 영문 대비 토큰 효율 다름.
  // 우리 byte-level 엔진은 1 byte = 1 token. 외부 LLM은 1 word ≈ 1.3 tokens 정도.
  return <>
    <div className="pane-eb">설정 · 채팅 기본값</div>
    <h1>채팅 기본값.<SavedChip savedAt={savedAt}/></h1>
    <p className="lede">새 대화에 자동 적용됩니다. 슬라이더 값은 <code>PUT /settings</code> 로 즉시 저장됩니다.</p>
    <div className="ch-card">
      <div className="ch-row">
        <div className="lbl">현재 모델<small>M3 엔진의 <code>/v1/models</code> 에서 자동 감지. 변경은 M3 의 <code>CPN_VERSION</code> 환경변수로.</small></div>
        <div className="ctrl">
          <span className="v" style={{fontFamily:'var(--font-mono)',fontSize:13,padding:'7px 10px',background:'var(--bg-surface)',border:'1px solid var(--border-1)',borderRadius:'var(--r-2)',color:'var(--fg-1)'}}>
            {liveModel || '— 엔진 응답 대기 중 —'}
          </span>
        </div>
      </div>
      <div className="ch-row">
        <div className="lbl">Temperature<small>0 = 항상 같은 단정한 답 / 2 = 매번 다른 창의적 답. 0.2가 안정·일관, 0.8이 사람 대화 톤.</small></div>
        <div className="ctrl">
          <input type="range" min="0" max="2" step="0.01" value={temp} onChange={e => set('default_temp', +e.target.value)} style={{flex:1, marginRight:12}}/>
          <span className="v" style={{fontFamily:'var(--font-mono)', minWidth:50, textAlign:'right'}}>{temp.toFixed(2)}</span>
        </div>
      </div>
      <div className="ch-row">
        <div className="lbl">Top-p<small>다음 단어 후보 누적 확률 cutoff. 0.95 = 상위 95% 확률 안에서만 선택 → tail 잘라 안전. 1.0이면 모든 후보.</small></div>
        <div className="ctrl">
          <input type="range" min="0" max="1" step="0.01" value={topP} onChange={e => set('default_top_p', +e.target.value)} style={{flex:1, marginRight:12}}/>
          <span className="v" style={{fontFamily:'var(--font-mono)', minWidth:50, textAlign:'right'}}>{topP.toFixed(2)}</span>
        </div>
      </div>
      <div className="ch-row">
        <div className="lbl">Max tokens<small>응답 최대 길이. 우리 V16 엔진은 byte-level (1 byte ≈ 1 token, 한글 1자 = 3 bytes). 512면 한글 약 170자.</small></div>
        <div className="ctrl">
          <input type="range" min="128" max="4096" step="128" value={maxTok} onChange={e => set('default_max_tokens', +e.target.value)} style={{flex:1, marginRight:12}}/>
          <span className="v" style={{fontFamily:'var(--font-mono)', minWidth:50, textAlign:'right'}}>{maxTok}</span>
        </div>
      </div>
      <div className="ch-row"><div className="lbl">스트리밍 응답<small>토큰 생성 즉시 한 글자씩 표시 (stream:true)</small></div><div className="ctrl"><div className="ch-switch on"></div></div></div>
    </div>
    <div className="ch-card">
      <h3>시스템 프롬프트</h3>
      <p className="desc">모든 새 대화 시작 시 모델에 먼저 들어가는 지시문. 비워두면 적용 안 됨.</p>
      <textarea
        value={localSys}
        onChange={e => setLocalSys(e.target.value)}
        onBlur={() => { if (localSys !== sysPrompt) set('system_prompt', localSys); }}
        placeholder="예: 당신은 친절한 한국어 비서입니다. 짧고 명확하게 답해주세요."
        style={{width:'100%',minHeight:80,background:'var(--bg-canvas)',border:'1px solid var(--border-1)',borderRadius:'var(--r-2)',padding:'10px 12px',color:'var(--fg-1)',fontFamily:'var(--font-mono)',fontSize:12.5,lineHeight:1.6,resize:'vertical',outline:'none'}}
      />
      <div style={{marginTop:6, fontSize:11, color:'var(--fg-4)'}}>
        ⓘ 우리 V16 인사봇은 system prompt를 무시하고 인사만 응답합니다. 외부 LLM 연동 시점부터 적용됩니다.
      </div>
    </div>
  </>;
}

function NotificationsPane() {
  return <>
    <div className="pane-eb">설정 · 알림</div>
    <h1>알림.</h1>
    <p className="lede">현재 서버에 알림 발송 기능이 없습니다. 별 sprint 예정 (이메일/웹훅/인앱).</p>
    <div className="ch-card">
      <div className="ch-row"><div className="lbl">응답 완료<small>준비 중</small></div><div className="ctrl"><div className="ch-switch on"></div></div></div>
      <div className="ch-row"><div className="lbl">응답 실패<small>준비 중</small></div><div className="ctrl"><div className="ch-switch on"></div></div></div>
      <div className="ch-row"><div className="lbl">할당량 80% 도달<small>준비 중</small></div><div className="ctrl"><div className="ch-switch on"></div></div></div>
      <div className="ch-row"><div className="lbl">주간 요약<small>매주 월요일 09:00 (Asia/Seoul)</small></div><div className="ctrl"><div className="ch-switch"></div></div></div>
      <div className="ch-row"><div className="lbl">제품 업데이트<small>새 모델, API 변경 사항</small></div><div className="ctrl"><div className="ch-switch on"></div></div></div>
    </div>
  </>;
}

function ShortcutsPane() {
  const M = window.MOD_KEY || 'Ctrl';
  const S = window.SHIFT_KEY || 'Shift';
  const ENT = window.ENTER_KEY || 'Enter';
  const list = [
    { l: '새 대화',           k: [M, 'N'] },
    { l: '스레드 검색',        k: [M, 'K'] },
    { l: '메시지 전송',        k: [ENT] },
    { l: '여러 줄 입력',       k: [S, ENT] },
    { l: '응답 재생성',        k: [M, S, 'R'] },
    { l: '설정 열기',          k: [M, ','] },
    { l: '모델 전환',          k: [M, S, 'M'] },
    { l: '플레이그라운드 토글', k: [M, '.'] },
  ];
  return <>
    <div className="pane-eb">설정 · 단축키</div>
    <h1>키보드 단축키.</h1>
    <p className="lede">키보드 우선 워크플로우용. 현재 OS({window.IS_MAC ? 'macOS' : 'Windows/Linux'}) 기준으로 표시됩니다.</p>
    <div className="ch-card">
      <div className="ch-kbd-list">
        {list.map((row, i) => <React.Fragment key={i}>
          <div className="l">{row.l}</div>
          <div className="r">{row.k.map((kk, j) => <kbd key={j}>{kk}</kbd>)}</div>
        </React.Fragment>)}
      </div>
    </div>
  </>;
}

function DataPane() {
  return <>
    <div className="pane-eb">설정 · 데이터 · 개인정보</div>
    <h1>데이터 · 개인정보.</h1>
    <p className="lede">현재 대화는 서버 sqlite 에 저장됩니다. 서버 비용 부담 줄이기 위해 곧 로컬 저장 전환을 검토 중입니다 (IndexedDB / file-system).</p>
    <div className="ch-card">
      <div className="ch-row"><div className="lbl">저장 위치<small>현재 서버 sqlite · 향후 로컬 전환 검토</small></div><div className="ctrl"><span className="v">서버</span></div></div>
      <div className="ch-row"><div className="lbl">대화 보관 기간<small>준비 중</small></div><div className="ctrl"><span className="v">무기한</span><button className="ghost" disabled>변경</button></div></div>
      <div className="ch-row"><div className="lbl">내 대화로 학습<small>준비 중 · 옵트인</small></div><div className="ctrl"><div className="ch-switch"></div></div></div>
      <div className="ch-row"><div className="lbl">익명 텔레메트리 공유<small>준비 중</small></div><div className="ctrl"><div className="ch-switch on"></div></div></div>
      <div className="ch-row"><div className="lbl">모든 데이터 내보내기<small>JSON 다운로드</small></div><div className="ctrl"><button className="ghost" onClick={() => window.__chOpenModal('export')}>요청</button></div></div>
      <div className="ch-row"><div className="lbl">모든 대화 삭제</div><div className="ctrl"><button className="danger" onClick={() => window.__chOpenModal('confirm-delete-convos')}>삭제</button></div></div>
    </div>
  </>;
}

window.SettingsShell = SettingsShell;
