/* ============================================================
   設定（管理者）— メンバー管理 / マスタ管理
   ※ 取得設定は 連携 > ReadyCrew の詳細に移動
   ============================================================ */

/* メンバー招待モーダル */
function InviteMemberModal({ onClose }) {
  const { addMember } = useStore();
  const [name, setName] = React.useState('');
  const [email, setEmail] = React.useState('');
  const [role, setRole] = React.useState('member');
  const [err, setErr] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const submit = async () => {
    if (busy || !name.trim() || !email.trim()) return;
    setErr(''); setBusy(true);
    try { const r = await addMember({ name, email, role }); onClose(); if (r && r.emailed === false) {} }
    catch (e) { setErr(e.message); }
    setBusy(false);
  };
  return (
    <Modal open onClose={onClose} title={t('settings.inviteMember')} subtitle={t('settings.inviteMemberSubtitle')} width={480}
      footer={<><Button variant="subtle" onClick={onClose}>{t('btn.cancel')}</Button>
        <Button variant="primary" icon="plus" onClick={submit} disabled={busy || !name.trim() || !email.trim()}>{busy ? t('settings.inviting') : t('settings.invite')}</Button></>}>
      <Field label={t('settings.memberName')} required><TextInput value={name} onChange={(e) => setName(e.target.value)} placeholder={t('settings.memberNamePlaceholder')} /></Field>
      <Field label={t('settings.email')} required><TextInput value={email} onChange={(e) => { setEmail(e.target.value); setErr(''); }} placeholder="yamada@alion.jp" /></Field>
      {err && <div style={{ fontSize: 12, color: '#dc2626', marginTop: -8, marginBottom: 12 }}>{err}</div>}
      <Field label={t('settings.role')}>
        <div style={{ display: 'flex', gap: 8 }}>
          {[['member', t('role.member')], ['manager', t('settings.roleManager')], ['admin', t('role.admin')]].map(([v, l]) => (
            <button key={v} onClick={() => setRole(v)} style={{ flex: 1, padding: '9px 0', borderRadius: 8, cursor: 'pointer', fontFamily: 'inherit', fontSize: 13, fontWeight: 600,
              border: '1px solid ' + (role === v ? '#4a5af0' : '#e2e5ea'), background: role === v ? '#eef0fe' : '#fff', color: role === v ? '#4a5af0' : '#7b828d' }}>{l}</button>
          ))}
        </div>
        <div style={{ fontSize: 11.5, color: '#9aa1ab', marginTop: 6, lineHeight: 1.6 }}>{t('settings.roleHint')}</div>
      </Field>
    </Modal>
  );
}

/* 「…」ドロップダウン（カードの overflow:hidden に切られないよう fixed 配置） */
function DotsMenu({ items }) {
  const [open, setOpen] = React.useState(false);
  const [pos, setPos] = React.useState({ top: 0, left: 0 });
  const ref = React.useRef(null);
  const btnRef = React.useRef(null);
  React.useEffect(() => {
    const h = (e) => { if (ref.current && !ref.current.contains(e.target) && btnRef.current && !btnRef.current.contains(e.target)) setOpen(false); };
    const close = (e) => { if (ref.current && e.target && ref.current.contains(e.target)) return; setOpen(false); };
    document.addEventListener('mousedown', h);
    window.addEventListener('scroll', close, true);
    return () => { document.removeEventListener('mousedown', h); window.removeEventListener('scroll', close, true); };
  }, []);
  const toggle = (e) => {
    const r = e.currentTarget.getBoundingClientRect();
    const est = items.length * 36 + 12; // 項目高さ×件数＋パディングでメニュー高を概算
    // 画面下部で下方向に開くと切れるので、下端がビューポート内に収まるよう上へクランプ（cases.jsx と同方式）
    const top = Math.max(8, Math.min(r.bottom + 6, window.innerHeight - est - 10));
    setPos({ top, left: Math.max(8, r.right - 200) });
    setOpen(o => !o);
  };
  return (
    <>
      <span ref={btnRef}><IconButton name="dots" size={18} onClick={toggle} /></span>
      {open && (
        <div ref={ref} style={{ position: 'fixed', top: pos.top, left: pos.left, zIndex: 300, width: 200, background: '#fff', borderRadius: 10,
          border: '1px solid #e6e8ec', boxShadow: '0 14px 34px rgba(20,22,40,.16)', padding: 6 }}>
          {items.map((it, i) => (
            <div key={i} className="row-hover" onClick={() => { if (!it.disabled) it.onClick(); setOpen(false); }}
              style={{ display: 'flex', alignItems: 'center', gap: 9, padding: '8px 10px', borderRadius: 7,
                cursor: it.disabled ? 'not-allowed' : 'pointer', fontSize: 13,
                color: it.disabled ? '#c4c9d0' : (it.danger ? '#dc2626' : '#3b414b') }}>
              <Icon name={it.icon} size={14} stroke={2} style={{ color: it.disabled ? '#c4c9d0' : (it.danger ? '#dc2626' : '#9aa1ab') }} />{it.label}
            </div>
          ))}
        </div>
      )}
    </>
  );
}

/* メンバー行の「…」メニュー */
function MemberMenu({ user, isSelf }) {
  const { setMemberRole, removeMember, showToast } = useStore();
  const [resetResult, setResetResult] = React.useState(null); // {password, emailed}
  const [copied, setCopied] = React.useState(false);
  const doReset = async () => {
    if (!window.confirm(t('settings.resetPwConfirm', { name: user.name }))) return;
    try { setResetResult(await API.resetMemberPassword(user.id)); }
    catch (e) { showToast(e.message, 'x'); }
  };
  return (
    <>
      <DotsMenu items={[
        ...ROLE_ORDER.filter(r => r !== user.role).map(r => ({ icon: 'user', label: t('settings.changeToRole', { role: ROLE_LABEL[r] }), onClick: () => setMemberRole(user.id, r) })),
        { icon: 'refresh', label: t('settings.resetPassword'), onClick: doReset },
        { icon: 'x', label: t('settings.removeMember'), danger: true, disabled: isSelf,
          onClick: () => { if (window.confirm(t('settings.removeMemberConfirm', { name: user.name }))) removeMember(user.id).catch(e => showToast(e.message, 'x')); } },
      ]} />
      {resetResult && (
        <Modal open onClose={() => setResetResult(null)} title={t('settings.tempPwIssued')} width={440}
          subtitle={resetResult.emailed ? t('settings.tempPwEmailed', { name: user.name }) : t('settings.tempPwShare', { name: user.name })}
          footer={<Button variant="primary" onClick={() => setResetResult(null)}>{t('btn.close')}</Button>}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '14px 16px', background: '#f8f9fb', borderRadius: 10 }}>
            <code style={{ flex: 1, fontSize: 18, fontWeight: 700, fontFamily: 'var(--mono)', color: '#1c1f26', letterSpacing: '.03em' }}>{resetResult.password}</code>
            <Button size="sm" variant="default" onClick={async () => { try { await navigator.clipboard.writeText(resetResult.password); setCopied(true); setTimeout(() => setCopied(false), 1500); } catch (_) {} }}>
              {copied ? t('settings.copied') : t('settings.copy')}
            </Button>
          </div>
          <div style={{ fontSize: 12, color: '#9aa1ab', marginTop: 10, lineHeight: 1.6 }}>
            {t('settings.tempPwInstruction')}
          </div>
        </Modal>
      )}
    </>
  );
}

/* ステータス追加・編集モーダル */
const STATUS_COLORS = ['#2563eb', '#d97706', '#ea580c', '#16a34a', '#0f766e', '#6b7280', '#db2777', '#7c3aed', '#0891b2', '#b45309'];
function StatusFormModal({ editKey, onClose }) {
  const { addStatus, updateStatus } = useStore();
  const D = window.APP_DATA;
  const editing = editKey ? D.STATUS[editKey] : null;
  const [label, setLabel] = React.useState(editing ? editing.label : '');
  const [color, setColor] = React.useState(editing ? editing.color : STATUS_COLORS[0]);
  const [closed, setClosed] = React.useState(editing ? !!editing.closed : false);
  const submit = () => {
    if (!label.trim()) return;
    if (editing) updateStatus(editKey, { label, color, closed });
    else addStatus({ label, color, closed });
    onClose();
  };
  return (
    <Modal open onClose={onClose} title={editing ? t('settings.editStatus') : t('settings.addStatus')} width={440}
      footer={<><Button variant="subtle" onClick={onClose}>{t('btn.cancel')}</Button>
        <Button variant="primary" icon="check" onClick={submit} disabled={!label.trim()}>{editing ? t('btn.update') : t('settings.addAction')}</Button></>}>
      <Field label={t('settings.displayName')} required><TextInput value={label} onChange={(e) => setLabel(e.target.value)} placeholder={t('settings.statusNamePlaceholder')} /></Field>
      <Field label={t('settings.color')}>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          {STATUS_COLORS.map(cl => (
            <button key={cl} onClick={() => setColor(cl)}
              style={{ width: 30, height: 30, borderRadius: 8, background: cl, cursor: 'pointer',
                border: color === cl ? '3px solid #1c1f26' : '3px solid transparent', boxShadow: color === cl ? '0 0 0 2px #fff inset' : 'none' }} />
          ))}
        </div>
      </Field>
      <Field label={t('settings.statusNoTodo')} hint={t('settings.statusNoTodoHint')}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <Toggle on={closed} onClick={() => setClosed(v => !v)} />
          <span style={{ fontSize: 13, color: closed ? '#b45309' : '#7b828d', fontWeight: 600 }}>{closed ? t('settings.statusNoTodoOn') : t('settings.statusNoTodoOff')}</span>
        </div>
      </Field>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 12px', background: '#f8f9fb', borderRadius: 9 }}>
        <span style={{ fontSize: 12, color: '#9aa1ab' }}>{t('settings.preview')}</span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, background: color + '1f', color, padding: '3px 10px', borderRadius: 999, fontSize: 12, fontWeight: 600 }}>
          <span style={{ width: 7, height: 7, borderRadius: '50%', background: color }} />{label || t('settings.displayName')}
        </span>
      </div>
    </Modal>
  );
}

/* ランク追加・編集モーダル（記号 A〜E…＋説明＋カラー） */
function RankFormModal({ editKey, onClose }) {
  const { addRank, updateRank } = useStore();
  const D = window.APP_DATA;
  const editing = editKey ? D.RANKS[editKey] : null;
  const [key, setKey] = React.useState(editing ? editing.key : '');
  const [desc, setDesc] = React.useState(editing ? editing.desc : '');
  const [color, setColor] = React.useState(editing ? editing.color : STATUS_COLORS[3]);
  const submit = () => {
    if (editing) updateRank(editKey, { desc, color });
    else { if (!key.trim()) return; addRank({ key, desc, color }); }
    onClose();
  };
  return (
    <Modal open onClose={onClose} title={editing ? t('settings.editRank', { key: editing.key }) : t('settings.addRank')} width={440}
      footer={<><Button variant="subtle" onClick={onClose}>{t('btn.cancel')}</Button>
        <Button variant="primary" icon="check" onClick={submit} disabled={!editing && !key.trim()}>{editing ? t('btn.update') : t('settings.addAction')}</Button></>}>
      {!editing && (
        <Field label={t('settings.symbol')} required hint={t('settings.symbolHint')}>
          <TextInput value={key} onChange={(e) => setKey(e.target.value.toUpperCase().slice(0, 2))} placeholder="F" style={{ width: 90 }} />
        </Field>
      )}
      <Field label={t('settings.description')}><TextInput value={desc} onChange={(e) => setDesc(e.target.value)} placeholder={t('settings.descPlaceholder')} /></Field>
      <Field label={t('settings.color')}>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          {STATUS_COLORS.map(cl => (
            <button key={cl} onClick={() => setColor(cl)}
              style={{ width: 30, height: 30, borderRadius: 8, background: cl, cursor: 'pointer',
                border: color === cl ? '3px solid #1c1f26' : '3px solid transparent', boxShadow: color === cl ? '0 0 0 2px #fff inset' : 'none' }} />
          ))}
        </div>
      </Field>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 12px', background: '#f8f9fb', borderRadius: 9 }}>
        <span style={{ fontSize: 12, color: '#9aa1ab' }}>{t('settings.preview')}</span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, background: color + '1f', color, borderRadius: 7, padding: '4px 9px', fontSize: 12.5, fontWeight: 700 }}>
          {(editing ? editing.key : key) || 'A'}
        </span>
        <span style={{ fontSize: 12, color: '#7b828d' }}>{desc || t('settings.description')}</span>
      </div>
    </Modal>
  );
}

/* 商談方法 追加モーダル */
function MethodFormModal({ onClose }) {
  const { addMethod } = useStore();
  const [label, setLabel] = React.useState('');
  const submit = () => { if (!label.trim()) return; addMethod(label); onClose(); };
  return (
    <Modal open onClose={onClose} title={t('settings.addMethod')} width={400}
      footer={<><Button variant="subtle" onClick={onClose}>{t('btn.cancel')}</Button>
        <Button variant="primary" icon="check" onClick={submit} disabled={!label.trim()}>{t('settings.addAction')}</Button></>}>
      <Field label={t('settings.displayName')} required>
        <TextInput value={label} onChange={(e) => setLabel(e.target.value)} placeholder={t('settings.methodPlaceholder')} onKeyDown={(e) => { if (enterSubmits(e)) submit(); }} />
      </Field>
    </Modal>
  );
}

/* 権限マトリクス（設定→権限）。ロール別の操作可否をチェックで編集→保存（masters に永続化） */
function PermissionsMatrix() {
  const { PERM_GROUPS, permissions, savePermissions, showToast } = useStore();
  const initial = () => {
    const m = {};
    PERM_GROUPS.forEach(g => g.items.forEach(([k, , d]) => {
      const saved = permissions[k];
      m[k] = saved ? { member: !ASM_WORKSPACES.MANAGER_ACTIONS.includes(k)&&!!saved.member, manager: !!saved.manager } : { member: d[0] === 1, manager: d[1] === 1 };
    }));
    return m;
  };
  const [m, setM] = React.useState(initial);
  const [dirty, setDirty] = React.useState(false);
  const toggle = (k, role) => { setDirty(true); setM(s => ({ ...s, [k]: { ...s[k], [role]: !s[k][role] } })); };
  const reset = () => { setM(initial()); setDirty(false); };
  const [saving,setSaving]=React.useState(false);
  const save = async () => {setSaving(true);try{await savePermissions(m);setDirty(false);showToast(t('settings.permissionsSaved'));}catch(e){showToast(e.message,'x');}finally{setSaving(false);}};
  const cell = { textAlign: 'center', padding: '9px 4px', borderTop: '1px solid #f0f1f4' };
  const th = { fontSize: 12, fontWeight: 700, color: '#9aa1ab', padding: '0 8px 8px' };
  const box = { width: 17, height: 17, cursor: 'pointer' };
  return (
    <Card title={t('settings.permissionsTitle')} pad={0} action={<div style={{ display: 'flex', gap: 8 }}>{dirty && <Button size="sm" variant="subtle" onClick={reset}>{t('settings.revert')}</Button>}<Button size="sm" variant="primary" icon="check" onClick={save} disabled={!dirty||saving}>{t('btn.save')}</Button></div>}>
      <div style={{ padding: '12px 18px 4px', fontSize: 12.5, color: '#7b828d', lineHeight: 1.7 }}>
        {t('settings.permissionsLead.0')}<b>{t('settings.permissionsLead.1')}</b>{t('settings.permissionsLead.2')}
      </div>
      <div style={{ overflowX: 'auto', padding: '4px 14px 14px' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13.5 }}>
          <thead><tr>
            <th style={{ ...th, textAlign: 'left' }}>{t('settings.colFeature')}</th>
            <th style={{ ...th, width: 92 }}>{t('role.member')}</th>
            <th style={{ ...th, width: 96 }}>{t('settings.roleManager')}</th>
            <th style={{ ...th, width: 80 }}>{t('role.admin')}</th>
          </tr></thead>
          <tbody>
            {PERM_GROUPS.map(g => (
              <React.Fragment key={g.group}>
                <tr><td colSpan={4} style={{ background: '#f6f7f9', padding: '6px 12px', fontSize: 12, fontWeight: 700, color: '#7b828d', borderRadius: 6 }}>{g.group}</td></tr>
                {g.items.map(([k, label]) => (
                  <tr key={k}>
                    <td style={{ padding: '8px 12px', borderTop: '1px solid #f0f1f4', color: '#2b2f38' }}>{label}</td>
                    <td style={cell}><input type="checkbox" aria-label={label+(" "+t("role.member")+"")} disabled={saving||ASM_WORKSPACES.MANAGER_ACTIONS.includes(k)} title={ASM_WORKSPACES.MANAGER_ACTIONS.includes(k)?t("settings.managerOnly"):undefined} checked={!!m[k].member} onChange={() => toggle(k, 'member')} style={box} /></td>
                    <td style={cell}><input type="checkbox" aria-label={label+(" "+t("settings.roleManager")+"")} disabled={saving} checked={!!m[k].manager} onChange={() => toggle(k, 'manager')} style={box} /></td>
                    <td style={cell}><input type="checkbox" checked disabled style={{ width: 17, height: 17 }} /></td>
                  </tr>
                ))}
              </React.Fragment>
            ))}
          </tbody>
        </table>
      </div>
    </Card>
  );
}

/* 案件カテゴリ候補の管理（設定→マスタ）。追加・削除は即保存→全員のフォーム・絞り込みに反映 */
function CategoryMasterCard() {
  const { saveCategoryMaster } = useStore();
  const D = window.APP_DATA;
  const [input, setInput] = React.useState('');
  const list = D.CATEGORIES || [];
  const add = () => { const v = input.trim(); if (!v || list.includes(v)) { setInput(''); return; } saveCategoryMaster([...list, v]); setInput(''); };
  const remove = (c) => { if (window.confirm(t('settings.deleteCategoryConfirm',{name:c}))) saveCategoryMaster(list.filter(x => x !== c)); };
  return (
    <Card title={t("settings.caseCategories")} pad={18}>
      <div style={{ fontSize: 12.5, color: '#7b828d', marginBottom: 12, lineHeight: 1.6 }}>{t("settings.categoryHint")}</div>
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 14 }}>
        {list.map(c => (
          <span key={c} style={{ display: 'inline-flex', alignItems: 'center', gap: 8, padding: '8px 13px', background: '#eef0fe', borderRadius: 8, fontSize: 13, fontWeight: 600, color: '#5048c8' }}>
            {c}
            <button onClick={() => remove(c)} style={{ border: 'none', background: 'transparent', padding: 0, cursor: 'pointer', display: 'inline-flex' }}>
              <Icon name="x" size={13} stroke={2} style={{ color: '#9089d6' }} />
            </button>
          </span>
        ))}
        {list.length === 0 && <span style={{ fontSize: 13, color: '#9aa1ab' }}>{t("settings.noCandidates")}</span>}
      </div>
      <div style={{ display: 'flex', gap: 8 }}>
        <input value={input} onChange={(e) => setInput(e.target.value)} onKeyDown={(e) => { if (enterSubmits(e)) { e.preventDefault(); add(); } }}
          placeholder={t("settings.addCategory")} style={{ ...inputStyle, flex: 1 }} />
        <Button variant="primary" icon="plus" onClick={add} disabled={!input.trim()}>{t("btn.add")}</Button>
      </div>
    </Card>
  );
}

/* AIモデル選択（設定→AI・管理者のみ）。OpenAIの利用可能モデルをサーバー経由で自動取得し、ドロップダウンで選択（手入力なし）。
   '' は機能ごとの既定を自動使用。新モデル（gpt-5.5系など）はOpenAIに追加され次第、一覧に自動で出てくる。サーバーは masters.config.aiModel を参照。 */
const AI_MODEL_FALLBACK = ['gpt-5', 'gpt-5-mini', 'gpt-5-nano']; // 取得失敗時の最低限の候補
function AiModelCard() {
  const { saveAiModel } = useStore();
  const D = window.APP_DATA;
  const cur = D.aiModel || '';
  const [models, setModels] = React.useState(null); // null=取得中 / 配列=取得済み
  const [err, setErr] = React.useState(false);
  React.useEffect(() => {
    let live = true;
    API.aiModels()
      .then(r => { if (live) { setModels((r && r.models && r.models.length) ? r.models : AI_MODEL_FALLBACK); if (r && r.error) setErr(true); } })
      .catch(() => { if (live) { setModels(AI_MODEL_FALLBACK); setErr(true); } });
    return () => { live = false; };
  }, []);
  const list = models || [];
  // 現在の保存値が一覧に無ければ先頭に補完して選択状態を保つ
  const opts = (!cur || list.includes(cur)) ? list : [cur, ...list];
  const onSelect = (v) => { if (v !== cur) saveAiModel(v); };
  const selectStyle = { ...inputStyle, appearance: 'none', WebkitAppearance: 'none', cursor: 'pointer', fontWeight: 600,
    backgroundImage: 'url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'12\' height=\'12\' viewBox=\'0 0 24 24\' fill=\'none\' stroke=\'%23b4bac3\' stroke-width=\'2.4\' stroke-linecap=\'round\' stroke-linejoin=\'round\'%3E%3Cpath d=\'m6 9 6 6 6-6\'/%3E%3C/svg%3E")',
    backgroundRepeat: 'no-repeat', backgroundPosition: 'right 12px center' };
  return (
    <Card title={t("settings.aiModelTitle")} pad={18}>
      <div style={{ fontSize: 12.5, color: '#7b828d', marginBottom: 14, lineHeight: 1.65 }}>{t("settings.aiModelHint")}</div>
      {models === null ? (
        <div style={{ fontSize: 13, color: '#9aa1ab', padding: '11px 13px', background: '#f6f7fa', borderRadius: 9 }}>{t("settings.loadingModels")}</div>
      ) : (
        <select value={cur} onChange={(e) => onSelect(e.target.value)} style={selectStyle}>
          <option value="">{t("settings.autoModel")}</option>
          {opts.map(m => <option key={m} value={m}>{m}</option>)}
        </select>
      )}
      <div style={{ fontSize: 12, color: '#5a616c', marginTop: 12 }}>{t("settings.currentModel")}<code style={{ fontFamily: 'var(--mono)', color: '#4a5af0', fontWeight: 700 }}>{cur || t("settings.auto")}</code></div>
      <div style={{ fontSize: 11.5, color: '#b4bac3', marginTop: 10, lineHeight: 1.55 }}>{t("settings.modelsHint")}{err && t("settings.modelsFallback")}
      </div>
    </Card>
  );
}

function Settings() {
  const { showToast, currentUser, route, navigate, can, canManageWorkspaces, usersV, mastersV, removeStatus, removeMethod, removeRank } = useStore();
  const D = window.APP_DATA;
  const [selectedTab, setTab] = React.useState(['members','permissions','masters','ai','workspaces'].includes(route.tab) ? route.tab : 'masters');
  React.useEffect(() => { if (['members','permissions','masters','ai','workspaces'].includes(route.tab)) setTab(route.tab); }, [route.tab]);
  const [invite, setInvite] = React.useState(false);
  const [statusModal, setStatusModal] = React.useState(null); // null | { editKey?: string }
  const [rankModal, setRankModal] = React.useState(null); // null | { editKey?: string }
  const [methodModal, setMethodModal] = React.useState(false);
  const tab=currentUser.role==='admin'?selectedTab:'workspaces';
  const tabs = [{ k: 'workspaces', label: t("ws.management"), icon: 'grid' }, { k: 'members', label: t('settings.tabMembers'), icon: 'customers' }, { k: 'permissions', label: t('settings.tabPermissions'), icon: 'check2' }, { k: 'masters', label: t('settings.tabMasters'), icon: 'grid' },
    ...(currentUser.role === 'admin' ? [{ k: 'ai', label: t('settings.tabAi'), icon: 'spark' }] : [])].filter(t=>currentUser.role==='admin'||t.k==='workspaces'&&canManageWorkspaces);

  return (
    <Page title={t('page.settings')}>
      <div className="asm-settings">
        {/* タブナビ */}
        <div className="asm-settings-tabs" role="tablist">
          {tabs.map(t => (
            <button key={t.k} role="tab" aria-selected={tab === t.k} onClick={() => {setTab(t.k);navigate('settings',null,t.k);}} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 12px', borderRadius: 9, border: 'none', cursor: 'pointer', fontFamily: 'inherit',
              fontSize: 13.5, fontWeight: tab === t.k ? 600 : 500, textAlign: 'left', color: tab === t.k ? '#1c1f26' : '#5b626d', background: tab === t.k ? '#fff' : 'transparent', boxShadow: tab === t.k ? '0 1px 2px rgba(20,22,40,.06), inset 0 0 0 1px #ebecef' : 'none' }}>
              <Icon name={t.icon} size={17} stroke={2} style={{ color: tab === t.k ? '#4a5af0' : '#a8aeb8' }} />{t.label}
            </button>
          ))}
        </div>

        <div style={{ flex: 1, minWidth: 0, width: '100%' }}>
          {tab === 'workspaces' && <WorkspaceSettings />}
          {tab === 'members' && (
            <Card title={t('settings.tabMembers')} pad={0} action={<Button size="sm" variant="primary" icon="plus" onClick={() => setInvite(true)}>{t('settings.inviteMember')}</Button>}>
              {D.users.map((u, i) => (
                <div key={u.id} style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '14px 18px', borderBottom: i === D.users.length - 1 ? 'none' : '1px solid #f4f5f7' }}>
                  <Avatar user={u} size={36} />
                  <div style={{ flex: 1 }}>
                    <div style={{ fontSize: 13.5, fontWeight: 600, color: '#1f2430' }}>{u.name}{u.id === currentUser.id && <span style={{ fontSize: 12, color: '#9aa1ab', marginLeft: 8 }}>{t('settings.you')}</span>}</div>
                    <div style={{ fontSize: 12, color: '#9aa1ab', fontFamily: 'var(--mono)' }}>{u.email}</div>
                    {(() => { /* 追加日＝createdAt（新規分）またはID 'u'+Date.now() のタイムスタンプ復元（既存分）。誰が追加したかは createdBy（2026-08-19以降の追加分のみ記録） */
                      const ts = u.createdAt || (/^u\d{13}$/.test(u.id) ? new Date(Number(u.id.slice(1))).toISOString().slice(0, 10) + ' ' + new Date(Number(u.id.slice(1))).toTimeString().slice(0, 5) : '');
                      const by = u.createdBy && (D.users.find(x => x.id === u.createdBy) || {}).name;
                      return ts ? <div style={{ fontSize: 11, color: '#b4bac3', marginTop: 1 }}>{t('settings.memberAddedAt')}: {String(ts).slice(0, 16).replace('T', ' ')}{by ? '（' + t('settings.memberAddedBy', { name: by }) + '）' : ''}</div> : null; })()}
                  </div>
                  <span style={{ fontSize: 12, fontWeight: 600, color: u.role === 'admin' ? '#4a5af0' : u.role === 'manager' ? '#0f766e' : '#7b828d', background: u.role === 'admin' ? '#eef0fe' : u.role === 'manager' ? '#dcf3f0' : '#f0f1f4', padding: '4px 11px', borderRadius: 6 }}>{ROLE_LABEL[u.role] || t('role.member')}</span>
                  <MemberMenu user={u} isSelf={u.id === currentUser.id} />
                </div>
              ))}
              {invite && <InviteMemberModal onClose={() => setInvite(false)} />}
            </Card>
          )}

          {tab === 'permissions' && <PermissionsMatrix />}

          {tab === 'ai' && currentUser.role === 'admin' && <AiModelCard />}

          {tab === 'masters' && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
              <Card title={t('settings.status')} pad={18} action={<Button size="sm" variant="subtle" icon="plus" onClick={() => setStatusModal({})}>{t('btn.add')}</Button>}>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                  {D.STATUS_ORDER.map(s => (
                    <div key={s} className="row-hover" style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '9px 11px', borderRadius: 8, border: '1px solid #f0f1f4' }}>
                      <span style={{ width: 12, height: 12, borderRadius: 4, background: D.STATUS[s].color }} />
                      <span style={{ fontSize: 13.5, fontWeight: 600, color: '#2b2f38', flex: 1 }}>{D.STATUS[s].label}</span>
                      {((D.STATUS[s].closed != null) ? D.STATUS[s].closed : ['won', 'lost', 'done'].includes(s)) && <span style={{ fontSize: 11, fontWeight: 700, color: '#b45309', background: '#fdf0db', padding: '1px 8px', borderRadius: 999 }}>{t('settings.statusNoTodoBadge')}</span>}
                      <code style={{ fontSize: 12, fontFamily: 'var(--mono)', color: '#a8aeb8' }}>{s}</code>
                      <DotsMenu items={[
                        { icon: 'edit', label: t('btn.edit'), onClick: () => setStatusModal({ editKey: s }) },
                        { icon: 'x', label: t('btn.delete'), danger: true,
                          onClick: () => { if (window.confirm(t('settings.deleteStatusConfirm', { label: D.STATUS[s].label }))) removeStatus(s); } },
                      ]} />
                    </div>
                  ))}
                </div>
              </Card>
              <Card title={t('settings.caseRank')} pad={18} action={<Button size="sm" variant="subtle" icon="plus" onClick={() => setRankModal({})}>{t('btn.add')}</Button>}>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                  {D.RANK_ORDER.map(rk => {
                    const r = D.RANKS[rk];
                    return (
                      <div key={rk} className="row-hover" style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '9px 11px', borderRadius: 8, border: '1px solid #f0f1f4' }}>
                        <span style={{ width: 26, height: 26, borderRadius: 7, background: r.soft, color: r.fg, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 13, fontWeight: 700 }}>{r.label}</span>
                        <span style={{ fontSize: 13.5, fontWeight: 600, color: '#2b2f38', flex: 1 }}>{r.desc || '—'}</span>
                        <DotsMenu items={[
                          { icon: 'edit', label: t('btn.edit'), onClick: () => setRankModal({ editKey: rk }) },
                          { icon: 'x', label: t('btn.delete'), danger: true,
                            onClick: () => { if (window.confirm(t('settings.deleteRankConfirm', { key: rk }))) removeRank(rk); } },
                        ]} />
                      </div>
                    );
                  })}
                </div>
              </Card>
              <Card title={t('settings.meetingMethod')} pad={18} action={<Button size="sm" variant="subtle" icon="plus" onClick={() => setMethodModal(true)}>{t('btn.add')}</Button>}>
                <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                  {Object.values(D.METHODS).map(m => (
                    <span key={m.key} style={{ display: 'inline-flex', alignItems: 'center', gap: 8, padding: '8px 13px', background: '#f4f5f7', borderRadius: 8, fontSize: 13, fontWeight: 600, color: '#3b414b' }}>
                      {m.label}
                      <button onClick={() => { if (window.confirm(t('settings.deleteMethodConfirm', { label: m.label }))) removeMethod(m.key); }}
                        style={{ border: 'none', background: 'transparent', padding: 0, cursor: 'pointer', display: 'inline-flex' }}>
                        <Icon name="x" size={13} stroke={2} style={{ color: '#b4bac3' }} />
                      </button>
                    </span>
                  ))}
                </div>
              </Card>
              <CategoryMasterCard />
              {statusModal && <StatusFormModal editKey={statusModal.editKey} onClose={() => setStatusModal(null)} />}
              {rankModal && <RankFormModal editKey={rankModal.editKey} onClose={() => setRankModal(null)} />}
              {methodModal && <MethodFormModal onClose={() => setMethodModal(false)} />}
            </div>
          )}
        </div>
      </div>
    </Page>
  );
}
Object.assign(window, { Settings });
