// Settings views — Product catalog admin, Order status workflow, User setting

const SETTINGS_ITEMS = [
  { id: 'settings_catalog',  label: 'Product catalog',     th: 'จัดการสินค้าและแพ็กเกจ',       icon: 'package' },
  { id: 'settings_status',   label: 'Order status',        th: 'สถานะคำสั่งซื้อ',               icon: 'pipeline' },
  { id: 'settings_workflow', label: 'Workflow setting',    th: 'ลำดับการอนุมัติฟบริการ',         icon: 'sparkles' },
  { id: 'settings_docs',     label: 'Document setting',   th: 'เอกสารที่ต้องใช้ตอนสมัคร',       icon: 'file' },
  { id: 'settings_reasons',   label: 'Reasons & Quick fill', th: 'เหตุผลและข้อความสำเร็จรูป',    icon: 'list' },
  { id: 'settings_provision', label: 'Provision setting',   th: 'ขั้นตอน Provisioning',          icon: 'arrowRight' },
  { id: 'settings_user',      label: 'User setting',        th: 'ผู้ใช้และทีม',                  icon: 'users' },
];

const SettingsLayout = ({ current, setView, children }) => {
  const currentItem = SETTINGS_ITEMS.find(s => s.id === current);
  const { perms = {} } = React.useContext(window.PermCtx);
  const canAdminSetting = perms['Admin Setting'] === true;
  const canManageUsers  = perms['Manage users']  === true;
  // Admin Setting → access to all pages
  // Manage users only → access only to settings_user
  // Others → locked
  const locked =
    (current === 'settings_user'  && !canAdminSetting && !canManageUsers) ||
    (current !== 'settings_user'  && !canAdminSetting);

  return (
    <>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11.5, color: 'var(--ink-3)', marginBottom: 10 }}>
        <Icon name="cog" size={11}/>
        <span>Settings</span>
        <Icon name="chevron" size={9}/>
        <span style={{ color: 'var(--ink-2)' }}>{currentItem?.label}</span>
      </div>
      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', marginBottom: 20, gap: 16 }}>
        <div>
          <h1 style={{ fontSize: 22, fontWeight: 500, letterSpacing: '-0.01em', margin: '0 0 4px' }}>{currentItem?.label}</h1>
          <div style={{ fontSize: 12, color: 'var(--ink-3)' }}>{currentItem?.th}</div>
        </div>
        {locked && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '5px 10px', background: 'var(--negative-bg)', border: '1px solid var(--negative)', borderRadius: 3, fontSize: 11.5, color: 'var(--negative)' }}>
            <Icon name="lock" size={12}/>
            ไม่มีสิทธิ์จัดการหน้านี้
          </div>
        )}
      </div>
      {locked ? (
        <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4, padding: '80px 40px', textAlign: 'center' }}>
          <div style={{ fontSize: 36, marginBottom: 14 }}>🔒</div>
          <h3 style={{ fontSize: 16, fontWeight: 600, margin: '0 0 8px' }}>Access Denied</h3>
          <div style={{ fontSize: 13, color: 'var(--ink-3)', maxWidth: 360, margin: '0 auto' }}>
            Role ของคุณไม่มีสิทธิ์จัดการ <strong>{currentItem?.label}</strong>
            <br/>ติดต่อ System Admin เพื่อขอสิทธิ์เพิ่มเติม
          </div>
        </div>
      ) : children}
    </>
  );
};

// ---------- Product catalog admin ----------
const CATALOG_PRESET_COLORS = ['#3a6b8a','#2d3a8c','#d97b2e','#1f7a4d','#6b4a8a','#b8492f','#8b8f99','#1a6b4a'];
const CATALOG_CATEGORIES = ['Unified Communications','Customer Experience','Voice','Productivity','Security','Infrastructure'];
const CATALOG_UNITS = ['user','agent','number','license'];

const PRODUCT_STATUS_CONFIG = {
  live:    { label: 'Live',    bg: 'var(--positive-bg)', fg: 'var(--positive)' },
  suspend: { label: 'Suspend', bg: '#fef3e8',            fg: '#d97b2e'         },
  deleted: { label: 'Deleted', bg: 'var(--bg-3)',        fg: 'var(--ink-3)'    },
};

const CATEGORY_STATUS_CONFIG = {
  live:    { label: 'Live',    bg: 'var(--positive-bg)', fg: 'var(--positive)' },
  deleted: { label: 'Deleted', bg: 'var(--bg-3)',        fg: 'var(--ink-3)'    },
};

const ORDER_STATUS_STATUS_CONFIG = {
  live:     { label: 'Live',     bg: 'var(--positive-bg)', fg: 'var(--positive)' },
  disabled: { label: 'Disabled', bg: 'var(--bg-3)',        fg: 'var(--ink-3)'    },
};

const SettingsCatalogView = () => {
  const [products, setProducts] = useState([...PRODUCTS]);
  const [editing, setEditing] = useState(null); // null | '__new__' | productObj
  const [catTab, setCatTab] = useState('products'); // 'products' | 'categories'
  const dragSrc = React.useRef(null);
  const [dragOver, setDragOver] = useState(null); // product id being dragged over

  const refreshProducts = async () => {
    try {
      const r = await window.apiFetch('/api/products');
      if (r.ok) { const d = await r.json(); setProducts(d); window.PRODUCTS = d; }
    } catch {}
  };

  useEffect(() => { refreshProducts(); }, []);

  const handleDragStart = (e, productId) => {
    dragSrc.current = productId;
    e.dataTransfer.effectAllowed = 'move';
  };

  const handleDragOver = (e, productId) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
    if (productId !== dragSrc.current) setDragOver(productId);
  };

  const handleDrop = async (e, targetId) => {
    e.preventDefault();
    setDragOver(null);
    const srcId = dragSrc.current;
    if (!srcId || srcId === targetId) return;
    const reordered = [...products];
    const srcIdx = reordered.findIndex(p => p.id === srcId);
    const tgtIdx = reordered.findIndex(p => p.id === targetId);
    const [moved] = reordered.splice(srcIdx, 1);
    reordered.splice(tgtIdx, 0, moved);
    setProducts(reordered);
    window.PRODUCTS = reordered;
    try {
      await window.apiFetch('/api/products/reorder', {
        method: 'PATCH',
        body: JSON.stringify(reordered.map((p, i) => ({ id: p.id, sortOrder: i }))),
      });
      showToast('บันทึกลำดับ product แล้ว', { variant: 'success' });
    } catch { showToast('เกิดข้อผิดพลาดในการบันทึกลำดับ', { variant: 'error' }); }
  };

  const handleDragEnd = () => { dragSrc.current = null; setDragOver(null); };

  const updateProductStatus = (productId, newStatus) => {
    setProducts(ps => ps.map(p => p.id === productId ? { ...p, status: newStatus } : p));
    window.PRODUCTS = (window.PRODUCTS || []).map(p => p.id === productId ? { ...p, status: newStatus } : p);
  };

  return (
    <>
      {/* Tab bar */}
      <div style={{ display: 'flex', gap: 2, borderBottom: '2px solid var(--line)', marginBottom: 16 }}>
        {[{ id: 'products', label: 'Products', icon: 'package' }, { id: 'categories', label: 'Categories', icon: 'grid' }].map(tab => (
          <button key={tab.id} onClick={() => setCatTab(tab.id)} style={{
            background: 'none', border: 'none', cursor: 'pointer', fontFamily: 'inherit',
            padding: '8px 16px', fontSize: 13, fontWeight: catTab === tab.id ? 600 : 400,
            color: catTab === tab.id ? 'var(--brand)' : 'var(--ink-3)',
            borderBottom: catTab === tab.id ? '2px solid var(--brand)' : '2px solid transparent',
            marginBottom: -2, display: 'flex', alignItems: 'center', gap: 6,
          }}>
            <Icon name={tab.icon} size={13}/>
            {tab.label}
          </button>
        ))}
      </div>

      {/* ── Categories tab ── */}
      {catTab === 'categories' && <SettingsCategoriesView/>}

      {/* ── Products tab ── */}
      {catTab === 'products' && <>
      <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div>
            <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Product catalog</h3>
            <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>
              <span className="num">{products.length}</span> products · <span className="num">{products.reduce((s, p) => s + p.packages.length, 0)}</span> packages · จัดการราคาและ SLA ของบริการ Solutions
            </div>
          </div>
          <div style={{ display: 'flex', gap: 8 }}>
            <Button variant="ghost" icon="download">Export</Button>
            <Button variant="primary" icon="plus" onClick={() => setEditing('__new__')}>Add product</Button>
          </div>
        </div>

        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
          <thead>
            <tr style={{ background: 'var(--bg-2)' }}>
              <th style={{ padding: '10px', width: 28, borderBottom: '1px solid var(--line)' }}/>
              {[['Product','left'],['Category','left'],['Packages','left'],['SLA','right'],['Price range','right'],['Status','left'],['','right']].map(([l,a],i) => (
                <th key={i} className="eyebrow" style={{ padding: '10px', textAlign: a, fontWeight: 500, borderBottom: '1px solid var(--line)' }}>{l}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {products.map((p, i) => {
              const pp = p.packages.map(pk => pk.price);
              const min = pp.length ? Math.min(...pp) : 0;
              const max = pp.length ? Math.max(...pp) : 0;
              const isDeleted = p.status === 'deleted';
              const isDragTarget = dragOver === p.id;
              return (
                <tr key={p.id}
                  draggable
                  onDragStart={e => handleDragStart(e, p.id)}
                  onDragOver={e => handleDragOver(e, p.id)}
                  onDrop={e => handleDrop(e, p.id)}
                  onDragEnd={handleDragEnd}
                  style={{
                    borderBottom: i === products.length - 1 ? 'none' : '1px solid var(--line-2)',
                    background: isDragTarget ? 'var(--bg-3)' : isDeleted ? 'var(--bg-2)' : 'transparent',
                    outline: isDragTarget ? '2px solid var(--brand)' : 'none',
                    outlineOffset: -2,
                    transition: 'background 80ms',
                  }}>
                  <td style={{ padding: '12px 6px 12px 10px', width: 28, cursor: 'grab' }}>
                    <svg width="12" height="16" viewBox="0 0 12 16" fill="none" style={{ display: 'block', color: 'var(--ink-4)', opacity: 0.5 }}>
                      <circle cx="3" cy="3" r="1.5" fill="currentColor"/>
                      <circle cx="9" cy="3" r="1.5" fill="currentColor"/>
                      <circle cx="3" cy="8" r="1.5" fill="currentColor"/>
                      <circle cx="9" cy="8" r="1.5" fill="currentColor"/>
                      <circle cx="3" cy="13" r="1.5" fill="currentColor"/>
                      <circle cx="9" cy="13" r="1.5" fill="currentColor"/>
                    </svg>
                  </td>
                  <td style={{ padding: '12px 10px' }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 10, opacity: isDeleted ? 0.45 : 1 }}>
                      <ProductGlyph productId={p.id} size={30}/>
                      <div>
                        <div style={{ fontWeight: 500, textDecoration: isDeleted ? 'line-through' : 'none', color: isDeleted ? 'var(--ink-3)' : 'inherit' }}>{p.name}</div>
                        <div style={{ fontSize: 11, color: 'var(--ink-4)' }}>{p.nameTh}</div>
                      </div>
                    </div>
                  </td>
                  <td style={{ padding: '12px 10px', color: isDeleted ? 'var(--ink-4)' : 'var(--ink-2)' }}>{p.category}</td>
                  <td style={{ padding: '12px 10px', opacity: isDeleted ? 0.4 : 1 }}>
                    <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap' }}>
                      {p.packages.map(pk => (
                        <span key={pk.id} style={{ padding: '2px 7px', background: 'var(--bg-2)', borderRadius: 2, fontSize: 11, color: 'var(--ink-2)' }}>{pk.name}</span>
                      ))}
                    </div>
                  </td>
                  <td className="num" style={{ padding: '12px 10px', textAlign: 'right', fontWeight: 500, color: isDeleted ? 'var(--ink-4)' : 'inherit' }}>
                    {p.slaDays}<span style={{ fontSize: 10, color: 'var(--ink-4)', marginLeft: 3, fontWeight: 400 }}>d</span>
                  </td>
                  <td className="num" style={{ padding: '12px 10px', textAlign: 'right', color: isDeleted ? 'var(--ink-4)' : 'inherit' }}>
                    {pp.length === 0 ? '—' : pp.length === 1 ? `฿${min.toLocaleString()}` : `฿${min.toLocaleString()} – ฿${max.toLocaleString()}`}
                    <span style={{ fontSize: 10, color: 'var(--ink-4)', marginLeft: 3 }}>/mo</span>
                  </td>
                  <td style={{ padding: '12px 10px' }}>
                    <ProductStatusSelect status={p.status || 'live'}/>
                  </td>
                  <td style={{ padding: '12px 10px', textAlign: 'right' }}>
                    <div style={{ display: 'flex', gap: 6, justifyContent: 'flex-end' }}>
                      <button onClick={() => !isDeleted && setEditing(p)} disabled={isDeleted} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '4px 10px', background: 'none', border: '1px solid var(--line)', borderRadius: 3, color: 'var(--ink-4)', cursor: isDeleted ? 'not-allowed' : 'pointer', fontSize: 11.5, fontFamily: 'Kanit, sans-serif', opacity: isDeleted ? 0.4 : 1 }}>
                        <Icon name="edit" size={11}/>Edit
                      </button>
                      {isDeleted ? (
                        <button onClick={async () => {
                          try {
                            const r = await window.apiFetch(`/api/products/${p.id}/status`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: 'suspend' }) });
                            if (r.ok) { updateProductStatus(p.id, 'suspend'); showToast('เปิดใช้งานอีกครั้ง → Suspend', { variant: 'success' }); }
                          } catch {}
                        }} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '4px 10px', background: 'none', border: '1px solid var(--positive)', borderRadius: 3, color: 'var(--positive)', cursor: 'pointer', fontSize: 11.5, fontFamily: 'Kanit, sans-serif' }}>
                          <Icon name="check" size={11}/>Enable
                        </button>
                      ) : (
                        <button onClick={async () => {
                          try {
                            const r = await window.apiFetch(`/api/products/${p.id}/status`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: 'deleted' }) });
                            if (r.ok) { updateProductStatus(p.id, 'deleted'); showToast(`ลบ "${p.name}" แล้ว`, { variant: 'success' }); }
                            else { const e = await r.json(); showToast(e.error || 'ลบไม่ได้', { variant: 'error' }); }
                          } catch (e) { showToast('เกิดข้อผิดพลาด', { variant: 'error' }); }
                        }} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '4px 10px', background: 'none', border: '1px solid var(--line)', borderRadius: 3, color: 'var(--negative)', cursor: 'pointer', fontSize: 11.5, fontFamily: 'Kanit, sans-serif' }}>
                          <Icon name="close" size={11}/>Delete
                        </button>
                      )}
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {editing !== null && (
        <ProductCatalogModal
          product={editing === '__new__' ? null : editing}
          onClose={() => setEditing(null)}
          onSaved={async () => { await refreshProducts(); setEditing(null); }}
        />
      )}
      </>}

    </>
  );
};

// ─── Product create / edit modal ─────────────────────────────────────────────
const ProductCatalogModal = ({ product, onClose, onSaved }) => {
  const isNew = !product;
  const [form, setForm] = useState({
    id:       product?.id       || '',
    name:     product?.name     || '',
    nameTh:   product?.nameTh   || '',
    category: product?.category || '',
    color:    product?.color    || '#3a6b8a',
    icon:     product?.icon     || 'box',
    slaDays:  product?.slaDays  ?? 1,
    unit:     product?.unit     || 'user',
    status:   product?.status   || 'live',
  });
  const [packages, setPackages] = useState(
    (product?.packages || []).map(pk => ({ ...pk, billingPeriod: pk.billingPeriod || 'monthly', highlightsText: (pk.highlights || []).join('\n') }))
  );
  const [saving, setSaving] = useState(false);
  const [err, setErr] = useState(null);
  const [liveCategories, setLiveCategories] = useState(
    (PRODUCT_CATEGORIES || []).filter(c => c.status !== 'deleted').sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
  );

  useEffect(() => {
    window.apiFetch('/api/categories')
      .then(r => r.ok ? r.json() : null)
      .then(d => {
        if (d) {
          window.PRODUCT_CATEGORIES = d;
          setLiveCategories(d.filter(c => c.status !== 'deleted').sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0)));
        }
      })
      .catch(() => {});
  }, []);

  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const addPkg = () => setPackages(ps => [...ps, { id: `${form.id || 'pkg'}_${Date.now()}`, name: '', seats: 1, price: '', billingPeriod: 'monthly', highlightsText: '' }]);
  const removePkg = (i) => setPackages(ps => ps.filter((_, j) => j !== i));
  const setPkg = (i, k, v) => setPackages(ps => ps.map((p, j) => j === i ? { ...p, [k]: v } : p));

  const handleSave = async () => {
    if (!form.name) { setErr('กรุณากรอกชื่อ product'); return; }
    if (isNew && !form.id) { setErr('กรุณากรอก Product ID'); return; }
    setSaving(true); setErr(null);
    try {
      const payload = {
        ...form,
        icon: form.icon || 'box',
        slaDays: parseInt(form.slaDays) || 1,
        packages: packages.map((pk, i) => ({
          id: pk.id || `${form.id}_pkg${i + 1}`,
          name: pk.name,
          seats: parseInt(pk.seats) || 1,
          price: parseFloat(pk.price) || 0,
          billingPeriod: pk.billingPeriod || 'monthly',
          highlights: pk.highlightsText.split('\n').map(h => h.trim()).filter(Boolean),
        })),
      };
      const res = await window.apiFetch(isNew ? '/api/products' : `/api/products/${product.id}`, {
        method: isNew ? 'POST' : 'PUT',
        body: JSON.stringify(payload),
      });
      if (res.ok) {
        showToast(isNew ? 'เพิ่ม product แล้ว' : 'บันทึกการแก้ไขแล้ว', { variant: 'success' });
        onSaved();
      } else {
        const e = await res.json();
        setErr(e.error || 'เกิดข้อผิดพลาด');
      }
    } catch (e) {
      setErr('Network error: ' + e.message);
    } finally {
      setSaving(false);
    }
  };

  return (
    <Modal open={true}
      title={isNew ? 'Add product' : `Edit · ${product.name}`}
      subtitle={isNew ? 'สร้าง product ใหม่ในแค็ตตาล็อก' : 'แก้ไขข้อมูล product และ packages'}
      onClose={onClose} width={700}
      footer={<>
        <Button variant="ghost" onClick={onClose}>Cancel</Button>
        <Button variant="primary" icon="check" disabled={saving} onClick={handleSave}>
          {saving ? 'กำลังบันทึก…' : isNew ? 'Add product' : 'Save changes'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>

        {err && <div style={{ padding: '10px 14px', background: 'var(--negative-bg)', borderRadius: 3, fontSize: 12, color: 'var(--negative)' }}>{err}</div>}

        {/* Product info */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          {isNew && (
            <Field label="Product ID" required hint="ตัวพิมพ์เล็ก a–z 0–9 _ เท่านั้น" style={{ gridColumn: '1 / -1' }}>
              <TextInput value={form.id} onChange={e => set('id', e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, '_'))} placeholder="my_product" style={{ fontFamily: 'IBM Plex Mono' }}/>
            </Field>
          )}
          <Field label="ชื่อ Product (EN)" required>
            <TextInput value={form.name} onChange={e => set('name', e.target.value)} placeholder="Cloud PBX"/>
          </Field>
          <Field label="ชื่อ Product (TH)">
            <TextInput value={form.nameTh} onChange={e => set('nameTh', e.target.value)} placeholder="ระบบโทรศัพท์บนคลาวด์"/>
          </Field>
          <Field label="Category">
            <Select value={form.category} onChange={e => set('category', e.target.value)}>
              <option value="">— เลือก —</option>
              {liveCategories.map(c => <option key={c.id} value={c.name}>{c.name}</option>)}
            </Select>
          </Field>
          <Field label="Unit">
            <Select value={form.unit} onChange={e => set('unit', e.target.value)}>
              {CATALOG_UNITS.map(u => <option key={u} value={u}>{u}</option>)}
            </Select>
          </Field>
          <Field label="SLA (วัน)" required>
            <TextInput type="number" value={form.slaDays} onChange={e => set('slaDays', e.target.value)} min={1}/>
          </Field>
          <Field label="Status">
            <Select value={form.status} onChange={e => set('status', e.target.value)}>
              {Object.entries(PRODUCT_STATUS_CONFIG).filter(([k]) => k !== 'deleted').map(([k, v]) => (
                <option key={k} value={k}>{v.label}</option>
              ))}
            </Select>
          </Field>
          <Field label="สี Product">
            <div style={{ display: 'flex', gap: 6, alignItems: 'center', flexWrap: 'wrap' }}>
              {CATALOG_PRESET_COLORS.map(c => (
                <button key={c} onClick={() => set('color', c)} style={{ width: 22, height: 22, borderRadius: '50%', background: c, border: `3px solid ${form.color === c ? 'var(--ink)' : 'transparent'}`, cursor: 'pointer', padding: 0, flexShrink: 0 }}/>
              ))}
              <TextInput value={form.color} onChange={e => set('color', e.target.value)} style={{ width: 86, fontFamily: 'IBM Plex Mono', fontSize: 11 }}/>
            </div>
          </Field>

          {/* Icon picker — spans both columns */}
          <div style={{ gridColumn: '1 / -1' }}>
            <div style={{ fontSize: 11.5, fontWeight: 500, color: 'var(--ink-2)', marginBottom: 7 }}>Icon</div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
              {Object.entries(window.PRODUCT_ICONS || {}).map(([key, def]) => {
                const selected = form.icon === key;
                return (
                  <button
                    key={key}
                    type="button"
                    onClick={() => set('icon', key)}
                    title={def.label}
                    style={{
                      display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 4,
                      padding: '8px 4px 6px', borderRadius: 5, cursor: 'pointer', width: 58,
                      background: selected ? form.color + '1a' : 'var(--bg-2)',
                      border: `1.5px solid ${selected ? form.color : 'var(--line)'}`,
                      color: selected ? form.color : 'var(--ink-3)',
                    }}
                  >
                    <svg width={18} height={18} viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                      {def.path}
                    </svg>
                    <span style={{ fontSize: 8.5, lineHeight: 1.2, textAlign: 'center', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 50 }}>{def.label}</span>
                  </button>
                );
              })}
            </div>
          </div>
        </div>

        {/* Packages */}
        <div style={{ borderTop: '1px solid var(--line-2)', paddingTop: 16 }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
            <div>
              <div style={{ fontSize: 13, fontWeight: 600 }}>Packages</div>
              <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 2 }}>กำหนด tier ราคาของ product นี้ · <span className="num">{packages.length}</span> packages</div>
            </div>
            <Button variant="ghost" size="sm" icon="plus" onClick={addPkg}>Add package</Button>
          </div>

          {packages.length === 0
            ? <div style={{ padding: '20px 0', textAlign: 'center', color: 'var(--ink-4)', fontSize: 12 }}>ยังไม่มี packages — กด Add package เพื่อเพิ่ม</div>
            : <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                {packages.map((pk, i) => (
                  <div key={i} style={{ background: 'var(--bg-2)', borderRadius: 4, padding: '12px 14px', border: '1px solid var(--line-2)' }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
                      <div className="eyebrow" style={{ fontSize: 9.5, color: form.color }}>{form.name || 'Product'} · Package {i + 1}</div>
                      <button onClick={() => removePkg(i)} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '3px 8px', background: 'none', border: '1px solid var(--line)', borderRadius: 3, color: 'var(--negative)', cursor: 'pointer', fontSize: 11, fontFamily: 'Kanit, sans-serif' }}>
                        <Icon name="close" size={10}/>Remove
                      </button>
                    </div>
                    <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr 1fr auto', gap: 10, alignItems: 'end' }}>
                      <Field label="Package name" required>
                        <TextInput value={pk.name} onChange={e => setPkg(i, 'name', e.target.value)} placeholder="Starter"/>
                      </Field>
                      <Field label="Min seats">
                        <TextInput type="number" value={pk.seats} onChange={e => setPkg(i, 'seats', e.target.value)} min={1}/>
                      </Field>
                      <Field label={`ราคา ฿/${form.unit || 'unit'}/${pk.billingPeriod === 'yearly' ? 'yr' : 'mo'}`}>
                        <TextInput type="number" value={pk.price} onChange={e => setPkg(i, 'price', e.target.value)} min={0}/>
                      </Field>
                      <Field label="รอบเรียกเก็บ">
                        <div style={{ display: 'flex', borderRadius: 3, border: '1px solid var(--line)', overflow: 'hidden', height: 34 }}>
                          {[['monthly','รายเดือน'],['yearly','รายปี']].map(([val, label]) => (
                            <button key={val} type="button" onClick={() => setPkg(i, 'billingPeriod', val)} style={{
                              flex: 1, border: 'none', cursor: 'pointer', fontFamily: 'Kanit, sans-serif',
                              fontSize: 11.5, fontWeight: pk.billingPeriod === val ? 600 : 400,
                              background: pk.billingPeriod === val ? 'var(--ink)' : 'var(--panel)',
                              color: pk.billingPeriod === val ? '#fff' : 'var(--ink-3)',
                              padding: '0 10px', whiteSpace: 'nowrap',
                            }}>{label}</button>
                          ))}
                        </div>
                      </Field>
                    </div>
                    <div style={{ marginTop: 10 }}>
                      <Field label="Highlights (1 บรรทัด = 1 feature)">
                        <Textarea value={pk.highlightsText} onChange={e => setPkg(i, 'highlightsText', e.target.value)} style={{ resize: 'vertical', minHeight: 64 }} placeholder={'IVR, Call routing\nMobile + desktop softphone\n99.9% SLA'}/>
                      </Field>
                    </div>
                  </div>
                ))}
              </div>
          }
        </div>
      </div>
    </Modal>
  );
};

// ─── Delete product confirmation modal ───────────────────────────────────────
const DeleteCatalogModal = ({ product, onClose, onDeleted }) => {
  const [loading, setLoading] = useState(false);

  const handleDelete = async () => {
    setLoading(true);
    try {
      const res = await window.apiFetch(`/api/products/${product.id}`, { method: 'DELETE' });
      if (res.ok) {
        showToast(`ลบ "${product.name}" แล้ว`, { variant: 'success' });
        onDeleted();
      } else {
        const e = await res.json();
        showToast(e.error || 'ลบไม่ได้', { variant: 'error' });
        onClose();
      }
    } catch {
      showToast('เกิดข้อผิดพลาด', { variant: 'error' });
      onClose();
    } finally {
      setLoading(false);
    }
  };

  return (
    <Modal open={true}
      title="ยืนยันการลบ product"
      subtitle={product.name}
      onClose={onClose} width={440}
      footer={<>
        <Button variant="ghost" onClick={onClose} disabled={loading}>Cancel</Button>
        <Button variant="primary" style={{ background: 'var(--negative)', borderColor: 'var(--negative)' }} disabled={loading} onClick={handleDelete}>
          {loading ? 'กำลังลบ…' : 'ยืนยันลบ'}
        </Button>
      </>}>
      <div style={{ fontSize: 13, color: 'var(--ink-2)', lineHeight: 1.7 }}>
        <p style={{ margin: '0 0 12px' }}>คุณแน่ใจหรือไม่ที่จะลบ <strong style={{ color: 'var(--ink)' }}>{product.name}</strong>?</p>
        <div style={{ padding: '10px 14px', background: 'var(--bg-2)', borderRadius: 4, fontSize: 12, display: 'flex', flexDirection: 'column', gap: 4 }}>
          <span>· <span className="num">{product.packages?.length || 0}</span> packages จะถูกลบด้วย</span>
          <span>· Approval workflow ของ product นี้จะถูกลบ</span>
          <span>· Order ที่มีอยู่แล้วจะไม่ได้รับผลกระทบ</span>
        </div>
      </div>
    </Modal>
  );
};

// ---------- Product category admin ----------
const SettingsCategoriesView = () => {
  const [categories, setCategories] = useState(PRODUCT_CATEGORIES || []);
  const [editing, setEditing] = useState(null);
  const [dragIdx, setDragIdx] = useState(null);
  const [dragOver, setDragOver] = useState(null);

  const refresh = async () => {
    try {
      const r = await window.apiFetch('/api/categories');
      if (r.ok) { const d = await r.json(); setCategories(d); window.PRODUCT_CATEGORIES = d; }
    } catch {}
  };

  useEffect(() => { refresh(); }, []);

  const updateCategoryStatus = (catId, newStatus) => {
    setCategories(cs => cs.map(c => c.id === catId ? { ...c, status: newStatus } : c));
    window.PRODUCT_CATEGORIES = (window.PRODUCT_CATEGORIES || []).map(c => c.id === catId ? { ...c, status: newStatus } : c);
  };

  const handleDragStart = (e, idx) => {
    setDragIdx(idx);
    e.dataTransfer.effectAllowed = 'move';
  };
  const handleDragOver = (e, idx) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
    if (dragOver !== idx) setDragOver(idx);
  };
  const handleDrop = async (e, dropIdx) => {
    e.preventDefault();
    if (dragIdx === null || dragIdx === dropIdx) { setDragIdx(null); setDragOver(null); return; }
    const next = [...categories];
    const [moved] = next.splice(dragIdx, 1);
    next.splice(dropIdx, 0, moved);
    const reordered = next.map((c, i) => ({ ...c, sortOrder: i + 1 }));
    setCategories(reordered);
    window.PRODUCT_CATEGORIES = reordered;
    setDragIdx(null); setDragOver(null);
    try {
      await window.apiFetch('/api/categories/reorder', {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ order: reordered.map(c => c.id) }),
      });
    } catch {}
  };
  const handleDragEnd = () => { setDragIdx(null); setDragOver(null); };

  return (
    <>
      <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div>
            <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Product categories</h3>
            <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>
              <span className="num">{categories.length}</span> categories · ลากเพื่อเรียงลำดับ · ใช้ใน dropdown ตอนสร้างและแก้ไข Product
            </div>
          </div>
          <Button variant="primary" icon="plus" onClick={() => setEditing('__new__')}>Add category</Button>
        </div>

        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
          <thead>
            <tr style={{ background: 'var(--bg-2)' }}>
              {[['','left'],['Category name','left'],['Products','right'],['Status','left'],['','right']].map(([l,a],i) => (
                <th key={i} className="eyebrow" style={{ padding: '10px', textAlign: a, fontWeight: 500, borderBottom: '1px solid var(--line)' }}>{l}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {categories.length === 0 && (
              <tr><td colSpan={4} style={{ padding: '32px 0', textAlign: 'center', color: 'var(--ink-4)', fontSize: 12 }}>ยังไม่มี categories — กด Add category เพื่อเพิ่ม</td></tr>
            )}
            {categories.map((c, i) => {
              const count = (window.PRODUCTS || []).filter(p => p.category === c.name).length;
              const isDragging = dragIdx === i;
              const isTarget   = dragOver === i && dragIdx !== i;
              const isDeleted  = c.status === 'deleted';
              return (
                <tr key={c.id}
                  draggable
                  onDragStart={e => handleDragStart(e, i)}
                  onDragOver={e => handleDragOver(e, i)}
                  onDrop={e => handleDrop(e, i)}
                  onDragEnd={handleDragEnd}
                  style={{
                    borderBottom: i === categories.length - 1 ? 'none' : '1px solid var(--line-2)',
                    borderTop: isTarget ? '2px solid var(--accent-2)' : undefined,
                    opacity: isDragging ? 0.4 : 1,
                    background: isDeleted ? 'var(--bg-2)' : 'transparent',
                    cursor: dragIdx !== null ? 'grabbing' : 'default',
                  }}>
                  {/* drag handle */}
                  <td style={{ padding: '12px 10px 12px 14px', width: 24, userSelect: 'none', cursor: 'grab' }}>
                    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 3px)', gap: '3px', opacity: 0.3 }}>
                      {[0,1,2,3,4,5].map(k => <span key={k} style={{ width: 3, height: 3, borderRadius: '50%', background: 'var(--ink)', display: 'block' }}/>)}
                    </div>
                  </td>
                  <td style={{ padding: '12px 10px' }}>
                    <div style={{ fontWeight: 500, textDecoration: isDeleted ? 'line-through' : 'none', color: isDeleted ? 'var(--ink-3)' : 'inherit', opacity: isDeleted ? 0.6 : 1 }}>{c.name}</div>
                    {c.description && <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 2 }}>{c.description}</div>}
                    <div style={{ fontSize: 10, color: 'var(--ink-4)', fontFamily: 'IBM Plex Mono', marginTop: 2 }}>{c.id}</div>
                  </td>
                  <td className="num" style={{ padding: '12px 10px', textAlign: 'right', opacity: isDeleted ? 0.4 : 1 }}>
                    {count > 0
                      ? <><span style={{ fontWeight: 500 }}>{count}</span><span style={{ fontSize: 10.5, color: 'var(--ink-3)', marginLeft: 4 }}>products</span></>
                      : <span style={{ color: 'var(--ink-4)' }}>0</span>}
                  </td>
                  <td style={{ padding: '12px 10px' }}>
                    {(() => {
                      const cfg = CATEGORY_STATUS_CONFIG[c.status] || CATEGORY_STATUS_CONFIG.live;
                      return (
                        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, padding: '3px 8px', background: cfg.bg, borderRadius: 2, fontSize: 10.5, fontWeight: 500, color: cfg.fg }}>
                          <span style={{ width: 5, height: 5, borderRadius: '50%', background: cfg.fg, flexShrink: 0 }}/>
                          {cfg.label}
                        </span>
                      );
                    })()}
                  </td>
                  <td style={{ padding: '12px 10px', textAlign: 'right' }}
                      onMouseDown={e => e.stopPropagation()}
                      onClick={e => e.stopPropagation()}>
                    <div style={{ display: 'flex', gap: 6, justifyContent: 'flex-end' }}>
                      <button onClick={() => setEditing(c)} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '4px 10px', background: 'none', border: '1px solid var(--line)', borderRadius: 3, color: isDeleted ? 'var(--ink-4)' : 'var(--ink-2)', cursor: 'pointer', fontSize: 11.5, fontFamily: 'Kanit, sans-serif' }}>
                        <Icon name="edit" size={11}/>Edit
                      </button>
                      {isDeleted ? (
                        <button onClick={async () => {
                          try {
                            const r = await window.apiFetch(`/api/categories/${c.id}/status`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: 'live' }) });
                            if (r.ok) { updateCategoryStatus(c.id, 'live'); showToast('เปิดใช้งานอีกครั้งแล้ว', { variant: 'success' }); }
                          } catch {}
                        }} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '4px 10px', background: 'none', border: '1px solid var(--positive)', borderRadius: 3, color: 'var(--positive)', cursor: 'pointer', fontSize: 11.5, fontFamily: 'Kanit, sans-serif' }}>
                          <Icon name="check" size={11}/>Enable
                        </button>
                      ) : (
                        <button onClick={async () => {
                          try {
                            const r = await window.apiFetch(`/api/categories/${c.id}/status`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: 'deleted' }) });
                            if (r.ok) { updateCategoryStatus(c.id, 'deleted'); showToast(`ลบ "${c.name}" แล้ว`, { variant: 'success' }); }
                          } catch {}
                        }} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '4px 10px', background: 'none', border: '1px solid var(--line)', borderRadius: 3, color: 'var(--negative)', cursor: 'pointer', fontSize: 11.5, fontFamily: 'Kanit, sans-serif' }}>
                          <Icon name="close" size={11}/>Delete
                        </button>
                      )}
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {editing !== null && (
        <CategoryModal
          category={editing === '__new__' ? null : editing}
          onClose={() => setEditing(null)}
          onSaved={async () => { await refresh(); setEditing(null); }}
        />
      )}
    </>
  );
};

const CategoryModal = ({ category, onClose, onSaved }) => {
  const isNew = !category;
  const autoId = (name) => name.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, '');
  const [form, setForm] = useState({
    id:          category?.id          || '',
    name:        category?.name        || '',
    description: category?.description || '',
  });
  const [saving, setSaving] = useState(false);
  const [err, setErr]       = useState(null);
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const handleSave = async () => {
    if (!form.name.trim()) { setErr('กรุณากรอกชื่อ category'); return; }
    setSaving(true); setErr(null);
    try {
      const payload = {
        id: isNew ? (form.id || autoId(form.name)) : category.id,
        name: form.name.trim(),
        description: form.description.trim() || null,
      };
      const res = await fetch(isNew ? '/api/categories' : `/api/categories/${category.id}`, {
        method: isNew ? 'POST' : 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload),
      });
      if (res.ok) {
        showToast(isNew ? 'เพิ่ม category แล้ว' : 'บันทึกการแก้ไขแล้ว', { variant: 'success' });
        onSaved();
      } else {
        const e = await res.json();
        setErr(e.error || 'เกิดข้อผิดพลาด');
      }
    } catch (e) {
      setErr('Network error: ' + e.message);
    } finally {
      setSaving(false);
    }
  };

  return (
    <Modal open={true}
      title={isNew ? 'Add category' : `Edit · ${category.name}`}
      subtitle={isNew ? 'สร้างหมวดหมู่ใหม่สำหรับ Product catalog' : 'แก้ไขข้อมูล category'}
      onClose={onClose} width={480}
      footer={<>
        <Button variant="ghost" onClick={onClose}>Cancel</Button>
        <Button variant="primary" icon="check" disabled={saving} onClick={handleSave}>
          {saving ? 'กำลังบันทึก…' : isNew ? 'Add category' : 'Save changes'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {err && <div style={{ padding: '10px 14px', background: 'var(--negative-bg)', borderRadius: 3, fontSize: 12, color: 'var(--negative)' }}>{err}</div>}
        {isNew && (
          <Field label="Category ID" hint="ตัวพิมพ์เล็ก a–z 0–9 _ (auto-fill จากชื่อ)">
            <TextInput
              value={form.id}
              onChange={e => set('id', e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, '_'))}
              placeholder="unified_comms"
              style={{ fontFamily: 'IBM Plex Mono' }}
            />
          </Field>
        )}
        <Field label="ชื่อ Category" required>
          <TextInput
            value={form.name}
            onChange={e => { set('name', e.target.value); if (isNew) set('id', autoId(e.target.value)); }}
            placeholder="Unified Communications"
          />
        </Field>
        <Field label="Description" hint="คำอธิบายหมวดหมู่ — แสดงใต้ชื่อในรายการ">
          <Textarea
            value={form.description}
            onChange={e => set('description', e.target.value)}
            placeholder="เช่น บริการด้านการสื่อสารแบบรวมศูนย์สำหรับองค์กร"
            style={{ resize: 'vertical', minHeight: 72 }}
          />
        </Field>
      </div>
    </Modal>
  );
};

const DeleteCategoryModal = ({ category, onClose, onDeleted }) => {
  const [loading, setLoading] = useState(false);
  const handleDelete = async () => {
    setLoading(true);
    try {
      const res = await window.apiFetch(`/api/categories/${category.id}`, { method: 'DELETE' });
      if (res.ok) {
        showToast(`ลบ "${category.name}" แล้ว`, { variant: 'success' });
        onDeleted();
      } else {
        const e = await res.json();
        showToast(e.error || 'ลบไม่ได้', { variant: 'error' });
        onClose();
      }
    } catch {
      showToast('เกิดข้อผิดพลาด', { variant: 'error' });
      onClose();
    } finally {
      setLoading(false);
    }
  };

  return (
    <Modal open={true} title="ยืนยันการลบ category" subtitle={category.name}
      onClose={onClose} width={400}
      footer={<>
        <Button variant="ghost" onClick={onClose} disabled={loading}>Cancel</Button>
        <Button variant="primary" style={{ background: 'var(--negative)', borderColor: 'var(--negative)' }} disabled={loading} onClick={handleDelete}>
          {loading ? 'กำลังลบ…' : 'ยืนยันลบ'}
        </Button>
      </>}>
      <div style={{ fontSize: 13, color: 'var(--ink-2)', lineHeight: 1.7 }}>
        <p style={{ margin: '0 0 12px' }}>ลบ <strong style={{ color: 'var(--ink)' }}>{category.name}</strong> ออกจากระบบ?</p>
        <div style={{ padding: '10px 14px', background: 'var(--bg-2)', borderRadius: 4, fontSize: 12 }}>
          Products ที่ใช้ category นี้อยู่จะยังคงเก็บชื่อเดิมไว้ แต่จะไม่ปรากฏใน dropdown สำหรับ product ใหม่
        </div>
      </div>
    </Modal>
  );
};

// ─── Static status badge (read-only) ────────────────────────────────────────
const ProductStatusSelect = ({ status }) => {
  const cfg = PRODUCT_STATUS_CONFIG[status] || PRODUCT_STATUS_CONFIG.live;
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, padding: '3px 8px', background: cfg.bg, borderRadius: 2, fontSize: 10.5, fontWeight: 500, color: cfg.fg, whiteSpace: 'nowrap' }}>
      <span style={{ width: 5, height: 5, borderRadius: '50%', background: cfg.fg, flexShrink: 0 }}/>
      {cfg.label}
    </span>
  );
};

// ─── Order status edit modal ─────────────────────────────────────────────────
const STATUS_PRESET_COLORS = ['#8b8f99','#3a6b8a','#d97b2e','#1f7a4d','#2d3a8c','#6b4a8a','#b8492f','#b07d2e'];

const StatusEditModal = ({ status, onClose, onSaved }) => {
  const [form, setForm] = useState({ label: status.label, labelTh: status.th || '', color: status.color, status: status.status || 'live' });
  const [saving, setSaving] = useState(false);
  const [err, setErr] = useState(null);
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const handleSave = async () => {
    if (!form.label.trim()) { setErr('กรุณากรอกชื่อ status'); return; }
    setSaving(true); setErr(null);
    try {
      const r = await window.apiFetch(`/api/order-statuses/${status.id}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ label: form.label.trim(), labelTh: form.labelTh.trim(), color: form.color }),
      });
      if (!r.ok) { const e = await r.json(); setErr(e.error || 'เกิดข้อผิดพลาด'); setSaving(false); return; }

      // Update status if changed
      if (form.status !== (status.status || 'live')) {
        const r2 = await window.apiFetch(`/api/order-statuses/${status.id}/status`, {
          method: 'PATCH',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ status: form.status }),
        });
        if (!r2.ok) { const e2 = await r2.json(); setErr(e2.error || 'เกิดข้อผิดพลาด'); setSaving(false); return; }
      }

      showToast('บันทึกการแก้ไขแล้ว', { variant: 'success' });
      onSaved({ label: form.label.trim(), th: form.labelTh.trim(), color: form.color, status: form.status });
    } catch (e) {
      setErr('Network error: ' + e.message);
    } finally { setSaving(false); }
  };

  return (
    <Modal open={true}
      title={`Edit status · ${status.id}`}
      subtitle="แก้ไขชื่อและสีของสถานะ"
      onClose={onClose} width={440}
      footer={<>
        <Button variant="ghost" onClick={onClose}>Cancel</Button>
        <Button variant="primary" icon="check" disabled={saving} onClick={handleSave}>
          {saving ? 'กำลังบันทึก…' : 'Save changes'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {err && <div style={{ padding: '10px 14px', background: 'var(--negative-bg)', borderRadius: 3, fontSize: 12, color: 'var(--negative)' }}>{err}</div>}
        <div style={{ padding: '10px 14px', background: 'var(--bg-2)', borderRadius: 3, fontSize: 12, color: 'var(--ink-3)' }}>
          Status ID: <span style={{ fontFamily: 'IBM Plex Mono', color: 'var(--ink-2)' }}>{status.id}</span>
          <span style={{ marginLeft: 12 }}>Stage: <strong style={{ color: 'var(--ink-2)' }}>{status.stage < 0 ? 'ปฏิเสธ' : status.stage}</strong></span>
        </div>
        <Field label="ชื่อ Status (EN)" required>
          <TextInput value={form.label} onChange={e => set('label', e.target.value)} placeholder="Pending approval"/>
        </Field>
        <Field label="ชื่อ Status (TH)">
          <TextInput value={form.labelTh} onChange={e => set('labelTh', e.target.value)} placeholder="รออนุมัติ"/>
        </Field>
        <Field label="สี Status">
          <div style={{ display: 'flex', gap: 6, alignItems: 'center', flexWrap: 'wrap' }}>
            {STATUS_PRESET_COLORS.map(c => (
              <button key={c} onClick={() => set('color', c)} style={{ width: 22, height: 22, borderRadius: '50%', background: c, border: `3px solid ${form.color === c ? 'var(--ink)' : 'transparent'}`, cursor: 'pointer', padding: 0, flexShrink: 0 }}/>
            ))}
            <TextInput value={form.color} onChange={e => set('color', e.target.value)} style={{ width: 90, fontFamily: 'IBM Plex Mono', fontSize: 11 }}/>
            <span style={{ padding: '3px 10px', background: form.color + '20', border: `1px solid ${form.color}`, borderRadius: 3, fontSize: 11.5, fontWeight: 500, color: form.color }}>{form.label || 'Preview'}</span>
          </div>
        </Field>
        <Field label="Enable">
          <div style={{ display: 'flex', gap: 8 }}>
            {['live', 'disabled'].map(v => {
              const cfg = ORDER_STATUS_STATUS_CONFIG[v];
              const active = form.status === v;
              return (
                <button key={v} onClick={() => set('status', v)} style={{
                  display: 'inline-flex', alignItems: 'center', gap: 6, padding: '5px 12px',
                  background: active ? cfg.bg : 'var(--bg-2)', border: `1px solid ${active ? cfg.fg + '40' : 'var(--line)'}`,
                  borderRadius: 3, fontSize: 11.5, fontWeight: active ? 600 : 400,
                  color: active ? cfg.fg : 'var(--ink-3)', cursor: 'pointer',
                }}>
                  <span style={{ width: 6, height: 6, borderRadius: '50%', background: active ? cfg.fg : 'var(--ink-4)', flexShrink: 0 }}/>
                  {cfg.label}
                </button>
              );
            })}
          </div>
        </Field>
      </div>
    </Modal>
  );
};

// ---------- Add Status Modal ----------
const AddStatusModal = ({ onClose, onAdded }) => {
  const [form, setForm] = useState({ id: '', label: '', labelTh: '', color: '#3a6b8a' });
  const [saving, setSaving] = useState(false);
  const [err, setErr] = useState(null);
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const handleSave = async () => {
    if (!form.id.trim()) { setErr('กรุณากรอก Status ID'); return; }
    if (!form.label.trim()) { setErr('กรุณากรอกชื่อ Status'); return; }
    setSaving(true); setErr(null);
    try {
      const r = await window.apiFetch('/api/order-statuses', {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ id: form.id.trim(), label: form.label.trim(), labelTh: form.labelTh.trim(), color: form.color }),
      });
      const data = await r.json();
      if (r.ok) {
        showToast('เพิ่ม status ใหม่แล้ว', { variant: 'success' });
        onAdded({ id: form.id.trim(), label: form.label.trim(), th: form.labelTh.trim(), color: form.color, stage: data.stage, status: 'live' });
      } else {
        setErr(data.error || 'เกิดข้อผิดพลาด');
      }
    } catch (e) { setErr('Network error: ' + e.message); }
    finally { setSaving(false); }
  };

  return (
    <Modal open={true} title="Add status" subtitle="เพิ่มสถานะใหม่ในขั้นตอน order"
      onClose={onClose} width={440}
      footer={<>
        <Button variant="ghost" onClick={onClose}>Cancel</Button>
        <Button variant="primary" icon="check" disabled={saving} onClick={handleSave}>
          {saving ? 'กำลังบันทึก…' : 'Add status'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {err && <div style={{ padding: '10px 14px', background: 'var(--negative-bg)', borderRadius: 3, fontSize: 12, color: 'var(--negative)' }}>{err}</div>}
        <Field label="Status ID" required>
          <TextInput value={form.id} onChange={e => set('id', e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, ''))} placeholder="my_status" style={{ fontFamily: 'IBM Plex Mono', fontSize: 12 }}/>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 4 }}>ตัวอักษรพิมพ์เล็ก, ตัวเลข และ _ เท่านั้น · ไม่สามารถแก้ไขภายหลัง</div>
        </Field>
        <Field label="ชื่อ Status (EN)" required>
          <TextInput value={form.label} onChange={e => set('label', e.target.value)} placeholder="Pending payment"/>
        </Field>
        <Field label="ชื่อ Status (TH)">
          <TextInput value={form.labelTh} onChange={e => set('labelTh', e.target.value)} placeholder="รอชำระเงิน"/>
        </Field>
        <Field label="สี Status">
          <div style={{ display: 'flex', gap: 6, alignItems: 'center', flexWrap: 'wrap' }}>
            {STATUS_PRESET_COLORS.map(c => (
              <button key={c} onClick={() => set('color', c)} style={{ width: 22, height: 22, borderRadius: '50%', background: c, border: `3px solid ${form.color === c ? 'var(--ink)' : 'transparent'}`, cursor: 'pointer', padding: 0, flexShrink: 0 }}/>
            ))}
            <TextInput value={form.color} onChange={e => set('color', e.target.value)} style={{ width: 90, fontFamily: 'IBM Plex Mono', fontSize: 11 }}/>
            <span style={{ padding: '3px 10px', background: form.color + '20', border: `1px solid ${form.color}`, borderRadius: 3, fontSize: 11.5, fontWeight: 500, color: form.color }}>{form.label || 'Preview'}</span>
          </div>
        </Field>
      </div>
    </Modal>
  );
};

// ---------- Order status workflow ----------
const SettingsStatusView = () => {
  const [statuses, setStatuses] = useState(ORDER_STATUSES || []);
  const [editingStatus, setEditingStatus] = useState(null);
  const [addingStatus, setAddingStatus] = useState(false);
  const [dragIdx, setDragIdx] = useState(null);
  const [dragOver, setDragOver] = useState(null);

  useEffect(() => {
    window.apiFetch('/api/order-statuses')
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d) { window.ORDER_STATUSES = d; setStatuses(d); } })
      .catch(() => {});
  }, []);

  const updateLocalStatus = (id, patch) => {
    const next = statuses.map(s => s.id === id ? { ...s, ...patch } : s);
    setStatuses(next);
    window.ORDER_STATUSES = next;
  };

  const handleDragStart = (e, idx) => { setDragIdx(idx); e.dataTransfer.effectAllowed = 'move'; };
  const handleDragOver  = (e, idx) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; if (dragOver !== idx) setDragOver(idx); };
  const handleDragEnd   = () => { setDragIdx(null); setDragOver(null); };
  const handleDrop = async (e, dropIdx) => {
    e.preventDefault();
    if (dragIdx === null || dragIdx === dropIdx) { setDragIdx(null); setDragOver(null); return; }
    const flowItems = statuses.filter(s => s.stage >= 0).sort((a, b) => a.stage - b.stage);
    const next = [...flowItems];
    const [moved] = next.splice(dragIdx, 1);
    next.splice(dropIdx, 0, moved);
    const reordered = next.map((s, i) => ({ ...s, stage: i }));
    const rejected = statuses.find(s => s.stage < 0);
    const newAll = [...reordered, ...(rejected ? [rejected] : [])];
    setStatuses(newAll);
    window.ORDER_STATUSES = newAll;
    setDragIdx(null); setDragOver(null);
    try {
      await window.apiFetch('/api/order-statuses/reorder', {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ order: reordered.map(s => s.id) }),
      });
    } catch {}
  };

  const updateItemStatus = async (id, newStatus) => {
    try {
      const r = await window.apiFetch(`/api/order-statuses/${id}/status`, {
        method: 'PATCH', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ status: newStatus }),
      });
      if (r.ok) { updateLocalStatus(id, { status: newStatus }); showToast(`Status → ${ORDER_STATUS_STATUS_CONFIG[newStatus].label}`, { variant: 'success' }); }
      else { showToast('อัปเดตไม่ได้', { variant: 'error' }); }
    } catch { showToast('เกิดข้อผิดพลาด', { variant: 'error' }); }
  };

  const allFlow = statuses.filter(s => s.stage >= 0).sort((a, b) => a.stage - b.stage);
  const flow = allFlow.filter(s => (s.status || 'live') === 'live');
  const rejected = statuses.find(s => s.stage < 0);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      {/* Pipeline visualization */}
      <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4, padding: '18px 20px' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 16 }}>
          <div>
            <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Order workflow</h3>
            <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>ลำดับสถานะคำสั่งซื้อตั้งแต่สร้างจนถึงใช้งานจริง</div>
          </div>
          <Button variant="ghost" size="sm" icon="plus" onClick={() => setAddingStatus(true)}>Add status</Button>
        </div>

        <div style={{ display: 'flex', alignItems: 'center', gap: 4, padding: '8px 0', overflowX: 'auto' }}>
          {flow.map((s, i) => (
            <React.Fragment key={s.id}>
              <div style={{
                background: s.color + '14', border: `1px solid ${s.color}`,
                padding: '10px 14px', borderRadius: 3, minWidth: 130, textAlign: 'center', flexShrink: 0,
              }}>
                <div className="eyebrow" style={{ fontSize: 9, color: s.color }}>Stage {s.stage}</div>
                <div style={{ fontSize: 13, fontWeight: 500, color: s.color, marginTop: 4 }}>{s.label}</div>
                <div style={{ fontSize: 10.5, color: 'var(--ink-2)', marginTop: 2 }}>{s.th}</div>
              </div>
              {i < flow.length - 1 && <Icon name="arrowRight" size={14} color="var(--ink-4)"/>}
            </React.Fragment>
          ))}
        </div>

        <div style={{ marginTop: 10, padding: '10px 14px', background: 'var(--negative-bg)', border: `1px solid ${rejected.color}40`, borderRadius: 3, display: 'flex', alignItems: 'center', gap: 10 }}>
          <span style={{ width: 6, height: 6, borderRadius: '50%', background: rejected.color }}/>
          <span style={{ fontSize: 12, color: rejected.color, fontWeight: 500 }}>{rejected.label}</span>
          <span style={{ fontSize: 11, color: 'var(--ink-2)' }}>{rejected.th} — ปลายทางสำหรับ order ที่ถูกปฏิเสธหรือยกเลิก</span>
        </div>
      </div>

      {/* Status table */}
      <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)' }}>
          <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Status definitions</h3>
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>ตั้งค่าสี, รหัสสถานะ, และผู้รับผิดชอบในแต่ละขั้น</div>
        </div>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
          <thead>
            <tr style={{ background: 'var(--bg-2)' }}>
              {[['','left'],['Status','left'],['ID','left'],['Stage','right'],['Color','left'],['Active','right'],['Enable','left'],['','right']].map(([l,a],i) => (
                <th key={i} className="eyebrow" style={{ padding: '10px', textAlign: a, fontWeight: 500, borderBottom: '1px solid var(--line)' }}>{l}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {(() => {
              const DragHandle = () => (
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2,3px)', gap: '3px', opacity: 0.3, cursor: 'grab' }}>
                  {[0,1,2,3,4,5].map(k => <span key={k} style={{ width: 3, height: 3, borderRadius: '50%', background: 'var(--ink)', display: 'block' }}/>)}
                </div>
              );
              const rows = [];
              // Draggable flow rows
              allFlow.forEach((s, i) => {
                const count = ORDERS.filter(o => o.status.id === s.id).length;
                const isDragging = dragIdx === i;
                const isTarget   = dragOver === i && dragIdx !== i;
                rows.push(
                  <tr key={s.id}
                    draggable
                    onDragStart={e => handleDragStart(e, i)}
                    onDragOver={e => handleDragOver(e, i)}
                    onDrop={e => handleDrop(e, i)}
                    onDragEnd={handleDragEnd}
                    style={{ borderBottom: '1px solid var(--line-2)', borderTop: isTarget ? '2px solid var(--accent-2)' : undefined, opacity: isDragging ? 0.4 : 1, cursor: dragIdx !== null ? 'grabbing' : 'default' }}>
                    <td style={{ padding: '12px 10px 12px 14px', width: 24, userSelect: 'none' }}><DragHandle/></td>
                    <td style={{ padding: '12px 10px' }}>
                      <StatusChip status={s}/>
                      <span style={{ fontSize: 11, color: 'var(--ink-3)', marginLeft: 8 }}>{s.th}</span>
                    </td>
                    <td className="num" style={{ padding: '12px 10px', color: 'var(--ink-2)' }}>{s.id}</td>
                    <td className="num" style={{ padding: '12px 10px', textAlign: 'right', color: 'var(--ink-2)', fontWeight: 500 }}>{s.stage}</td>
                    <td style={{ padding: '12px 10px' }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                        <span style={{ width: 16, height: 16, borderRadius: 3, background: s.color }}/>
                        <span className="num" style={{ fontSize: 11, color: 'var(--ink-2)' }}>{s.color}</span>
                      </div>
                    </td>
                    <td className="num" style={{ padding: '12px 10px', textAlign: 'right' }}>
                      {count > 0 ? <span style={{ fontWeight: 500 }}>{count}</span> : <span style={{ color: 'var(--ink-4)' }}>0</span>}
                    </td>
                    <td style={{ padding: '12px 10px' }} onMouseDown={e => e.stopPropagation()} onClick={e => e.stopPropagation()}>
                      {(() => {
                        const st = s.status || 'live';
                        const cfg = ORDER_STATUS_STATUS_CONFIG[st] || ORDER_STATUS_STATUS_CONFIG.live;
                        return (
                          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, padding: '3px 8px', background: cfg.bg, borderRadius: 2, fontSize: 10.5, fontWeight: 500, color: cfg.fg, whiteSpace: 'nowrap' }}>
                            <span style={{ width: 5, height: 5, borderRadius: '50%', background: cfg.fg, flexShrink: 0 }}/>
                            {cfg.label}
                          </span>
                        );
                      })()}
                    </td>
                    <td style={{ padding: '12px 10px', textAlign: 'right' }} onMouseDown={e => e.stopPropagation()} onClick={e => e.stopPropagation()}>
                      <button onClick={() => setEditingStatus(s)} style={{ background: 'none', border: 'none', color: 'var(--ink-3)', cursor: 'pointer', padding: 4 }}>
                        <Icon name="edit" size={12}/>
                      </button>
                    </td>
                  </tr>
                );
              });
              // Fixed Rejected row at bottom
              if (rejected) {
                const count = ORDERS.filter(o => o.status.id === rejected.id).length;
                const rejSt = rejected.status || 'live';
                const rejCfg = ORDER_STATUS_STATUS_CONFIG[rejSt] || ORDER_STATUS_STATUS_CONFIG.live;
                rows.push(
                  <tr key={rejected.id} style={{ borderTop: '2px solid var(--line)', background: 'var(--bg-2)' }}>
                    <td style={{ padding: '12px 10px 12px 14px', width: 24 }}>
                      <div style={{ width: 14, opacity: 0.2, textAlign: 'center', fontSize: 10 }}>—</div>
                    </td>
                    <td style={{ padding: '12px 10px' }}>
                      <StatusChip status={rejected}/>
                      <span style={{ fontSize: 11, color: 'var(--ink-3)', marginLeft: 8 }}>{rejected.th}</span>
                    </td>
                    <td className="num" style={{ padding: '12px 10px', color: 'var(--ink-2)' }}>{rejected.id}</td>
                    <td className="num" style={{ padding: '12px 10px', textAlign: 'right', color: 'var(--ink-4)' }}>—</td>
                    <td style={{ padding: '12px 10px' }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                        <span style={{ width: 16, height: 16, borderRadius: 3, background: rejected.color }}/>
                        <span className="num" style={{ fontSize: 11, color: 'var(--ink-2)' }}>{rejected.color}</span>
                      </div>
                    </td>
                    <td className="num" style={{ padding: '12px 10px', textAlign: 'right' }}>
                      {count > 0 ? <span style={{ fontWeight: 500 }}>{count}</span> : <span style={{ color: 'var(--ink-4)' }}>0</span>}
                    </td>
                    <td style={{ padding: '12px 10px' }}>
                      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, padding: '3px 8px', background: rejCfg.bg, borderRadius: 2, fontSize: 10.5, fontWeight: 500, color: rejCfg.fg, whiteSpace: 'nowrap' }}>
                        <span style={{ width: 5, height: 5, borderRadius: '50%', background: rejCfg.fg, flexShrink: 0 }}/>
                        {rejCfg.label}
                      </span>
                    </td>
                    <td style={{ padding: '12px 10px', textAlign: 'right' }}>
                      <button onClick={() => setEditingStatus(rejected)} style={{ background: 'none', border: 'none', color: 'var(--ink-3)', cursor: 'pointer', padding: 4 }}>
                        <Icon name="edit" size={12}/>
                      </button>
                    </td>
                  </tr>
                );
              }
              return rows;
            })()}
          </tbody>
        </table>
      </div>

      {addingStatus && (
        <AddStatusModal
          onClose={() => setAddingStatus(false)}
          onAdded={(newStatus) => {
            const next = [...statuses, newStatus];
            setStatuses(next);
            window.ORDER_STATUSES = next;
            setAddingStatus(false);
          }}
        />
      )}

      {editingStatus && (
        <StatusEditModal
          status={editingStatus}
          onClose={() => setEditingStatus(null)}
          onSaved={(patch) => { updateLocalStatus(editingStatus.id, patch); setEditingStatus(null); }}
        />
      )}
    </div>
  );
};

// ---------- Team setting ----------
const TEAM_STATUS_CONFIG = {
  live:     { label: 'Live',     bg: 'var(--positive-bg)', fg: 'var(--positive)' },
  disabled: { label: 'Disabled', bg: 'var(--bg-3)',        fg: 'var(--ink-3)'   },
};

const SettingsTeamsView = () => {
  const [teams, setTeams] = useState([]);
  const [editing, setEditing] = useState(null);  // null | 'new' | { id, name, description, status }
  const [form, setForm] = useState({ name: '', description: '', status: 'live' });
  const [saving, setSaving] = useState(false);
  const [err, setErr] = useState(null);
  const [disableConfirm, setDisableConfirm] = useState(null); // null | { memberCount }

  useEffect(() => {
    window.apiFetch('/api/teams').then(r => r.ok ? r.json() : null)
      .then(d => { if (d) { window.TEAMS = d; setTeams(d); } }).catch(() => {});
  }, []);

  const openNew = () => { setForm({ name: '', description: '', status: 'live' }); setErr(null); setDisableConfirm(null); setEditing('new'); };
  const openEdit = t => { setForm({ name: t.name, description: t.description, status: t.status || 'live' }); setErr(null); setDisableConfirm(null); setEditing(t); };
  const closeModal = () => { setEditing(null); setErr(null); setDisableConfirm(null); };

  // Called when user clicks Disabled button
  const handleClickDisabled = () => {
    const isNew = editing === 'new';
    const wasLive = !isNew && (editing.status || 'live') !== 'disabled';
    if (!isNew && wasLive) {
      const memberCount = (window.USERS || []).filter(u => u.team === editing.name).length;
      setDisableConfirm({ memberCount });
    } else {
      setForm(f => ({ ...f, status: 'disabled' }));
    }
  };

  const confirmDisable = () => {
    setForm(f => ({ ...f, status: 'disabled' }));
    setDisableConfirm(null);
  };

  const handleSave = async () => {
    if (!form.name.trim()) { setErr('กรุณากรอกชื่อทีม'); return; }
    const isNew = editing === 'new';
    const wasLive = !isNew && (editing.status || 'live') !== 'disabled';

    setSaving(true); setErr(null);
    try {
      const url = isNew ? '/api/teams' : `/api/teams/${editing.id}`;
      const r = await fetch(url, {
        method: isNew ? 'POST' : 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name: form.name.trim(), description: form.description.trim(), status: form.status }),
      });
      const data = await r.json();
      if (!r.ok) { setErr(data.error || 'เกิดข้อผิดพลาด'); return; }

      // Sync window.USERS — clear team for affected users
      if (!isNew && form.status === 'disabled' && wasLive && data.clearedUsers > 0) {
        if (window.USERS) {
          window.USERS = window.USERS.map(u => u.team === editing.name ? { ...u, team: '' } : u);
        }
      }

      const next = isNew ? [...teams, data] : teams.map(t => t.id === data.id ? data : t);
      next.sort((a, b) => a.name.localeCompare(b.name));
      setTeams(next); window.TEAMS = next;
      const msg = data.clearedUsers > 0
        ? `Disabled ทีม "${data.name}" และเคลียร์ข้อมูลทีมของ ${data.clearedUsers} คนแล้ว`
        : (isNew ? 'เพิ่มทีมใหม่แล้ว' : 'บันทึกแล้ว');
      showToast(msg, { variant: 'success' });
      closeModal();
    } catch (e) { setErr('Network error: ' + e.message); }
    finally { setSaving(false); }
  };

  const handleDelete = async (t) => {
    if (!confirm(`ลบทีม "${t.name}" ใช่ไหม?`)) return;
    try {
      await window.apiFetch(`/api/teams/${t.id}`, { method: 'DELETE' });
      const next = teams.filter(x => x.id !== t.id);
      setTeams(next); window.TEAMS = next;
      showToast('ลบทีมแล้ว', { variant: 'success' });
    } catch { showToast('ลบไม่ได้', { variant: 'error' }); }
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div>
            <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Teams</h3>
            <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>
              <span className="num">{teams.length}</span> ทีม · ใช้กำหนดสังกัดของผู้ใช้งานในระบบ
            </div>
          </div>
          <Button variant="primary" icon="plus" onClick={openNew}>New team</Button>
        </div>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
          <thead>
            <tr style={{ background: 'var(--bg-2)' }}>
              {[['ชื่อทีม','left'],['คำอธิบาย','left'],['สมาชิก','right'],['Status','left'],['','right']].map(([l,a],i) => (
                <th key={i} className="eyebrow" style={{ padding: '10px', textAlign: a, fontWeight: 500, borderBottom: '1px solid var(--line)' }}>{l}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {teams.map((t, i) => {
              const memberCount = (window.USERS || []).filter(u => u.team === t.name).length;
              const st = t.status || 'live';
              const cfg = TEAM_STATUS_CONFIG[st];
              return (
                <tr key={t.id} style={{ borderBottom: i === teams.length - 1 ? 'none' : '1px solid var(--line-2)' }}>
                  <td style={{ padding: '12px 10px', fontWeight: 500 }}>{t.name}</td>
                  <td style={{ padding: '12px 10px', color: 'var(--ink-3)', fontSize: 12 }}>{t.description || <span style={{ color: 'var(--ink-4)' }}>—</span>}</td>
                  <td className="num" style={{ padding: '12px 10px', textAlign: 'right', color: 'var(--ink-2)' }}>{memberCount}</td>
                  <td style={{ padding: '12px 10px' }}>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, padding: '3px 8px', background: cfg.bg, borderRadius: 2, fontSize: 10.5, fontWeight: 500, color: cfg.fg, whiteSpace: 'nowrap' }}>
                      <span style={{ width: 5, height: 5, borderRadius: '50%', background: cfg.fg, flexShrink: 0 }}/>
                      {cfg.label}
                    </span>
                  </td>
                  <td style={{ padding: '12px 10px', textAlign: 'right' }}>
                    <div style={{ display: 'flex', gap: 4, justifyContent: 'flex-end' }}>
                      <button onClick={() => openEdit(t)} style={{ background: 'none', border: 'none', color: 'var(--ink-3)', cursor: 'pointer', padding: 4 }}><Icon name="edit" size={12}/></button>
                      <button onClick={() => handleDelete(t)} style={{ background: 'none', border: 'none', color: 'var(--negative)', cursor: 'pointer', padding: 4, opacity: 0.6 }}><Icon name="x" size={12}/></button>
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {editing !== null && (
        <Modal open={true}
          title={editing === 'new' ? 'New team' : `Edit team · ${editing.name}`}
          subtitle={editing === 'new' ? 'สร้างทีมใหม่' : 'แก้ไขข้อมูลทีม'}
          onClose={closeModal} width={400}
          footer={<>
            <Button variant="ghost" onClick={closeModal}>Cancel</Button>
            <Button variant="primary" icon="check" disabled={saving} onClick={handleSave}>
              {saving ? 'กำลังบันทึก…' : editing === 'new' ? 'Create team' : 'Save changes'}
            </Button>
          </>}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            {err && <div style={{ padding: '10px 14px', background: 'var(--negative-bg)', borderRadius: 3, fontSize: 12, color: 'var(--negative)' }}>{err}</div>}
            <Field label="ชื่อทีม" required>
              <TextInput value={form.name} onChange={e => setForm(f => ({ ...f, name: e.target.value }))} placeholder="เช่น Sales, Engineering"/>
            </Field>
            <Field label="คำอธิบาย">
              <TextInput value={form.description} onChange={e => setForm(f => ({ ...f, description: e.target.value }))} placeholder="เช่น ทีมขายและพัฒนาธุรกิจ"/>
            </Field>
            <Field label="Status">
              <div style={{ display: 'flex', gap: 8 }}>
                {['live', 'disabled'].map(v => {
                  const cfg = TEAM_STATUS_CONFIG[v];
                  const active = form.status === v;
                  return (
                    <button key={v} onClick={() => v === 'disabled' ? handleClickDisabled() : setForm(f => ({ ...f, status: 'live' }))} style={{
                      display: 'inline-flex', alignItems: 'center', gap: 6, padding: '5px 12px',
                      background: active ? cfg.bg : 'var(--bg-2)', border: `1px solid ${active ? cfg.fg + '40' : 'var(--line)'}`,
                      borderRadius: 3, fontSize: 11.5, fontWeight: active ? 600 : 400,
                      color: active ? cfg.fg : 'var(--ink-3)', cursor: 'pointer',
                    }}>
                      <span style={{ width: 6, height: 6, borderRadius: '50%', background: active ? cfg.fg : 'var(--ink-4)', flexShrink: 0 }}/>
                      {cfg.label}
                    </button>
                  );
                })}
              </div>
            </Field>

            {disableConfirm !== null && (
              <div style={{ border: '1px solid var(--negative)', borderRadius: 4, overflow: 'hidden' }}>
                <div style={{ padding: '14px 16px', background: 'var(--negative-bg)' }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--negative)', marginBottom: 6 }}>ยืนยันการ Disable ทีม</div>
                  <div style={{ fontSize: 12.5, color: 'var(--ink-2)', lineHeight: 1.6 }}>
                    ผู้ใช้งานที่อยู่ในทีมนี้ จะถูกลบออกจากทีมเป็นจำนวน{' '}
                    <strong style={{ color: 'var(--negative)' }}>{disableConfirm.memberCount} คน</strong>
                  </div>
                </div>
                <div style={{ display: 'flex', gap: 8, padding: '10px 16px', borderTop: '1px solid var(--negative)', background: 'var(--panel)', justifyContent: 'flex-end' }}>
                  <Button variant="ghost" onClick={() => setDisableConfirm(null)}>ยกเลิก</Button>
                  <Button variant="primary" style={{ background: 'var(--negative)', borderColor: 'var(--negative)' }} onClick={confirmDisable}>ตกลง</Button>
                </div>
              </div>
            )}
          </div>
        </Modal>
      )}
    </div>
  );
};

// ---------- User setting ----------
// USERS is a window global set by data.js (fallback) and overwritten by /api/init (DB)

const SettingsUserView = () => {
  const { perms = {} } = React.useContext(window.PermCtx);
  const canAdminSetting = perms['Admin Setting'] === true;
  const [tab, setTab] = useState('team');

  const tabOptions = [
    { value: 'team',    label: 'Team members',        icon: 'users'  },
    { value: 'teams',   label: 'Team setting',         icon: 'users'  },
    // Roles & permissions: only Admin Setting users can see
    ...(canAdminSetting ? [{ value: 'roles', label: 'Roles & permissions', icon: 'shield' }] : []),
  ];

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end' }}>
        <Segmented options={tabOptions} value={tab} onChange={setTab}/>
      </div>

      {tab === 'team'    && <TeamTab/>}
      {tab === 'teams'   && <SettingsTeamsView/>}
      {tab === 'roles'   && canAdminSetting && <RolesTab/>}
    </div>
  );
};

const ProfileTab = () => {
  const [teams, setTeams] = useState(window.TEAMS || []);
  useEffect(() => {
    if (window.TEAMS?.length) { setTeams(window.TEAMS); return; }
    window.apiFetch('/api/teams').then(r => r.ok ? r.json() : null)
      .then(d => { if (d) { window.TEAMS = d; setTeams(d); } }).catch(() => {});
  }, []);
  return (
  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
    <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)' }}>
        <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Profile</h3>
        <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>ข้อมูลส่วนตัวและตำแหน่ง</div>
      </div>
      <div style={{ padding: 18 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 18, paddingBottom: 16, borderBottom: '1px solid var(--line-2)' }}>
          <Avatar name="ธีระพงษ์ ม." size={56}/>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 14, fontWeight: 500 }}>ธีระพงษ์ มหาชัย</div>
            <div style={{ fontSize: 11.5, color: 'var(--ink-3)' }}>Account Manager · Sales / Solutions team</div>
            <div style={{ marginTop: 6, display: 'flex', gap: 6 }}>
              <Button variant="ghost" size="sm" icon="upload">Change photo</Button>
              <Button variant="text" size="sm">Remove</Button>
            </div>
          </div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <Field label="ชื่อ-นามสกุล"><TextInput defaultValue="ธีระพงษ์ มหาชัย"/></Field>
          <Field label="Employee ID"><TextInput defaultValue="TB-04428" style={{ fontFamily: 'IBM Plex Mono' }}/></Field>
          <Field label="อีเมล"><TextInput type="email" defaultValue="theerapong.m@truebusiness.co.th"/></Field>
          <Field label="เบอร์ภายใน"><TextInput defaultValue="ext. 4428"/></Field>
          <Field label="ทีม">
            <Select defaultValue="">
              <option value="">— เลือกทีม —</option>
              {teams.map(t => <option key={t.id} value={t.name}>{t.name}{t.description ? ` — ${t.description}` : ''}</option>)}
            </Select>
          </Field>
          <Field label="ผู้จัดการ"><TextInput defaultValue="สมชาย ใจกล้า"/></Field>
        </div>
      </div>
    </div>

    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)' }}>
          <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Preferences</h3>
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>การตั้งค่าการแสดงผลและภาษา</div>
        </div>
        <div style={{ padding: 18, display: 'flex', flexDirection: 'column', gap: 14 }}>
          <PrefRow label="ภาษา" hint="Display language">
            <Select defaultValue="th" style={{ width: 160 }}>
              <option value="th">ภาษาไทย</option>
              <option value="en">English</option>
            </Select>
          </PrefRow>
          <PrefRow label="เขตเวลา" hint="Timezone">
            <Select defaultValue="bangkok" style={{ width: 160 }}>
              <option value="bangkok">Asia/Bangkok (GMT+7)</option>
              <option value="singapore">Asia/Singapore (GMT+8)</option>
            </Select>
          </PrefRow>
          <PrefRow label="รูปแบบวันที่" hint="Date format">
            <Select defaultValue="dmy" style={{ width: 160 }}>
              <option value="dmy">DD/MM/YYYY</option>
              <option value="ymd">YYYY-MM-DD</option>
              <option value="mdy">MM/DD/YYYY</option>
            </Select>
          </PrefRow>
          <PrefRow label="สกุลเงิน" hint="Currency display">
            <Select defaultValue="thb" style={{ width: 160 }}>
              <option value="thb">฿ THB (Thai Baht)</option>
              <option value="usd">$ USD</option>
            </Select>
          </PrefRow>
        </div>
      </div>

      <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)' }}>
          <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Notifications</h3>
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>เลือกรับการแจ้งเตือนผ่านช่องทางต่างๆ</div>
        </div>
        <div style={{ padding: 18, display: 'flex', flexDirection: 'column', gap: 12 }}>
          {[
            ['Order ใหม่ที่ฉันสร้าง', 'New orders I created', true, true],
            ['Order ของฉันถูกอนุมัติ', 'My orders approved', true, true],
            ['Order ของฉันถูกปฏิเสธ', 'My orders rejected', true, true],
            ['Order ใกล้ครบ SLA', 'SLA approaching', true, false],
            ['สรุปประจำสัปดาห์', 'Weekly summary', false, true],
          ].map(([th, en, email, push], i) => (
            <div key={i} style={{ display: 'grid', gridTemplateColumns: '1fr auto auto', gap: 12, alignItems: 'center', paddingBottom: 8, borderBottom: i === 4 ? 'none' : '1px solid var(--line-2)' }}>
              <div>
                <div style={{ fontSize: 12.5 }}>{th}</div>
                <div style={{ fontSize: 10.5, color: 'var(--ink-3)' }}>{en}</div>
              </div>
              <Toggle label="Email" value={email}/>
              <Toggle label="In-app" value={push}/>
            </div>
          ))}
        </div>
      </div>
    </div>
  </div>
  );
};

const PrefRow = ({ label, hint, children }) => (
  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}>
    <div>
      <div style={{ fontSize: 12.5, fontWeight: 500 }}>{label}</div>
      <div style={{ fontSize: 10.5, color: 'var(--ink-3)' }}>{hint}</div>
    </div>
    {children}
  </div>
);

const Toggle = ({ label, value }) => {
  const [on, setOn] = useState(value);
  return (
    <button onClick={() => setOn(o => !o)} title={label} style={{
      width: 28, height: 16, padding: 0, borderRadius: 999,
      background: on ? 'var(--positive)' : 'var(--line-3)',
      border: 'none', cursor: 'pointer', position: 'relative',
      transition: 'background 120ms',
    }}>
      <span style={{
        position: 'absolute', top: 2, left: on ? 14 : 2,
        width: 12, height: 12, borderRadius: '50%', background: '#fff',
        transition: 'left 120ms',
        boxShadow: '0 1px 2px rgba(0,0,0,0.15)',
      }}/>
    </button>
  );
};

const USER_STATUS_OPTIONS = ['active', 'disabled'];

const EditUserModal = ({ user, onClose, onSaved }) => {
  const [form, setForm] = useState({
    name: user.name, email: user.email, role: user.role,
    team: user.team || '', tier: user.tier || '', status: user.status || 'active',
    username: user.username || '', roleId: user.roleId || '',
  });
  const [saving, setSaving] = useState(false);
  const [err, setErr] = useState(null);
  const [teams, setTeams] = useState(window.TEAMS || []);
  const [roles, setRoles] = useState(window.ROLES || []);
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  useEffect(() => {
    window.apiFetch('/api/teams').then(r => r.ok ? r.json() : null)
      .then(d => { if (d) { window.TEAMS = d; setTeams(d); } }).catch(() => {});
  }, []);

  const handleSave = async () => {
    if (!form.name.trim()) { setErr('กรุณากรอกชื่อ'); return; }
    setSaving(true); setErr(null);
    try {
      const r = await window.apiFetch(`/api/users/${user.id}`, {
        method: 'PATCH', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ ...form, roleId: form.roleId ? parseInt(form.roleId) : null }),
      });
      const data = await r.json();
      if (!r.ok) { setErr(data.error || 'เกิดข้อผิดพลาด'); return; }
      showToast('บันทึกข้อมูลผู้ใช้แล้ว', { variant: 'success' });
      onSaved(data);
    } catch (e) { setErr('Network error: ' + e.message); }
    finally { setSaving(false); }
  };

  const statusCfg = {
    active:   { label: 'Active',   bg: 'var(--positive-bg)', fg: 'var(--positive)' },
    disabled: { label: 'Disabled', bg: 'var(--bg-3)',        fg: 'var(--ink-3)'    },
  };

  return (
    <Modal open={true} title={`Edit user · ${user.name}`} subtitle="แก้ไขข้อมูลสมาชิกในทีม"
      onClose={onClose} width={520}
      footer={<>
        <Button variant="ghost" onClick={onClose}>Cancel</Button>
        <Button variant="primary" icon="check" disabled={saving} onClick={handleSave}>
          {saving ? 'กำลังบันทึก…' : 'Save changes'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {err && <div style={{ padding: '10px 14px', background: 'var(--negative-bg)', borderRadius: 3, fontSize: 12, color: 'var(--negative)' }}>{err}</div>}

        <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 14px', background: 'var(--bg-2)', borderRadius: 3 }}>
          <Avatar name={user.name} size={40}/>
          <div>
            <div style={{ fontSize: 13, fontWeight: 500 }}>{user.name}</div>
            <div className="num" style={{ fontSize: 11, color: 'var(--ink-3)' }}>{user.email}</div>
          </div>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <Field label="ชื่อ-นามสกุล" required>
            <TextInput value={form.name} onChange={e => set('name', e.target.value)}/>
          </Field>
          <Field label="อีเมล">
            <TextInput type="email" value={form.email} onChange={e => set('email', e.target.value)}/>
          </Field>
          <Field label="Username (สำหรับ Login)" hint="ตัวพิมพ์เล็ก a–z 0–9 . _ เท่านั้น">
            <TextInput
              value={form.username}
              onChange={e => set('username', e.target.value.toLowerCase().replace(/[^a-z0-9._]/g, ''))}
              placeholder="firstname.l"
              style={{ fontFamily: 'IBM Plex Mono', fontSize: 12 }}
            />
          </Field>
          <Field label="System Role (สิทธิ์ใช้งาน)">
            <Select value={form.roleId} onChange={e => set('roleId', e.target.value)}>
              <option value="">— ไม่ระบุ —</option>
              {(window.ROLES || []).map(r => (
                <option key={r.id} value={r.id}>{r.label}</option>
              ))}
            </Select>
          </Field>
          <Field label="ทีม">
            <Select value={form.team} onChange={e => set('team', e.target.value)}>
              <option value="">— ไม่ระบุ —</option>
              {teams.filter(t => (t.status || 'live') === 'live').map(t => (
                <option key={t.id} value={t.name}>{t.name}</option>
              ))}
            </Select>
          </Field>
          <Field label="ตำแหน่ง (Job title)">
            <TextInput value={form.role} onChange={e => set('role', e.target.value)} placeholder="Account Manager"/>
          </Field>
          <Field label="Tier / Abbreviation">
            <TextInput value={form.tier} onChange={e => set('tier', e.target.value)} placeholder="AM"/>
          </Field>
          <Field label="Status">
            <div style={{ display: 'flex', gap: 8 }}>
              {USER_STATUS_OPTIONS.map(v => {
                const cfg = statusCfg[v];
                const active = form.status === v;
                return (
                  <button key={v} onClick={() => set('status', v)} style={{
                    display: 'inline-flex', alignItems: 'center', gap: 6, padding: '5px 12px',
                    background: active ? cfg.bg : 'var(--bg-2)', border: `1px solid ${active ? cfg.fg + '40' : 'var(--line)'}`,
                    borderRadius: 3, fontSize: 11.5, fontWeight: active ? 600 : 400,
                    color: active ? cfg.fg : 'var(--ink-3)', cursor: 'pointer',
                  }}>
                    <span style={{ width: 6, height: 6, borderRadius: '50%', background: active ? cfg.fg : 'var(--ink-4)', flexShrink: 0 }}/>
                    {cfg.label}
                  </button>
                );
              })}
            </div>
          </Field>
        </div>
      </div>
    </Modal>
  );
};

// ─── Add User Modal ──────────────────────────────────────────────────────────
const AddUserModal = ({ onClose, onCreated }) => {
  const [form, setForm] = useState({
    name: '', email: '', username: '', password: '', confirmPwd: '',
    role: '', team: '', tier: '', roleId: '',
  });
  const [showPw,  setShowPw]  = useState(false);
  const [saving,  setSaving]  = useState(false);
  const [err,     setErr]     = useState(null);
  const [teams,   setTeams]   = useState(window.TEAMS || []);
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  useEffect(() => {
    window.apiFetch('/api/teams').then(r => r.ok ? r.json() : null)
      .then(d => { if (d) { window.TEAMS = d; setTeams(d); } }).catch(() => {});
  }, []);

  // Password strength
  const pw = form.password;
  const checks = { len: pw.length >= 8, upper: /[A-Z]/.test(pw), digit: /[0-9]/.test(pw), sym: /[^A-Za-z0-9]/.test(pw) };
  const score = Object.values(checks).filter(Boolean).length;
  const strengthLabel = ['—','Very weak','Weak','Good','Strong'][score];
  const strengthColor = ['var(--ink-4)','var(--negative)','#d97b2e','#d97b2e','var(--positive)'][score];

  const valid = form.name.trim() && form.username.trim() && pw.length >= 8 && pw === form.confirmPwd;

  const handleSave = async () => {
    if (!form.name.trim())        { setErr('กรุณากรอกชื่อ-นามสกุล'); return; }
    if (!form.username.trim())    { setErr('กรุณากรอก Username'); return; }
    if (pw.length < 8)            { setErr('Password ต้องมีอย่างน้อย 8 ตัวอักษร'); return; }
    if (pw !== form.confirmPwd)   { setErr('Password ไม่ตรงกัน'); return; }
    setSaving(true); setErr(null);
    try {
      const r = await window.apiFetch('/api/users', {
        method: 'POST',
        body: JSON.stringify({
          name: form.name.trim(), email: form.email.trim(),
          username: form.username.trim().toLowerCase(),
          password: pw,
          role: form.role.trim(), team: form.team, tier: form.tier.trim(),
          roleId: form.roleId ? parseInt(form.roleId) : null,
        }),
      });
      const data = await r.json();
      if (!r.ok) { setErr(data.error || 'เกิดข้อผิดพลาด'); return; }
      showToast(`เพิ่มผู้ใช้ "${data.name}" สำเร็จ`, { variant: 'success' });
      onCreated(data);
    } catch (e) { setErr('Network error: ' + e.message); }
    finally { setSaving(false); }
  };

  return (
    <Modal open={true} title="Add user" subtitle="เพิ่มสมาชิกใหม่เข้าสู่ระบบ"
      onClose={onClose} width={540}
      footer={<>
        <Button variant="ghost" onClick={onClose}>Cancel</Button>
        <Button variant="primary" icon="plus" disabled={saving || !valid} onClick={handleSave}>
          {saving ? 'กำลังสร้าง…' : 'Create user'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {err && <div style={{ padding: '10px 14px', background: 'var(--negative-bg)', borderRadius: 3, fontSize: 12, color: 'var(--negative)', border: '1px solid var(--negative)' }}>{err}</div>}

        {/* Identity */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <Field label="ชื่อ-นามสกุล" required>
            <TextInput value={form.name} onChange={e => set('name', e.target.value)} placeholder="ธีระพงษ์ มหาชัย"/>
          </Field>
          <Field label="อีเมล">
            <TextInput type="email" value={form.email} onChange={e => set('email', e.target.value)} placeholder="firstname@truebusiness.co.th"/>
          </Field>
        </div>

        {/* Login credentials */}
        <div style={{ padding: '12px 14px', background: 'var(--bg-2)', borderRadius: 4, border: '1px solid var(--line)' }}>
          <div style={{ fontSize: 10.5, fontWeight: 600, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.07em', marginBottom: 12 }}>
            Login Credentials
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <Field label="Username" required hint="a–z 0–9 . _ เท่านั้น">
              <TextInput
                value={form.username}
                onChange={e => set('username', e.target.value.toLowerCase().replace(/[^a-z0-9._]/g, ''))}
                placeholder="firstname.l"
                style={{ fontFamily: 'IBM Plex Mono', fontSize: 12 }}
              />
            </Field>
            <div/>
            <Field label="Password เริ่มต้น" required>
              <div style={{ position: 'relative' }}>
                <TextInput
                  type={showPw ? 'text' : 'password'}
                  value={pw}
                  onChange={e => set('password', e.target.value)}
                  placeholder="••••••••"
                  style={{ paddingRight: 36 }}
                />
                <button onClick={() => setShowPw(v => !v)} style={{
                  position: 'absolute', right: 8, top: '50%', transform: 'translateY(-50%)',
                  background: 'none', border: 'none', cursor: 'pointer', color: 'var(--ink-3)', padding: 2,
                }}>
                  <Icon name={showPw ? 'eyeOff' : 'eye'} size={14}/>
                </button>
              </div>
              {pw.length > 0 && (
                <div style={{ marginTop: 6 }}>
                  <div style={{ display: 'flex', gap: 3, marginBottom: 4 }}>
                    {[1,2,3,4].map(i => (
                      <div key={i} style={{ flex: 1, height: 3, borderRadius: 1, background: i <= score ? strengthColor : 'var(--line-2)', transition: 'background 120ms' }}/>
                    ))}
                  </div>
                  <div style={{ fontSize: 10, color: strengthColor, fontWeight: 500 }}>{strengthLabel}</div>
                </div>
              )}
            </Field>
            <Field label="ยืนยัน Password" required error={form.confirmPwd.length > 0 && form.confirmPwd !== pw ? 'ไม่ตรงกัน' : null}>
              <TextInput
                type={showPw ? 'text' : 'password'}
                value={form.confirmPwd}
                onChange={e => set('confirmPwd', e.target.value)}
                placeholder="••••••••"
              />
            </Field>
          </div>
        </div>

        {/* Role & Team */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <Field label="System Role (สิทธิ์ใช้งาน)">
            <Select value={form.roleId} onChange={e => set('roleId', e.target.value)}>
              <option value="">— ไม่ระบุ —</option>
              {(window.ROLES || []).map(r => (
                <option key={r.id} value={r.id}>{r.label}</option>
              ))}
            </Select>
          </Field>
          <Field label="ทีม">
            <Select value={form.team} onChange={e => set('team', e.target.value)}>
              <option value="">— ไม่ระบุ —</option>
              {teams.filter(t => (t.status || 'live') === 'live').map(t => (
                <option key={t.id} value={t.name}>{t.name}</option>
              ))}
            </Select>
          </Field>
          <Field label="ตำแหน่ง (Job title)">
            <TextInput value={form.role} onChange={e => set('role', e.target.value)} placeholder="Account Manager"/>
          </Field>
          <Field label="Tier / Abbreviation">
            <TextInput value={form.tier} onChange={e => set('tier', e.target.value)} placeholder="AM"/>
          </Field>
        </div>
      </div>
    </Modal>
  );
};

// ─── Set Password Modal (admin) ─────────────────────────────────────────────
const SetPasswordModal = ({ user, onClose }) => {
  const [pwd, setPwd]         = useState('');
  const [confirm, setConfirm] = useState('');
  const [saving, setSaving]   = useState(false);
  const [err, setErr]         = useState('');

  const checks = {
    len:   pwd.length >= 8,
    upper: /[A-Z]/.test(pwd),
    digit: /[0-9]/.test(pwd),
    sym:   /[^A-Za-z0-9]/.test(pwd),
  };
  const score = Object.values(checks).filter(Boolean).length;
  const strengthColor = ['var(--ink-4)','var(--negative)','#d97b2e','#d97b2e','var(--positive)'][score];
  const valid = checks.len && pwd === confirm;

  const handleSave = async () => {
    if (!valid) return;
    setSaving(true); setErr('');
    try {
      const r = await window.apiFetch(`/api/users/${user.id}/set-password`, {
        method: 'POST', body: JSON.stringify({ password: pwd }),
      });
      const d = await r.json();
      if (!r.ok) { setErr(d.error || 'เกิดข้อผิดพลาด'); return; }
      showToast(`รีเซ็ต password ของ ${user.name} แล้ว`, { variant: 'success' });
      onClose();
    } catch { setErr('Network error'); }
    finally { setSaving(false); }
  };

  return (
    <Modal open title={`Set password · ${user.name}`} subtitle={`Username: ${user.username || '—'}`}
      onClose={onClose} width={440}
      footer={<>
        <Button variant="ghost" onClick={onClose}>Cancel</Button>
        <Button variant="primary" icon="check" disabled={!valid || saving} onClick={handleSave}>
          {saving ? 'กำลังบันทึก…' : 'Set password'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {err && <div style={{ padding: '8px 12px', background: 'var(--negative-bg)', borderRadius: 3, fontSize: 12, color: 'var(--negative)' }}>{err}</div>}
        <Field label="รหัสผ่านใหม่" required hint="อย่างน้อย 8 ตัวอักษร">
          <TextInput type="password" value={pwd} onChange={e => setPwd(e.target.value)} placeholder="••••••••"/>
        </Field>
        {pwd.length > 0 && (
          <div style={{ marginTop: -8 }}>
            <div style={{ display: 'flex', gap: 4, marginBottom: 5 }}>
              {[1,2,3,4].map(i => (
                <div key={i} style={{ flex: 1, height: 3, borderRadius: 1, background: i <= score ? strengthColor : 'var(--line-2)', transition: 'background 120ms' }}/>
              ))}
            </div>
            <div style={{ fontSize: 10.5, display: 'flex', justifyContent: 'space-between' }}>
              <span style={{ color: strengthColor, fontWeight: 500 }}>{['—','Very weak','Weak','Good','Strong'][score]}</span>
              <span style={{ color: 'var(--ink-3)' }}>
                {Object.entries({ '8+': checks.len, 'A–Z': checks.upper, '0–9': checks.digit, 'Sym': checks.sym }).map(([k,v]) => (
                  <span key={k} style={{ marginLeft: 7, color: v ? 'var(--positive)' : 'var(--ink-4)' }}>{v ? '✓' : '·'} {k}</span>
                ))}
              </span>
            </div>
          </div>
        )}
        <Field label="ยืนยันรหัสผ่าน" required
          error={confirm.length > 0 && confirm !== pwd ? 'รหัสผ่านไม่ตรงกัน' : null}>
          <TextInput type="password" value={confirm} onChange={e => setConfirm(e.target.value)} placeholder="••••••••"/>
        </Field>
      </div>
    </Modal>
  );
};

const TeamTab = () => {
  const [users, setUsers] = useState(window.USERS || []);
  const [editingUser, setEditingUser] = useState(null);
  const [setPwdUser, setSetPwdUser] = useState(null);
  const [addingUser, setAddingUser] = useState(false);
  const { perms = {} } = React.useContext(window.PermCtx);
  const isAdmin = perms['Manage users'] === true;

  useEffect(() => {
    window.apiFetch('/api/users').then(r => r.ok ? r.json() : null)
      .then(d => { if (d) { window.USERS = d; setUsers(d); } }).catch(() => {});
  }, []);

  return (
    <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div>
          <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Team members</h3>
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}><span className="num">{users.length}</span> members · จัดการสมาชิกในทีมและสิทธิ์การเข้าใช้งาน</div>
        </div>
        {isAdmin && <Button variant="primary" icon="plus" onClick={() => setAddingUser(true)}>Add user</Button>}
      </div>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
        <thead>
          <tr style={{ background: 'var(--bg-2)' }}>
            {[['User','left'],['Username','left'],['Team','left'],['System role','left'],['Status','left'],['','right']].map(([l,a],i) => (
              <th key={i} className="eyebrow" style={{ padding: '10px', textAlign: a, fontWeight: 500, borderBottom: '1px solid var(--line)' }}>{l}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {users.map((u, i) => {
            const isDisabled = u.status === 'disabled';
            return (
            <tr key={u.id || i} style={{
              borderBottom: i === users.length - 1 ? 'none' : '1px solid var(--line-2)',
              background: isDisabled ? 'var(--bg-2)' : 'transparent',
              opacity: isDisabled ? 0.6 : 1,
              transition: 'opacity 120ms',
            }}>
              <td style={{ padding: '12px 10px' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <Avatar name={u.name} size={28}/>
                  <div>
                    <div style={{ fontWeight: 500, textDecoration: isDisabled ? 'line-through' : 'none', color: isDisabled ? 'var(--ink-3)' : 'inherit' }}>{u.name}</div>
                    <div style={{ fontSize: 11, color: 'var(--ink-4)' }}>{u.role}</div>
                  </div>
                </div>
              </td>
              <td style={{ padding: '12px 10px' }}>
                {u.username ? (
                  <span className="num" style={{ fontSize: 11.5, color: isDisabled ? 'var(--ink-4)' : 'var(--ink-2)', background: 'var(--bg-2)', padding: '2px 8px', borderRadius: 3, border: '1px solid var(--line-2)' }}>
                    {u.username}
                  </span>
                ) : (
                  <span style={{ fontSize: 11, color: 'var(--ink-4)', fontStyle: 'italic' }}>ยังไม่มี username</span>
                )}
              </td>
              <td style={{ padding: '12px 10px', color: 'var(--ink-4)' }}>{u.team || '—'}</td>
              <td style={{ padding: '12px 10px' }}>
                {u.roleName && !isDisabled ? (
                  <span style={{
                    display: 'inline-flex', alignItems: 'center', gap: 5,
                    padding: '2px 8px', background: 'var(--bg-2)', border: '1px solid var(--line-2)',
                    borderRadius: 3, fontSize: 11, fontWeight: 500, color: 'var(--ink-2)',
                  }}>
                    <Icon name="shield" size={10} color="var(--ink-3)"/>
                    {u.roleName}
                  </span>
                ) : <span style={{ fontSize: 11, color: 'var(--ink-4)' }}>—</span>}
              </td>
              <td style={{ padding: '12px 10px' }}>
                <span style={{
                  display: 'inline-flex', alignItems: 'center', gap: 5,
                  padding: '2px 7px', borderRadius: 2, fontSize: 10.5, fontWeight: 500,
                  background: isDisabled ? 'var(--bg-3)' : 'var(--positive-bg)',
                  color: isDisabled ? 'var(--ink-3)' : 'var(--positive)',
                }}>
                  <span style={{ width: 5, height: 5, borderRadius: '50%', background: isDisabled ? 'var(--ink-4)' : 'var(--positive)' }}/>
                  {isDisabled ? 'Disabled' : 'Active'}
                </span>
              </td>
              <td style={{ padding: '12px 10px', textAlign: 'right' }}>
                <div style={{ display: 'flex', gap: 6, justifyContent: 'flex-end' }}>
                  {isAdmin && (
                    <button onClick={() => setSetPwdUser(u)} title="Set password"
                      style={{ background: 'none', border: '1px solid var(--line)', borderRadius: 3, color: 'var(--ink-3)', cursor: 'pointer', padding: '4px 8px', display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 11, fontFamily: 'Kanit, sans-serif' }}>
                      <Icon name="lock" size={11}/>Password
                    </button>
                  )}
                  {isAdmin && (
                    <button onClick={() => setEditingUser(u)}
                      style={{ background: 'none', border: 'none', color: 'var(--ink-3)', cursor: 'pointer', padding: 4, borderRadius: 3 }}>
                      <Icon name="edit" size={13}/>
                    </button>
                  )}
                </div>
              </td>
            </tr>
            );
          })}
        </tbody>
      </table>

      {editingUser && (
        <EditUserModal
          user={editingUser}
          onClose={() => setEditingUser(null)}
          onSaved={(updated) => {
            const next = users.map(u => u.id === updated.id ? updated : u);
            setUsers(next); window.USERS = next;
            setEditingUser(null);
          }}
        />
      )}
      {setPwdUser && <SetPasswordModal user={setPwdUser} onClose={() => setSetPwdUser(null)}/>}
      {addingUser && (
        <AddUserModal
          onClose={() => setAddingUser(false)}
          onCreated={(newUser) => {
            const next = [...users, newUser];
            setUsers(next); window.USERS = next;
            setAddingUser(false);
          }}
        />
      )}
    </div>
  );
};

const ROLES_DEFAULT = [
  { id: 'sales',    label: 'Sales / AM',          desc: 'สร้างและดูแล order, ดูราคา catalog',                    members: 12,
    perms: { 'View orders': 'own + team', 'Create orders': true,  'Approve orders': true,  'Manage provisioning': false, 'Edit catalog': false, 'Manage users': false, 'Admin Setting': false, 'View customer': true,  'Edit customer': true  } },
  { id: 'manager',  label: 'Solution Manager',    desc: 'อนุมัติ order ทุกระดับ ดูภาพรวมทีม',                   members: 3,
    perms: { 'View orders': 'all',        'Create orders': true,  'Approve orders': true,  'Manage provisioning': true,  'Edit catalog': false, 'Manage users': true,  'Admin Setting': false, 'View customer': true,  'Edit customer': true  } },
  { id: 'engineer', label: 'Solution Engineer',   desc: 'ดูข้อมูล provisioning, อัปเดตสถานะการติดตั้ง',          members: 8,
    perms: { 'View orders': 'assigned',   'Create orders': false, 'Approve orders': false, 'Manage provisioning': true,  'Edit catalog': false, 'Manage users': false, 'Admin Setting': false, 'View customer': true,  'Edit customer': false } },
  { id: 'cs',       label: 'Customer Success',    desc: 'ดูแลหลัง provisioning, ส่งมอบและฝึกอบรม',              members: 5,
    perms: { 'View orders': 'active',     'Create orders': false, 'Approve orders': false, 'Manage provisioning': false, 'Edit catalog': false, 'Manage users': false, 'Admin Setting': false, 'View customer': true,  'Edit customer': true  } },
  { id: 'admin',    label: 'System Admin',        desc: 'จัดการสินค้า, ผู้ใช้ และตั้งค่าระบบ',                   members: 2,
    perms: { 'View orders': 'all',        'Create orders': true,  'Approve orders': true,  'Manage provisioning': true,  'Edit catalog': true,  'Manage users': true,  'Admin Setting': true,  'View customer': true,  'Edit customer': true  } },
];
const PERM_KEYS = Object.keys(ROLES_DEFAULT[0].perms);
const VIEW_ORDERS_OPTIONS = ['all', 'own + team', 'assigned', 'active'];

const AddRoleModal = ({ onClose, onAdded }) => {
  const initPerms = Object.fromEntries(PERM_KEYS.map(k => [k, false]));
  const [form, setForm] = useState({ label: '', desc: '', perms: initPerms });
  const [error, setError] = useState('');
  const [saving, setSaving] = useState(false);

  const setP = (k, v) => setForm(f => ({ ...f, perms: { ...f.perms, [k]: v } }));

  const handleSave = async () => {
    if (!form.label.trim()) { setError('กรุณากรอกชื่อ Role'); return; }
    setSaving(true);
    try {
      const r = await window.apiFetch('/api/roles', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name: form.label.trim(), description: form.desc.trim(), permissions: form.perms }),
      });
      const data = await r.json();
      if (!r.ok) { setError(data.error || 'เกิดข้อผิดพลาด'); return; }
      const newRole = { ...data, perms: data.permissions || {}, label: data.name, desc: data.description || '' };
      showToast('เพิ่ม Role แล้ว', { variant: 'success' });
      onAdded(newRole);
    } catch (e) { setError('Network error: ' + e.message); }
    finally { setSaving(false); }
  };

  return (
    <Modal open={true} title="Add role" subtitle="สร้าง Role ใหม่และกำหนดสิทธิ์การเข้าถึง"
      onClose={onClose} width={520}
      footer={<>
        <Button variant="ghost" onClick={onClose} disabled={saving}>Cancel</Button>
        <Button variant="primary" icon="check" disabled={saving} onClick={handleSave}>
          {saving ? 'กำลังบันทึก…' : 'Add role'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {error && <div style={{ color: 'var(--negative)', fontSize: 12, padding: '8px 12px', background: 'var(--negative-bg)', borderRadius: 3 }}>{error}</div>}
        <Field label="ชื่อ Role">
          <TextInput value={form.label} onChange={e => { setError(''); setForm(f => ({ ...f, label: e.target.value })); }} placeholder="เช่น Finance, Support"/>
        </Field>
        <Field label="คำอธิบาย">
          <TextInput value={form.desc} onChange={e => setForm(f => ({ ...f, desc: e.target.value }))} placeholder="อธิบายหน้าที่ของ role นี้"/>
        </Field>
        <div>
          <div className="eyebrow" style={{ fontSize: 10.5, color: 'var(--ink-3)', marginBottom: 8, letterSpacing: '.06em' }}>Permissions</div>
          <div style={{ border: '1px solid var(--line)', borderRadius: 4, overflow: 'hidden' }}>
            {PERM_KEYS.map((perm, i) => {
              const isView = perm === 'View orders';
              const val = form.perms[perm];
              return (
                <div key={perm} style={{
                  display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                  padding: '9px 14px', borderBottom: i < PERM_KEYS.length - 1 ? '1px solid var(--line-2)' : 'none',
                  background: 'var(--panel)',
                }}>
                  <span style={{ fontSize: 12.5, color: 'var(--ink-1)' }}>{perm}</span>
                  {isView ? (
                    <select value={val || ''}
                      onChange={e => setP(perm, e.target.value || false)}
                      style={{ fontSize: 11.5, padding: '4px 8px', border: '1px solid var(--line)', borderRadius: 3, background: 'var(--bg-2)', color: 'var(--ink-1)', cursor: 'pointer' }}>
                      <option value="">No access</option>
                      {VIEW_ORDERS_OPTIONS.map(o => <option key={o} value={o}>{o}</option>)}
                    </select>
                  ) : (
                    <button onClick={() => setP(perm, !val)} style={{
                      display: 'inline-flex', alignItems: 'center', gap: 5, padding: '4px 10px',
                      border: `1px solid ${val ? 'var(--positive)' : 'var(--line)'}`,
                      borderRadius: 3, fontSize: 11.5, fontWeight: val ? 600 : 400,
                      background: val ? 'var(--positive-bg)' : 'var(--bg-2)',
                      color: val ? 'var(--positive)' : 'var(--ink-3)', cursor: 'pointer',
                    }}>
                      {val
                        ? <Icon name="check" size={11} color="var(--positive)"/>
                        : <span style={{ fontSize: 13, lineHeight: 1 }}>—</span>}
                      {val ? 'Yes' : 'No'}
                    </button>
                  )}
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </Modal>
  );
};

const VIEW_ORDERS_CYCLE = [false, 'all', 'own + team', 'assigned', 'active'];

const EditRoleModal = ({ role, onClose, onSave, onDelete }) => {
  const [form, setForm] = useState({ label: role.label, desc: role.desc || '', perms: { ...(role.perms || {}) } });
  const [confirmDel, setConfirmDel] = useState(false);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState('');

  const setP = (k, v) => setForm(f => ({ ...f, perms: { ...f.perms, [k]: v } }));

  const handleSave = () => {
    if (!form.label.trim()) { setError('กรุณากรอกชื่อ Role'); return; }
    onSave({ ...role, label: form.label.trim(), desc: form.desc.trim(), perms: form.perms });
  };

  return (
    <Modal open={true} title="Edit role" subtitle={`แก้ไข Role · ${role.members} members`} onClose={onClose} width={520}
      footer={<>
        <div style={{ flex: 1 }}>
          {!confirmDel ? (
            <Button variant="ghost" icon="trash" onClick={() => setConfirmDel(true)}
              style={{ color: 'var(--negative)' }}>ลบ Role</Button>
          ) : (
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ fontSize: 12, color: 'var(--negative)', fontWeight: 500 }}>ลบ "{role.label}"?</span>
              <Button variant="ghost" size="sm" onClick={() => setConfirmDel(false)}>ยกเลิก</Button>
              <Button size="sm" onClick={onDelete}
                style={{ background: 'var(--negative)', color: '#fff', border: 'none' }}>ยืนยันลบ</Button>
            </div>
          )}
        </div>
        <Button variant="ghost" onClick={onClose} disabled={saving}>Cancel</Button>
        <Button variant="primary" icon="check" disabled={saving || confirmDel} onClick={handleSave}>
          {saving ? 'กำลังบันทึก…' : 'Save changes'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {error && <div style={{ color: 'var(--negative)', fontSize: 12, padding: '8px 12px', background: 'var(--negative-bg)', borderRadius: 3 }}>{error}</div>}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <Field label="ชื่อ Role" required>
            <TextInput value={form.label} onChange={e => { setError(''); setForm(f => ({ ...f, label: e.target.value })); }}/>
          </Field>
          <Field label="คำอธิบาย">
            <TextInput value={form.desc} onChange={e => setForm(f => ({ ...f, desc: e.target.value }))} placeholder="อธิบายหน้าที่ของ role"/>
          </Field>
        </div>
        <div>
          <div className="eyebrow" style={{ fontSize: 10.5, color: 'var(--ink-3)', marginBottom: 8, letterSpacing: '.06em' }}>Permissions</div>
          <div style={{ border: '1px solid var(--line)', borderRadius: 4, overflow: 'hidden' }}>
            {PERM_KEYS.map((perm, i) => {
              const isView = perm === 'View orders';
              const val = form.perms[perm];
              return (
                <div key={perm} style={{
                  display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                  padding: '9px 14px', borderBottom: i < PERM_KEYS.length - 1 ? '1px solid var(--line-2)' : 'none',
                  background: 'var(--panel)',
                }}>
                  <span style={{ fontSize: 12.5, color: 'var(--ink-1)' }}>{perm}</span>
                  {isView ? (
                    <select value={val || ''}
                      onChange={e => setP(perm, e.target.value || false)}
                      style={{ fontSize: 11.5, padding: '4px 8px', border: '1px solid var(--line)', borderRadius: 3, background: 'var(--bg-2)', color: 'var(--ink-1)', cursor: 'pointer' }}>
                      <option value="">No access</option>
                      {VIEW_ORDERS_OPTIONS.map(o => <option key={o} value={o}>{o}</option>)}
                    </select>
                  ) : (
                    <button onClick={() => setP(perm, !val)} style={{
                      display: 'inline-flex', alignItems: 'center', gap: 5, padding: '4px 10px',
                      border: `1px solid ${val ? 'var(--positive)' : 'var(--line)'}`,
                      borderRadius: 3, fontSize: 11.5, fontWeight: val ? 600 : 400,
                      background: val ? 'var(--positive-bg)' : 'var(--bg-2)',
                      color: val ? 'var(--positive)' : 'var(--ink-3)', cursor: 'pointer',
                    }}>
                      {val ? <Icon name="check" size={11} color="var(--positive)"/> : <span style={{ fontSize: 13, lineHeight: 1 }}>—</span>}
                      {val ? 'Yes' : 'No'}
                    </button>
                  )}
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </Modal>
  );
};

const PermCell = ({ value, permKey, onClick }) => {
  const isView = permKey === 'View orders';
  const [hover, setHover] = useState(false);

  let display;
  if (value === true)        display = <Icon name="check" size={13} color="var(--positive)"/>;
  else if (value === false)  display = <span style={{ color: hover ? 'var(--ink-3)' : 'var(--ink-4)', fontSize: 13 }}>—</span>;
  else display = (
    <span style={{ padding: '2px 7px', background: hover ? 'var(--bg-2)' : 'var(--bg-3)', borderRadius: 2, fontSize: 10.5, color: 'var(--ink-2)' }}>{value}</span>
  );

  return (
    <button onClick={onClick}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      title={isView ? `คลิกเพื่อเปลี่ยน: ${VIEW_ORDERS_CYCLE.map(v => v || 'ไม่มีสิทธิ์').join(' → ')}` : 'คลิกเพื่อ toggle'}
      style={{
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        minWidth: 60, padding: '4px 6px', borderRadius: 3, cursor: 'pointer',
        border: hover ? '1px solid var(--line-2)' : '1px solid transparent',
        background: hover ? 'var(--bg-2)' : 'transparent',
        transition: 'all 120ms',
      }}>
      {display}
    </button>
  );
};

const RolesTab = () => {
  const [roles, setRoles] = useState([]);
  const [loading, setLoading] = useState(true);
  const [showAdd, setShowAdd] = useState(false);
  const [editingRole, setEditingRole] = useState(null);

  // Drag-to-reorder columns
  const [dragCol, setDragCol] = useState(null);
  const [dragOverCol, setDragOverCol] = useState(null);

  const handleColDragStart = (e, idx) => {
    setDragCol(idx);
    e.dataTransfer.effectAllowed = 'move';
  };
  const handleColDragOver = (e, idx) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
    if (dragOverCol !== idx) setDragOverCol(idx);
  };
  const handleColDrop = (e, dropIdx) => {
    e.preventDefault();
    const from = dragCol;
    setDragCol(null); setDragOverCol(null);
    if (from === null || from === dropIdx) return;
    const next = [...roles];
    const [moved] = next.splice(from, 1);
    next.splice(dropIdx, 0, moved);
    const reordered = next.map((r, i) => ({ ...r, sort_order: i + 1 }));
    setRoles(reordered);
    // Persist new order to DB (must use apiFetch to include Bearer token)
    window.apiFetch('/api/roles/reorder', {
      method: 'POST',
      body: JSON.stringify(reordered.map((r, i) => ({ id: r.id, sort_order: i + 1 }))),
    }).catch(() => {});
  };
  const handleColDragEnd = () => { setDragCol(null); setDragOverCol(null); };

  // Load from DB on mount
  useEffect(() => {
    window.apiFetch('/api/roles').then(r => r.ok ? r.json() : null)
      .then(data => {
        if (data) {
          // Normalize: DB uses 'permissions' key, frontend uses 'perms'
          const norm = data.map(r => ({ ...r, perms: r.permissions || {}, label: r.name, desc: r.description }));
          setRoles(norm);
        }
        setLoading(false);
      }).catch(() => setLoading(false));
  }, []);

  const cyclePerm = (roleId, permKey) => {
    setRoles(rs => {
      const next = rs.map(r => {
        if (r.id !== roleId) return r;
        const cur = r.perms[permKey];
        let nextVal;
        if (permKey === 'View orders') {
          const idx = VIEW_ORDERS_CYCLE.indexOf(cur);
          nextVal = VIEW_ORDERS_CYCLE[(idx + 1) % VIEW_ORDERS_CYCLE.length];
        } else {
          nextVal = !cur;
        }
        return { ...r, perms: { ...r.perms, [permKey]: nextVal } };
      });
      // Auto-save to DB
      const updated = next.find(r => r.id === roleId);
      if (updated) {
        window.apiFetch(`/api/roles/${roleId}`, {
          method: 'PATCH',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ permissions: updated.perms }),
        }).catch(() => {});
      }
      return next;
    });
  };

  return (
    <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div>
          <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Roles & permissions</h3>
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>
            {loading ? 'กำลังโหลด…' : `${roles.length} roles · กดที่ช่องเพื่อแก้ไขสิทธิ์ · กดที่ชื่อ role เพื่อแก้ไข`}
          </div>
        </div>
        <Button variant="ghost" icon="plus" onClick={() => setShowAdd(true)} disabled={loading}>Add role</Button>
      </div>
      {loading && (
        <div style={{ padding: '32px 0', textAlign: 'center', color: 'var(--ink-4)', fontSize: 12 }}>
          กำลังโหลดข้อมูล Roles…
        </div>
      )}
      <div style={{ overflowX: 'auto', display: loading ? 'none' : 'block' }}>
        <table style={{ width: '100%', minWidth: 200 + roles.length * 130, borderCollapse: 'collapse', fontSize: 12 }}>
          <thead>
            <tr style={{ background: 'var(--bg-2)' }}>
              <th className="eyebrow" style={{ padding: '10px', textAlign: 'left', fontWeight: 500, borderBottom: '1px solid var(--line)', minWidth: 200 }}>Permission</th>
              {roles.map((r, colIdx) => {
                const isDragging  = dragCol === colIdx;
                const isDropTarget = dragOverCol === colIdx && dragCol !== colIdx;
                return (
                <th key={r.id} className="eyebrow"
                  draggable
                  onDragStart={e => handleColDragStart(e, colIdx)}
                  onDragOver={e => handleColDragOver(e, colIdx)}
                  onDrop={e => handleColDrop(e, colIdx)}
                  onDragEnd={handleColDragEnd}
                  style={{
                    padding: '8px 10px', textAlign: 'center', fontWeight: 500,
                    borderBottom: '1px solid var(--line)', minWidth: 130,
                    borderLeft: isDropTarget ? '3px solid var(--brand)' : '3px solid transparent',
                    opacity: isDragging ? 0.35 : 1,
                    cursor: dragCol !== null ? 'grabbing' : 'grab',
                    background: isDropTarget ? 'var(--bg-3)' : 'var(--bg-2)',
                    transition: 'opacity 120ms, background 120ms',
                    userSelect: 'none',
                  }}>
                  {/* Drag grip indicator */}
                  <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 2, opacity: 0.3, letterSpacing: 2, fontSize: 9 }}>
                    ⠿
                  </div>
                  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4 }}>
                    <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink-1)', textTransform: 'uppercase', letterSpacing: '.04em' }}>{r.label}</span>
                    <span style={{ fontSize: 9.5, color: 'var(--ink-3)', fontFamily: 'IBM Plex Mono', textTransform: 'none', letterSpacing: 0, fontWeight: 400 }}>{r.members} members</span>
                    <button onClick={e => { e.stopPropagation(); setEditingRole(r); }} style={{
                      display: 'inline-flex', alignItems: 'center', gap: 4,
                      background: 'var(--bg-2)', border: '1px solid var(--line)',
                      borderRadius: 3, padding: '2px 8px', cursor: 'pointer',
                      fontSize: 10, color: 'var(--ink-2)', fontFamily: 'Kanit, sans-serif',
                      textTransform: 'none', letterSpacing: 0, fontWeight: 400,
                    }}
                    onMouseEnter={e => { e.currentTarget.style.background = 'var(--bg-3)'; e.currentTarget.style.borderColor = 'var(--ink-3)'; }}
                    onMouseLeave={e => { e.currentTarget.style.background = 'var(--bg-2)'; e.currentTarget.style.borderColor = 'var(--line)'; }}>
                      <Icon name="edit" size={9} color="var(--ink-3)"/> Edit
                    </button>
                  </div>
                </th>
                );
              })}
            </tr>
          </thead>
          <tbody>
            {PERM_KEYS.map((perm, i) => (
              <tr key={perm} style={{ borderBottom: i === PERM_KEYS.length - 1 ? 'none' : '1px solid var(--line-2)' }}>
                <td style={{ padding: '8px 10px', fontSize: 12, color: 'var(--ink-2)' }}>{perm}</td>
                {roles.map((r, colIdx) => (
                  <td key={r.id}
                    onDragOver={e => handleColDragOver(e, colIdx)}
                    onDrop={e => handleColDrop(e, colIdx)}
                    style={{
                      padding: '6px 10px', textAlign: 'center',
                      borderLeft: dragOverCol === colIdx && dragCol !== colIdx ? '3px solid var(--brand)' : '3px solid transparent',
                      opacity: dragCol === colIdx ? 0.35 : 1,
                      background: dragOverCol === colIdx && dragCol !== colIdx ? 'rgba(var(--brand-rgb,45,58,140),0.04)' : 'transparent',
                      transition: 'opacity 120ms',
                    }}>
                    <PermCell value={r.perms[perm]} permKey={perm} onClick={() => cyclePerm(r.id, perm)}/>
                  </td>
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {showAdd && (
        <AddRoleModal
          onClose={() => setShowAdd(false)}
          onAdded={newRole => { setRoles(rs => [...rs, newRole]); setShowAdd(false); }}
        />
      )}

      {editingRole && (
        <EditRoleModal
          role={editingRole}
          onClose={() => setEditingRole(null)}
          onSave={async updated => {
            try {
              const r = await window.apiFetch(`/api/roles/${updated.id}`, {
                method: 'PATCH',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ name: updated.label, description: updated.desc, permissions: updated.perms }),
              });
              if (r.ok) {
                setRoles(rs => rs.map(r => r.id === updated.id ? updated : r));
                showToast('บันทึกแล้ว', { variant: 'success' });
              } else {
                showToast('บันทึกไม่ได้', { variant: 'error' });
              }
            } catch { showToast('เกิดข้อผิดพลาด', { variant: 'error' }); }
            setEditingRole(null);
          }}
          onDelete={async () => {
            try {
              const r = await window.apiFetch(`/api/roles/${editingRole.id}`, { method: 'DELETE' });
              if (r.ok) {
                setRoles(rs => rs.filter(r => r.id !== editingRole.id));
                showToast('ลบ Role แล้ว', { variant: 'success' });
              } else {
                showToast('ลบไม่ได้', { variant: 'error' });
              }
            } catch { showToast('เกิดข้อผิดพลาด', { variant: 'error' }); }
            setEditingRole(null);
          }}
        />
      )}
    </div>
  );
};

// ---------- Document setting ----------
// DOC_TYPES and DOC_REQUIREMENTS are window globals set by data.js / /api/init

const CAT_COLOR_PRESETS = [
  { bg: '#fce8e4', fg: '#b8492f', label: 'Red'    },
  { bg: '#e0e4f5', fg: '#2d3a8c', label: 'Blue'   },
  { bg: '#fef3e8', fg: '#d97b2e', label: 'Orange' },
  { bg: '#e3f1ea', fg: '#1f7a4d', label: 'Green'  },
  { bg: '#ecdef5', fg: '#6b4a8a', label: 'Purple' },
  { bg: '#e0f5f5', fg: '#1a7a7a', label: 'Teal'   },
  { bg: '#f0f0f2', fg: '#44475a', label: 'Gray'   },
  { bg: '#fce4ef', fg: '#a3294f', label: 'Pink'   },
];

// Fallback tag colors (used before categories are fetched)
const DOC_TAG_COLORS_DEFAULT = {
  KYC: { bg: '#fce8e4', fg: '#b8492f' }, Legal: { bg: '#e0e4f5', fg: '#2d3a8c' },
  Tax: { bg: '#fef3e8', fg: '#d97b2e' }, Finance: { bg: '#e3f1ea', fg: '#1f7a4d' },
  Provisioning: { bg: '#ecdef5', fg: '#6b4a8a' },
};

// ---- DocCategoriesTab ----
const DocCategoriesTab = ({ categories, setCategories }) => {
  const [editing, setEditing]   = useState(null); // null | 'new' | category object
  const [delConfirm, setDelConfirm] = useState(null); // null | category object

  // derive doc-type usage count per category name
  const usageCount = {};
  (window.DOC_TYPES || []).forEach(d => { usageCount[d.tag] = (usageCount[d.tag] || 0) + 1; });

  const saveCategory = async (form) => {
    const isNew = editing === 'new';
    const url   = isNew ? '/api/doc-categories' : `/api/doc-categories/${editing.id}`;
    const method = isNew ? 'POST' : 'PATCH';
    const r = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(form) });
    const data = await r.json();
    if (!r.ok) throw new Error(data.error || 'เกิดข้อผิดพลาด');
    if (isNew) {
      const next = [...categories, data];
      setCategories(next); window.DOC_CATEGORIES = next;
    } else {
      const next = categories.map(c => c.id === data.id ? data : c);
      setCategories(next); window.DOC_CATEGORIES = next;
    }
    setEditing(null);
  };

  const deleteCategory = async (cat) => {
    const r = await window.apiFetch(`/api/doc-categories/${cat.id}`, { method: 'DELETE' });
    if (!r.ok) return;
    const next = categories.filter(c => c.id !== cat.id);
    setCategories(next); window.DOC_CATEGORIES = next;
    setDelConfirm(null);
  };

  return (
    <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div>
          <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>หมวดเอกสาร</h3>
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>จัดการหมวดสำหรับแยกประเภทเอกสาร</div>
        </div>
        <Button variant="primary" icon="plus" onClick={() => setEditing('new')}>Add category</Button>
      </div>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
        <thead>
          <tr style={{ background: 'var(--bg-2)' }}>
            {[['หมวด', 'left'], ['ใช้ใน', 'center'], ['', 'right']].map(([l, a], i) => (
              <th key={i} className="eyebrow" style={{ padding: '9px 14px', textAlign: a, fontWeight: 500, borderBottom: '1px solid var(--line)', fontSize: 10.5 }}>{l}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {categories.map((cat, i) => (
            <tr key={cat.id} style={{ borderBottom: i === categories.length - 1 ? 'none' : '1px solid var(--line-2)' }}>
              <td style={{ padding: '11px 14px' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <span style={{
                    display: 'inline-block', width: 12, height: 12, borderRadius: 2,
                    background: cat.bgColor, border: `1.5px solid ${cat.fgColor}40`,
                  }}/>
                  <span style={{
                    padding: '2px 8px', background: cat.bgColor, color: cat.fgColor,
                    borderRadius: 2, fontSize: 10.5, fontWeight: 600, letterSpacing: '0.05em',
                    textTransform: 'uppercase',
                  }}>{cat.name}</span>
                </div>
              </td>
              <td style={{ padding: '11px 14px', textAlign: 'center', color: 'var(--ink-3)', fontSize: 12 }}>
                <span className="num">{usageCount[cat.name] || 0}</span>
                <span style={{ fontSize: 10.5, marginLeft: 3 }}>เอกสาร</span>
              </td>
              <td style={{ padding: '11px 14px', textAlign: 'right' }}>
                <div style={{ display: 'flex', gap: 4, justifyContent: 'flex-end' }}>
                  <button onClick={() => setEditing(cat)} style={{ background: 'none', border: 'none', color: 'var(--ink-3)', cursor: 'pointer', padding: 4, borderRadius: 3 }}>
                    <Icon name="edit" size={13}/>
                  </button>
                  <button onClick={() => setDelConfirm(cat)} style={{ background: 'none', border: 'none', color: 'var(--ink-3)', cursor: 'pointer', padding: 4, borderRadius: 3 }}>
                    <Icon name="trash" size={13}/>
                  </button>
                </div>
              </td>
            </tr>
          ))}
          {categories.length === 0 && (
            <tr><td colSpan={3} style={{ padding: '24px', textAlign: 'center', color: 'var(--ink-4)', fontSize: 12 }}>ยังไม่มีหมวดเอกสาร</td></tr>
          )}
        </tbody>
      </table>

      {/* Add / Edit modal */}
      {editing !== null && (
        <DocCategoryModal
          cat={editing === 'new' ? null : editing}
          onClose={() => setEditing(null)}
          onSave={saveCategory}
        />
      )}

      {/* Delete confirm modal */}
      {delConfirm && (
        <Modal open={true} title="ลบหมวดเอกสาร" onClose={() => setDelConfirm(null)} width={420}
          footer={<>
            <Button variant="ghost" onClick={() => setDelConfirm(null)}>ยกเลิก</Button>
            <Button variant="primary" style={{ background: 'var(--negative)', borderColor: 'var(--negative)' }}
              onClick={() => deleteCategory(delConfirm)}>ลบ</Button>
          </>}>
          <div style={{ fontSize: 13, color: 'var(--ink-2)', lineHeight: 1.7 }}>
            ยืนยันการลบหมวด <strong style={{ color: 'var(--negative)' }}>{delConfirm.name}</strong> ?
            {(usageCount[delConfirm.name] || 0) > 0 && (
              <div style={{ marginTop: 8, padding: '8px 12px', background: '#fef3e8', border: '1px solid #f0c080', borderRadius: 3, fontSize: 12, color: '#a05a10' }}>
                มีเอกสาร <strong>{usageCount[delConfirm.name]} รายการ</strong> ที่ใช้หมวดนี้อยู่
              </div>
            )}
          </div>
        </Modal>
      )}
    </div>
  );
};

const DocCategoryModal = ({ cat, onClose, onSave }) => {
  const initial = cat
    ? { name: cat.name, bg: cat.bgColor, fg: cat.fgColor }
    : { name: '', bg: CAT_COLOR_PRESETS[0].bg, fg: CAT_COLOR_PRESETS[0].fg };
  const [form, setForm] = useState(initial);
  const [error, setError] = useState('');
  const [saving, setSaving] = useState(false);

  const selectedPreset = CAT_COLOR_PRESETS.findIndex(p => p.bg === form.bg && p.fg === form.fg);

  const handleSave = async () => {
    if (!form.name.trim()) { setError('กรุณากรอกชื่อหมวด'); return; }
    setSaving(true);
    try {
      await onSave({ name: form.name.trim(), bgColor: form.bg, fgColor: form.fg });
    } catch (e) { setError(e.message); setSaving(false); }
  };

  return (
    <Modal open={true} title={cat ? 'แก้ไขหมวดเอกสาร' : 'เพิ่มหมวดเอกสาร'}
      subtitle={cat ? 'แก้ไขชื่อและสีของหมวด' : 'สร้างหมวดใหม่สำหรับแยกประเภทเอกสาร'}
      onClose={onClose} width={460}
      footer={<>
        <Button variant="ghost" onClick={onClose}>Cancel</Button>
        <Button variant="primary" icon="check" onClick={handleSave} disabled={saving}>
          {cat ? 'Save changes' : 'Add category'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        {error && <div style={{ color: 'var(--negative)', fontSize: 12, padding: '8px 12px', background: 'var(--negative-bg)', borderRadius: 3 }}>{error}</div>}
        <Field label="ชื่อหมวด" required>
          <TextInput value={form.name} onChange={e => { setError(''); setForm(f => ({ ...f, name: e.target.value })); }}
            placeholder="เช่น HR, Finance, Compliance"/>
        </Field>
        <div>
          <div className="eyebrow" style={{ fontSize: 10.5, color: 'var(--ink-3)', marginBottom: 10, letterSpacing: '.06em' }}>สี</div>
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            {CAT_COLOR_PRESETS.map((p, i) => (
              <button key={i} title={p.label} onClick={() => setForm(f => ({ ...f, bg: p.bg, fg: p.fg }))}
                style={{
                  width: 32, height: 32, borderRadius: 4, cursor: 'pointer',
                  background: p.bg, border: selectedPreset === i ? `2.5px solid ${p.fg}` : '2px solid transparent',
                  boxShadow: selectedPreset === i ? `0 0 0 1.5px ${p.fg}40` : 'none',
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                }}>
                {selectedPreset === i && <span style={{ width: 8, height: 8, borderRadius: '50%', background: p.fg }}/>}
              </button>
            ))}
          </div>
        </div>
        <div>
          <div className="eyebrow" style={{ fontSize: 10.5, color: 'var(--ink-3)', marginBottom: 8, letterSpacing: '.06em' }}>ตัวอย่าง</div>
          <span style={{
            padding: '3px 10px', background: form.bg, color: form.fg,
            borderRadius: 2, fontSize: 11, fontWeight: 600, letterSpacing: '0.05em', textTransform: 'uppercase',
          }}>{form.name || 'PREVIEW'}</span>
        </div>
      </div>
    </Modal>
  );
};

const SettingsDocumentsView = () => {
  const [tab, setTab] = useState('documents');
  const [categories, setCategories] = useState(window.DOC_CATEGORIES || []);
  const [docTypes, setDocTypes] = useState(window.DOC_TYPES || DOC_TYPES);
  const [liveProducts, setLiveProducts] = useState(
    (window.PRODUCTS || PRODUCTS).filter(p => p.status !== 'deleted')
  );
  const [reqs, setReqs] = useState(() => {
    const base = { ...(window.DOC_REQUIREMENTS || DOC_REQUIREMENTS) };
    const docKeys = (window.DOC_TYPES || DOC_TYPES).map(d => d.id);
    (window.PRODUCTS || PRODUCTS).filter(p => p.status !== 'deleted').forEach(p => {
      if (!(p.id in base)) base[p.id] = Object.fromEntries(docKeys.map(k => [k, 'none']));
    });
    return base;
  });
  const [editing, setEditing] = useState(null);
  const [docCatFilter, setDocCatFilter] = useState('all'); // category filter for product list

  useEffect(() => {
    window.apiFetch('/api/doc-categories').then(r => r.ok ? r.json() : null)
      .then(d => { if (d) { window.DOC_CATEGORIES = d; setCategories(d); } }).catch(() => {});

    // fetch fresh doc-requirements from DB (overrides init-time snapshot)
    window.apiFetch('/api/doc-requirements').then(r => r.ok ? r.json() : null)
      .then(dbReqs => {
        if (dbReqs) {
          window.DOC_REQUIREMENTS = dbReqs;
          setReqs(prev => {
            const docKeys = (window.DOC_TYPES || DOC_TYPES).map(d => d.id);
            // start from DB values, fill any missing product/doc combos with 'none'
            const next = { ...dbReqs };
            (window.PRODUCTS || PRODUCTS).filter(p => p.status !== 'deleted').forEach(p => {
              if (!next[p.id]) next[p.id] = Object.fromEntries(docKeys.map(k => [k, 'none']));
            });
            return next;
          });
        }
      }).catch(() => {});

    window.apiFetch('/api/products').then(r => r.ok ? r.json() : null)
      .then(data => {
        if (data) {
          window.PRODUCTS = data;
          const live = data.filter(p => p.status !== 'deleted');
          setLiveProducts(live);
          setReqs(prev => {
            const next = { ...prev };
            const docKeys = (window.DOC_TYPES || DOC_TYPES).map(d => d.id);
            live.forEach(p => {
              if (!(p.id in next)) next[p.id] = Object.fromEntries(docKeys.map(k => [k, 'none']));
            });
            return next;
          });
        }
      }).catch(() => {});
  }, []);

  // derive tag color map from categories (with fallback to defaults)
  const tagColors = categories.length
    ? Object.fromEntries(categories.map(c => [c.name, { bg: c.bgColor, fg: c.fgColor }]))
    : DOC_TAG_COLORS_DEFAULT;

  const cycle = (productId, docId) => {
    const order = ['required', 'optional', 'none'];
    setReqs(r => {
      const docKeys = (window.DOC_TYPES || DOC_TYPES).map(d => d.id);
      const productReqs = r[productId] || Object.fromEntries(docKeys.map(k => [k, 'none']));
      const cur = productReqs[docId] || 'none';
      const next = order[(order.indexOf(cur) + 1) % order.length];
      // keep window.DOC_REQUIREMENTS in sync so remount shows correct value immediately
      if (!window.DOC_REQUIREMENTS) window.DOC_REQUIREMENTS = {};
      if (!window.DOC_REQUIREMENTS[productId]) window.DOC_REQUIREMENTS[productId] = {};
      window.DOC_REQUIREMENTS[productId][docId] = next;
      // persist to DB
      setTimeout(() => {
        window.apiFetch('/api/doc-requirements', {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ requirements: { [productId]: { [docId]: next } } }),
        }).catch(err => console.error('doc-req save:', err));
      }, 0);
      return { ...r, [productId]: { ...productReqs, [docId]: next } };
    });
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      {/* Tab switcher */}
      <div>
        <Segmented options={[
          { value: 'documents',  label: 'Document types',  icon: 'file'   },
          { value: 'categories', label: 'หมวดเอกสาร',      icon: 'tag'    },
        ]} value={tab} onChange={setTab}/>
      </div>

      {tab === 'categories' && (
        <DocCategoriesTab categories={categories} setCategories={setCategories}/>
      )}

      {tab === 'documents' && (<>
        {(() => {
          const docCats = ['all', ...[...new Set(liveProducts.map(p => p.category).filter(Boolean))].sort()];
          const filteredDocProducts = docCatFilter === 'all' ? liveProducts : liveProducts.filter(p => p.category === docCatFilter);
          return (<>
        {/* Category filter chips */}
        {docCats.length > 2 && (
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
            <span style={{ fontSize: 11, color: 'var(--ink-4)', marginRight: 2 }}>Category:</span>
            {docCats.map(cat => {
              const isActive = docCatFilter === cat;
              const count = cat === 'all' ? liveProducts.length : liveProducts.filter(p => p.category === cat).length;
              return (
                <button key={cat} onClick={() => setDocCatFilter(cat)} style={{
                  padding: '4px 10px', borderRadius: 20, fontSize: 11.5, cursor: 'pointer',
                  fontFamily: 'Kanit, sans-serif', fontWeight: isActive ? 700 : 500,
                  background: 'var(--bg-2)',
                  color: isActive ? 'var(--ink)' : 'var(--ink-3)',
                  border: `1.5px solid ${isActive ? 'var(--ink-2)' : 'var(--line)'}`,
                  boxShadow: isActive ? 'inset 0 0 0 1px var(--ink-2)' : 'none',
                  transition: 'all 0.12s',
                }}>
                  {cat === 'all' ? 'All' : cat}
                  <span style={{ marginLeft: 5, fontSize: 10, opacity: isActive ? 0.8 : 0.6 }}>{count}</span>
                </button>
              );
            })}
          </div>
        )}

        {/* Summary chips per product */}
        <div style={{ overflowX: 'auto', paddingBottom: 4 }}>
        <div style={{ display: 'flex', gap: 8, minWidth: 'min-content' }}>
          {filteredDocProducts.map(p => {
            const counts = docTypes.reduce((acc, d) => {
              const v = reqs[p.id]?.[d.id] || 'none';
              acc[v] = (acc[v] || 0) + 1;
              return acc;
            }, {});
            return (
              <div key={p.id} style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4, padding: 12, minWidth: 140, flexShrink: 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
                  <ProductGlyph productId={p.id} size={22}/>
                  <div style={{ fontSize: 12, fontWeight: 500 }}>{p.name}</div>
                </div>
                <div style={{ display: 'flex', gap: 4, fontSize: 10.5, flexWrap: 'wrap' }}>
                  <span className="num" style={{ padding: '2px 6px', background: 'var(--negative-bg)', color: 'var(--negative)', borderRadius: 2, fontWeight: 500 }}>
                    {counts.required || 0} required
                  </span>
                  <span className="num" style={{ padding: '2px 6px', background: '#fef3e8', color: '#d97b2e', borderRadius: 2 }}>
                    {counts.optional || 0} optional
                  </span>
                </div>
              </div>
            );
          })}
        </div>
        </div>

        {/* Requirement matrix */}
        <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
          <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <div>
              <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Document requirements per product</h3>
              <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>คลิกเซลล์เพื่อสลับสถานะ: Required → Optional → ไม่ต้องใช้</div>
            </div>
            <Button variant="ghost" size="sm" icon="download">Export rules</Button>
          </div>
          <div className="matrix-scroll" style={{ overflowX: 'auto', overflowY: 'visible' }}>
            <table style={{ width: '100%', minWidth: 300 + filteredDocProducts.length * 140, borderCollapse: 'collapse', fontSize: 12 }}>
              <thead>
                <tr style={{ background: 'var(--bg-2)' }}>
                  <th className="eyebrow" style={{ padding: '12px', textAlign: 'left', fontWeight: 500, borderBottom: '1px solid var(--line)', minWidth: 300, width: 300, position: 'sticky', left: 0, background: 'var(--bg-2)', zIndex: 2, boxShadow: '1px 0 0 var(--line)' }}>Document type</th>
                  {filteredDocProducts.map(p => (
                    <th key={p.id} className="eyebrow" style={{ padding: '12px 10px', textAlign: 'center', fontWeight: 500, borderBottom: '1px solid var(--line)', minWidth: 110 }}>
                      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4 }}>
                        <span style={{ width: 6, height: 6, borderRadius: '50%', background: p.color }}/>
                        <span>{p.name}</span>
                      </div>
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {docTypes.map((d, i) => {
                  const tagColor = tagColors[d.tag] || { bg: 'var(--bg-3)', fg: 'var(--ink-2)' };
                  return (
                    <tr key={d.id} style={{ borderBottom: i === docTypes.length - 1 ? 'none' : '1px solid var(--line-2)' }}>
                      <td style={{ padding: '10px 12px', position: 'sticky', left: 0, background: 'var(--panel)', zIndex: 1, width: 300, minWidth: 300, boxShadow: '1px 0 0 var(--line-2)' }}>
                        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>
                          <Icon name="file" size={14} color="var(--ink-3)"/>
                          <div style={{ flex: 1, minWidth: 0 }}>
                            <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
                              <span style={{ fontWeight: 500, fontSize: 12.5 }}>{d.label}</span>
                              <span style={{
                                padding: '1px 6px', background: tagColor.bg, color: tagColor.fg,
                                borderRadius: 2, fontSize: 9.5, fontWeight: 500, textTransform: 'uppercase', letterSpacing: '0.06em',
                              }}>{d.tag}</span>
                            </div>
                            <div style={{ fontSize: 10.5, color: 'var(--ink-3)', marginTop: 1 }}>{d.en} · <span className="num">{d.formats}</span> · max <span className="num">{d.maxMb} MB</span></div>
                            <div style={{ fontSize: 10.5, color: 'var(--ink-2)', marginTop: 2 }}>{d.desc}</div>
                          </div>
                          <button onClick={() => setEditing(d.id)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--ink-3)', padding: 2 }} title="Edit">
                            <Icon name="edit" size={11}/>
                          </button>
                        </div>
                      </td>
                      {filteredDocProducts.map(p => {
                        const v = reqs[p.id]?.[d.id] || 'none';
                        return (
                          <td key={p.id} style={{ padding: '10px', textAlign: 'center' }}>
                            <ReqCell value={v} onClick={() => cycle(p.id, d.id)}/>
                          </td>
                        );
                      })}
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
          <div style={{ padding: '10px 18px', borderTop: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: 8 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 14, fontSize: 11, color: 'var(--ink-3)', flexWrap: 'wrap' }}>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                <ReqCell value="required" small/>
                <span>Required · บังคับต้องแนบ</span>
              </span>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                <ReqCell value="optional" small/>
                <span>Optional · แนบเพิ่มเติมได้</span>
              </span>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                <ReqCell value="none" small/>
                <span>ไม่ต้องใช้</span>
              </span>
            </div>
            <Button variant="ghost" size="sm" icon="plus" onClick={() => setEditing('__new__')}>Add document type</Button>
          </div>
        </div>
          </>);
        })()}

        {editing && editing !== '__new__' && (() => {
          const editDoc = docTypes.find(d => d.id === editing);
          return editDoc ? (
            <DocTypeModal
              doc={editDoc}
              categories={categories}
              reqs={reqs}
              onClose={() => setEditing(null)}
              onSaved={(updated) => {
                const next = docTypes.map(d => d.id === updated.id ? updated : d);
                setDocTypes(next);
                window.DOC_TYPES = next;
                setEditing(null);
              }}
              onDeleted={(deletedId) => {
                const next = docTypes.filter(d => d.id !== deletedId);
                setDocTypes(next);
                window.DOC_TYPES = next;
                // remove from reqs state too
                setReqs(r => {
                  const updated = {};
                  for (const [pid, docs] of Object.entries(r)) {
                    const { [deletedId]: _, ...rest } = docs;
                    updated[pid] = rest;
                  }
                  return updated;
                });
                setEditing(null);
                showToast('ลบ document type แล้ว', { variant: 'success' });
              }}
            />
          ) : null;
        })()}
      </>)}
    </div>
  );
};

const ReqCell = ({ value, onClick, small }) => {
  const config = {
    required: { bg: '#fce8e4', fg: '#b8492f', label: 'Required' },
    optional: { bg: '#fef3e8', fg: '#d97b2e', label: 'Optional' },
    none:     { bg: 'transparent', fg: 'var(--ink-4)', label: '—' },
  }[value];
  if (small) {
    return (
      <span style={{
        display: 'inline-grid', placeItems: 'center',
        width: 14, height: 14, borderRadius: 2,
        background: config.bg, color: config.fg,
        fontSize: 9, fontWeight: 600,
        border: value === 'none' ? '1px dashed var(--line-3)' : 'none',
      }}>{value === 'required' ? '●' : value === 'optional' ? '○' : '—'}</span>
    );
  }
  return (
    <button onClick={onClick} title={`Click to cycle: ${config.label}`} style={{
      width: 80, padding: '5px 8px', borderRadius: 3, cursor: 'pointer',
      background: config.bg, color: config.fg,
      border: value === 'none' ? '1px dashed var(--line-3)' : 'none',
      fontFamily: 'Kanit, sans-serif', fontSize: 11, fontWeight: 500,
      transition: 'transform 120ms',
    }} onMouseDown={e => e.currentTarget.style.transform = 'scale(0.96)'}
       onMouseUp={e => e.currentTarget.style.transform = 'none'}
       onMouseLeave={e => e.currentTarget.style.transform = 'none'}>
      {config.label}
    </button>
  );
};

const FILE_EXTS = ['PDF', 'DOC', 'DOCX', 'XLS', 'XLSX', 'CSV', 'TXT', 'JPG', 'PNG', 'GIF', 'TIFF', 'WEBP', 'ZIP'];

const parseFormats = (str) =>
  (str || '').split(/[\s·,]+/).map(s => s.trim().toUpperCase()).filter(s => s.length > 0);

const serializeFormats = (arr) => arr.join(' · ');

const DocTypeModal = ({ doc, categories, reqs, onClose, onSaved, onDeleted }) => {
  const cats = (categories && categories.length)
    ? categories
    : Object.keys(DOC_TAG_COLORS_DEFAULT).map(k => ({ id: k, name: k }));
  const [form, setForm] = useState({
    label:   doc?.label   || '',
    en:      doc?.en      || '',
    tag:     doc?.tag     || cats[0]?.name || '',
    formats: parseFormats(doc?.formats || 'PDF · JPG · PNG'),
    maxMb:   doc?.maxMb   ?? 5,
    desc:    doc?.desc    || '',
  });
  const [saving, setSaving] = useState(false);
  const [deleting, setDeleting] = useState(false);
  const [confirmDelete, setConfirmDelete] = useState(false);
  const [err, setErr] = useState(null);
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  // count products using this doc type
  const usageCount = doc ? Object.values(reqs || {}).filter(docs => {
    const v = docs[doc.id];
    return v === 'required' || v === 'optional';
  }).length : 0;

  const handleDelete = async () => {
    setDeleting(true); setErr(null);
    try {
      const r = await window.apiFetch(`/api/doc-types/${doc.id}`, { method: 'DELETE' });
      const data = await r.json();
      if (!r.ok) { setErr(data.error || 'เกิดข้อผิดพลาด'); setDeleting(false); setConfirmDelete(false); return; }
      onDeleted(doc.id);
    } catch (e) { setErr('Network error: ' + e.message); setDeleting(false); }
  };

  const handleSave = async () => {
    if (!form.label.trim())      { setErr('กรุณากรอกชื่อเอกสาร'); return; }
    if (!form.tag)               { setErr('กรุณาเลือกหมวด');        return; }
    if (form.formats.length === 0) { setErr('กรุณาเลือกประเภทไฟล์ที่รองรับ'); return; }
    setSaving(true); setErr(null);
    try {
      const r = await window.apiFetch(`/api/doc-types/${doc.id}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ label: form.label.trim(), en: form.en.trim(), tag: form.tag, formats: serializeFormats(form.formats), maxMb: parseInt(form.maxMb)||5, desc: form.desc.trim() }),
      });
      const data = await r.json();
      if (!r.ok) { setErr(data.error || 'เกิดข้อผิดพลาด'); return; }
      showToast('บันทึกการแก้ไขแล้ว', { variant: 'success' });
      onSaved(data);
    } catch (e) { setErr('Network error: ' + e.message); }
    finally { setSaving(false); }
  };

  return (
    <Modal open={true}
      title="Edit document type"
      subtitle="แก้ไขรายละเอียดเอกสาร"
      onClose={onClose} width={540}
      footer={<>
        <div style={{ flex: 1 }}>
          {!confirmDelete ? (
            <Button variant="ghost" icon="trash"
              disabled={usageCount > 0}
              title={usageCount > 0 ? `ยังมี ${usageCount} product ใช้งานอยู่` : 'ลบ document type นี้'}
              onClick={() => setConfirmDelete(true)}
              style={{ color: usageCount > 0 ? 'var(--ink-4)' : 'var(--negative)' }}>
              Delete
            </Button>
          ) : (
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ fontSize: 12, color: 'var(--negative)', fontWeight: 500 }}>ยืนยันการลบ?</span>
              <Button variant="ghost" size="sm" onClick={() => setConfirmDelete(false)}>ยกเลิก</Button>
              <Button size="sm" disabled={deleting}
                onClick={handleDelete}
                style={{ background: 'var(--negative)', color: '#fff', border: 'none' }}>
                {deleting ? 'กำลังลบ…' : 'ยืนยันลบ'}
              </Button>
            </div>
          )}
        </div>
        <Button variant="ghost" onClick={onClose}>Cancel</Button>
        <Button variant="primary" icon="check" disabled={saving || confirmDelete} onClick={handleSave}>
          {saving ? 'กำลังบันทึก…' : 'Save changes'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
        {err && <div style={{ padding: '10px 14px', background: 'var(--negative-bg)', borderRadius: 3, fontSize: 12, color: 'var(--negative)', marginBottom: 10 }}>{err}</div>}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
          <Field label="ชื่อเอกสาร (ไทย)" required>
            <TextInput value={form.label} onChange={e => set('label', e.target.value)} placeholder="เช่น สำเนาบัตรประชาชน"/>
          </Field>
          <Field label="Document name (EN)" required>
            <TextInput value={form.en} onChange={e => set('en', e.target.value)} placeholder="e.g. ID card copy"/>
          </Field>
          <Field label="หมวด" required>
            <Select value={form.tag} onChange={e => set('tag', e.target.value)}>
              <option value="">— เลือกหมวด —</option>
              {cats.map(c => <option key={c.id} value={c.name}>{c.name}</option>)}
            </Select>
          </Field>
          <Field label="ขนาดสูงสุด (MB)">
            <TextInput type="number" value={form.maxMb} onChange={e => set('maxMb', e.target.value)} min={1}/>
          </Field>
          <div/>
          <div style={{ gridColumn: '1 / -1' }}>
          <Field label="ไฟล์ที่รองรับ">
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
              {FILE_EXTS.map(ext => {
                const selected = form.formats.includes(ext);
                return (
                  <button key={ext} type="button" onClick={() => {
                    set('formats', selected
                      ? form.formats.filter(e => e !== ext)
                      : [...form.formats, ext]
                    );
                  }} style={{
                    padding: '4px 10px', borderRadius: 4, fontSize: 11.5, cursor: 'pointer',
                    fontFamily: 'Kanit, sans-serif', fontWeight: selected ? 600 : 400,
                    background: selected ? 'var(--ink)' : 'var(--bg-2)',
                    color: selected ? 'var(--bg)' : 'var(--ink-3)',
                    border: `1.5px solid ${selected ? 'var(--ink)' : 'var(--line)'}`,
                    transition: 'all 0.1s',
                  }}>
                    {ext}
                  </button>
                );
              })}
            </div>
            {form.formats.length === 0 && (
              <div style={{ fontSize: 11, color: 'var(--negative)', marginTop: 4 }}>กรุณาเลือกอย่างน้อย 1 ประเภทไฟล์</div>
            )}
          </Field>
          </div>
          <div style={{ gridColumn: '1 / -1' }}>
            <Field label="คำอธิบาย / เงื่อนไข">
              <Textarea value={form.desc} onChange={e => set('desc', e.target.value)} placeholder="ระบุเงื่อนไข เช่น อายุไม่เกิน 6 เดือน" style={{ resize: 'vertical', minHeight: 72 }}/>
            </Field>
          </div>
        </div>
      </div>
    </Modal>
  );
};

// ---------- Condition Modal (Add / Edit) ----------
const ConditionModal = ({ cond, onClose, onSaved }) => {
  const isEdit   = !!cond;
  const isSystem = !!cond?.system;
  const [form, setForm] = useState({
    type:     cond?.type     || 'always',
    label:    cond?.label    || '',
    labelTh:  cond?.labelTh  || '',
    operator: cond?.operator || '>',
    value:    cond?.value    ?? '',
    value2:   cond?.value2   ?? '',
    status:   cond?.status   || 'live',
  });
  const [saving, setSaving] = useState(false);
  const [err, setErr]       = useState(null);
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const autoLabel = () => {
    const { type, operator, value, value2 } = form;
    if (type === 'always')   return 'Always';
    if (type === 'customer') return form.label || 'New customer';
    const prefix = type === 'mrr' ? 'MRR' : 'Contract';
    const unit   = type === 'mrr' ? '' : ' mo';
    if (operator === 'between') return `${prefix} ${value}–${value2}${unit}`;
    return `${prefix} ${operator} ${value}${unit}`;
  };

  const handleSave = async () => {
    const label = form.label.trim() || autoLabel();
    if (!label) { setErr('กรุณากรอกชื่อ condition'); return; }
    const payload = {
      type: form.type, label,
      labelTh: form.labelTh.trim(),
      operator: (form.type === 'always' || form.type === 'customer') ? null : form.operator,
      value:  (form.type !== 'always' && form.type !== 'customer') ? (parseFloat(form.value) || null) : null,
      value2: (form.type !== 'always' && form.type !== 'customer' && form.operator === 'between') ? (parseFloat(form.value2) || null) : null,
      status: form.status,
    };
    setSaving(true); setErr(null);
    try {
      const url = isEdit ? `/api/conditions/${cond.id}` : '/api/conditions';
      const r   = await window.apiFetch(url, {
        method: isEdit ? 'PATCH' : 'POST',
        body: JSON.stringify(payload),
      });
      const data = await r.json();
      if (!r.ok) { setErr(data.error || 'เกิดข้อผิดพลาด'); return; }
      showToast(isEdit ? 'บันทึก condition แล้ว' : 'เพิ่ม condition แล้ว', { variant: 'success' });
      onSaved(data);
    } catch(e) { setErr('Network error: ' + e.message); }
    finally { setSaving(false); }
  };

  const needsNumeric = form.type === 'mrr' || form.type === 'contract';
  const unit = form.type === 'mrr' ? '฿' : 'เดือน';

  return (
    <Modal open title={isEdit ? 'Edit condition' : 'Add condition'} onClose={onClose} width={460}
      footer={<>
        <Button variant="ghost" onClick={onClose}>Cancel</Button>
        <Button variant="primary" icon="check" disabled={saving} onClick={handleSave}>
          {saving ? 'กำลังบันทึก…' : 'Save'}
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {err && <div style={{ padding: '8px 12px', background: 'var(--negative-bg)', borderRadius: 3, fontSize: 12, color: 'var(--negative)' }}>{err}</div>}

        {isSystem && (
          <div style={{ padding: '8px 12px', background: 'var(--bg-3)', borderRadius: 3, fontSize: 11.5, color: 'var(--ink-3)', display: 'flex', alignItems: 'center', gap: 6 }}>
            <Icon name="info" size={11}/>
            System condition — ประเภทและเงื่อนไขไม่สามารถแก้ไขได้ แก้ได้เฉพาะ label และ status
          </div>
        )}

        <Field label="ประเภท Condition" required>
          <Select value={form.type} onChange={e => set('type', e.target.value)} disabled={isSystem}>
            {COND_TYPES.map(t => <option key={t.id} value={t.id}>{t.label} — {t.th}</option>)}
          </Select>
        </Field>

        {needsNumeric && (
          <div style={{ display: 'grid', gridTemplateColumns: form.operator === 'between' ? '1fr 1fr 1fr' : '1fr 1fr', gap: 10 }}>
            <Field label="Operator" required>
              <Select value={form.operator} onChange={e => set('operator', e.target.value)} disabled={isSystem}>
                {COND_OPERATORS.map(op => <option key={op} value={op}>{op}</option>)}
              </Select>
            </Field>
            <Field label={form.operator === 'between' ? `Min (${unit})` : `Value (${unit})`} required>
              <TextInput type="number" value={form.value} onChange={e => set('value', e.target.value)} placeholder="0" disabled={isSystem}/>
            </Field>
            {form.operator === 'between' && (
              <Field label={`Max (${unit})`} required>
                <TextInput type="number" value={form.value2} onChange={e => set('value2', e.target.value)} placeholder="0" disabled={isSystem}/>
              </Field>
            )}
          </div>
        )}

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
          <Field label="Label (EN)" required hint="ชื่อที่แสดงใน workflow">
            <TextInput value={form.label} onChange={e => set('label', e.target.value)}
              placeholder={autoLabel()} onFocus={e => { if (!form.label) set('label', autoLabel()); }}/>
          </Field>
          <Field label="Label (ไทย)">
            <TextInput value={form.labelTh} onChange={e => set('labelTh', e.target.value)} placeholder="เช่น MRR เกิน ฿50,000"/>
          </Field>
        </div>

        {isEdit && (
          <Field label="Status">
            <div style={{ display: 'flex', gap: 8 }}>
              {['live', 'disabled'].map(s => (
                <button key={s} type="button" onClick={() => set('status', s)} style={{
                  flex: 1, padding: '8px 0', borderRadius: 4, cursor: 'pointer', fontFamily: 'inherit',
                  fontSize: 12.5, fontWeight: form.status === s ? 600 : 400,
                  background: form.status === s ? (s === 'live' ? 'var(--positive-bg)' : 'var(--bg-3)') : 'var(--bg-2)',
                  color: form.status === s ? (s === 'live' ? 'var(--positive)' : 'var(--ink-3)') : 'var(--ink-3)',
                  border: `1.5px solid ${form.status === s ? (s === 'live' ? 'var(--positive)' : 'var(--ink-4)') : 'var(--line)'}`,
                }}>
                  {s === 'live' ? 'Live' : 'Disabled'}
                </button>
              ))}
            </div>
          </Field>
        )}
      </div>
    </Modal>
  );
};

// ---------- Conditions Tab ----------
const ConditionsTab = ({ conditions, setConditions }) => {
  const [addOpen,  setAddOpen]  = useState(false);
  const [editCond, setEditCond] = useState(null);
  const [delCond,  setDelCond]  = useState(null);
  const [deleting, setDeleting] = useState(false);

  const handleSaved = (saved) => {
    setConditions(prev => {
      const existing = prev.find(c => c.id === saved.id);
      if (existing) return prev.map(c => c.id === saved.id ? saved : c);
      return [...prev, saved];
    });
    window.CONDITIONS_DATA = conditions;
    setAddOpen(false); setEditCond(null);
  };

  // Soft-disable or re-enable a condition (no hard delete)
  const setCondStatus = async (cond, newStatus) => {
    try {
      const r = await window.apiFetch(`/api/conditions/${cond.id}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          label: cond.label, labelTh: cond.labelTh, type: cond.type,
          operator: cond.operator, value: cond.value, value2: cond.value2,
          status: newStatus,
        }),
      });
      const data = await r.json();
      if (!r.ok) { showToast(data.error || 'เกิดข้อผิดพลาด', { variant: 'error' }); return false; }
      setConditions(prev => prev.map(c => c.id === cond.id ? { ...c, status: newStatus } : c));
      return true;
    } catch(e) { showToast('Network error', { variant: 'error' }); return false; }
  };

  const handleDisable = async () => {
    if (!delCond) return;
    setDeleting(true);
    const ok = await setCondStatus(delCond, 'disabled');
    if (ok) showToast(`ปิดใช้งาน "${delCond.label}" แล้ว`, { variant: 'success' });
    setDelCond(null);
    setDeleting(false);
  };

  const handleEnable = async (c) => {
    const ok = await setCondStatus(c, 'live');
    if (ok) showToast(`เปิดใช้งาน "${c.label}" แล้ว`, { variant: 'success' });
  };

  const typeLabel = (type) => COND_TYPES.find(t => t.id === type)?.label || type;

  const condSummary = (c) => {
    if (c.type === 'always' || c.type === 'customer') return '—';
    const unit = c.type === 'mrr' ? '' : ' mo';
    if (c.operator === 'between') return `${c.operator} ${fmtCondValue(c.value)} – ${fmtCondValue(c.value2)}${unit}`;
    return `${c.operator} ${fmtCondValue(c.value)}${unit}`;
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      {/* Header */}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div>
          <div style={{ fontSize: 13.5, fontWeight: 600 }}>Approval Conditions</div>
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 2 }}>กำหนดเงื่อนไขที่ใช้ใน workflow ของแต่ละขั้น</div>
        </div>
        <Button variant="primary" icon="plus" size="sm" onClick={() => setAddOpen(true)}>Add condition</Button>
      </div>

      {/* Table */}
      <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4, overflow: 'hidden' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
          <thead>
            <tr style={{ background: 'var(--bg-2)', borderBottom: '1px solid var(--line)' }}>
              <th style={{ padding: '10px 14px', textAlign: 'left', fontWeight: 500, fontSize: 11 }}>Label</th>
              <th style={{ padding: '10px 10px', textAlign: 'left', fontWeight: 500, fontSize: 11 }}>ไทย</th>
              <th style={{ padding: '10px 10px', textAlign: 'left', fontWeight: 500, fontSize: 11 }}>Type</th>
              <th style={{ padding: '10px 10px', textAlign: 'left', fontWeight: 500, fontSize: 11 }}>Logic</th>
              <th style={{ padding: '10px 10px', textAlign: 'center', fontWeight: 500, fontSize: 11 }}>Status</th>
              <th style={{ padding: '10px 14px', textAlign: 'right', fontWeight: 500, fontSize: 11 }}></th>
            </tr>
          </thead>
          <tbody>
            {conditions.length === 0 && (
              <tr><td colSpan={6} style={{ padding: 24, textAlign: 'center', color: 'var(--ink-4)', fontSize: 12 }}>ยังไม่มี condition</td></tr>
            )}
            {conditions.map((c, i) => {
              const isDisabled = c.status === 'disabled';
              return (
              <tr key={c.id} style={{
                borderBottom: i === conditions.length - 1 ? 'none' : '1px solid var(--line-2)',
                background: isDisabled ? 'repeating-linear-gradient(135deg, var(--bg-2) 0px, var(--bg-2) 6px, var(--bg-3) 6px, var(--bg-3) 7px)' : 'transparent',
              }}>
                <td style={{ padding: '10px 14px', fontWeight: 500 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
                    <span style={{ color: isDisabled ? 'var(--ink-4)' : 'inherit', textDecoration: isDisabled ? 'line-through' : 'none' }}>
                      {c.label}
                    </span>
                    {c.system && <span style={{ fontSize: 9.5, color: isDisabled ? 'var(--ink-4)' : 'var(--brand)', background: isDisabled ? 'var(--bg-3)' : 'var(--brand-bg, #eef2ff)', borderRadius: 3, padding: '1px 5px' }}>system</span>}
                  </div>
                </td>
                <td style={{ padding: '10px 10px', color: isDisabled ? 'var(--ink-4)' : 'var(--ink-2)', textDecoration: isDisabled ? 'line-through' : 'none' }}>{c.labelTh || '—'}</td>
                <td style={{ padding: '10px 10px', opacity: isDisabled ? 0.45 : 1 }}>
                  <span style={{ background: 'var(--bg-3)', borderRadius: 3, padding: '2px 7px', fontSize: 11 }}>{typeLabel(c.type)}</span>
                </td>
                <td style={{ padding: '10px 10px', fontFamily: 'IBM Plex Mono', fontSize: 11.5, color: isDisabled ? 'var(--ink-4)' : 'var(--ink-2)' }}>{condSummary(c)}</td>
                <td style={{ padding: '10px 10px', textAlign: 'center' }}>
                  {isDisabled
                    ? <span style={{ fontSize: 10.5, color: 'var(--ink-3)', background: 'var(--bg-3)', border: '1px solid var(--line-3)', borderRadius: 3, padding: '2px 8px', fontWeight: 500 }}>Disabled</span>
                    : <span style={{ fontSize: 10.5, color: 'var(--positive)', background: 'var(--positive-bg)', border: '1px solid var(--positive)', borderRadius: 3, padding: '2px 8px', fontWeight: 500 }}>Live</span>
                  }
                </td>
                <td style={{ padding: '10px 14px', textAlign: 'right' }}>
                  <div style={{ display: 'flex', gap: 6, justifyContent: 'flex-end' }}>
                    {!isDisabled && <Button variant="ghost" size="sm" icon="edit" onClick={() => setEditCond(c)}>Edit</Button>}
                    {isDisabled
                      ? <Button variant="ghost" size="sm" onClick={() => handleEnable(c)}
                          style={{ color: 'var(--positive)', fontSize: 11.5 }}>
                          ✓ Enable
                        </Button>
                      : !c.system && (
                          <Button variant="ghost" size="sm" onClick={() => setDelCond(c)}
                            style={{ color: 'var(--ink-3)', fontSize: 11.5 }}>
                            ⊘ Disable
                          </Button>
                        )
                    }
                  </div>
                </td>
              </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {/* Add modal */}
      {addOpen  && <ConditionModal onClose={() => setAddOpen(false)}  onSaved={handleSaved}/>}
      {editCond && <ConditionModal cond={editCond} onClose={() => setEditCond(null)} onSaved={handleSaved}/>}

      {/* Disable confirm */}
      {delCond && (
        <Modal open title="ปิดใช้งาน condition?" onClose={() => setDelCond(null)} width={400}
          footer={<>
            <Button variant="ghost" onClick={() => setDelCond(null)}>Cancel</Button>
            <Button variant="primary" disabled={deleting} onClick={handleDisable}
              style={{ background: 'var(--ink-2)', borderColor: 'var(--ink-2)' }}>
              {deleting ? 'กำลังปิด…' : '⊘ Disable'}
            </Button>
          </>}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            <div style={{ fontSize: 13 }}>
              ต้องการปิดใช้งาน <strong>{delCond.label}</strong> ใช่หรือไม่?
            </div>
            <div style={{ fontSize: 11.5, color: 'var(--ink-3)', display: 'flex', alignItems: 'center', gap: 5 }}>
              <Icon name="info" size={11}/>
              Condition จะถูก disabled แต่ไม่ถูกลบออกจากระบบ สามารถเปิดใช้งานใหม่ได้ทุกเมื่อ
            </div>
          </div>
        </Modal>
      )}
    </div>
  );
};

// ---------- Workflow setting ----------
const ROLE_COLORS = {
  'Sales Lead':          '#3a6b8a',
  'Solution Manager':    '#2d3a8c',
  'Finance Manager':     '#1f7a4d',
  'Security Officer':    '#6b4a8a',
  'Legal Counsel':       '#a8553a',
  'CTO':                 '#d97b2e',
  'Account Manager':     '#8b8f99',
  'Solution Engineer':   '#8b8f99',
  'Customer Success':    '#8b8f99',
};
const roleColor = (role) => ROLE_COLORS[role] || 'var(--ink-3)';
const getUser = (id) => USERS.find(u => u.id === id);

// Fallback static conditions (used until API conditions load)
const CONDITIONS_FALLBACK = {
  always:           { label: 'Always',           th: 'ทุกคำสั่งซื้อ' },
  mrr_gt_50k:       { label: 'MRR > ฿50K',       th: 'MRR เกิน ฿50,000' },
  mrr_gt_200k:      { label: 'MRR > ฿200K',      th: 'MRR เกิน ฿200,000' },
  mrr_gt_500k:      { label: 'MRR > ฿500K',      th: 'MRR เกิน ฿500,000' },
  new_customer:     { label: 'New customer',     th: 'ลูกค้าใหม่' },
  contract_gt_24mo: { label: 'Contract ≥ 24 mo', th: 'สัญญา ≥ 24 เดือน' },
};

// condLabel / condLabelTh — safe lookup against live conditions array
const condLabel   = (condId, conditions) => {
  if (!condId) return 'Always';
  const c = (conditions || []).find(x => x.id === condId);
  if (c) return c.label;
  return CONDITIONS_FALLBACK[condId]?.label || condId;
};
const condLabelTh = (condId, conditions) => {
  if (!condId) return 'ทุกคำสั่งซื้อ';
  const c = (conditions || []).find(x => x.id === condId);
  if (c) return c.labelTh;
  return CONDITIONS_FALLBACK[condId]?.th || '';
};

// Format a numeric MRR/contract value nicely
const fmtCondValue = (v) => {
  if (v == null) return '';
  if (v >= 1000000) return '฿' + (v/1000000).toLocaleString() + 'M';
  if (v >= 1000)    return '฿' + (v/1000).toLocaleString() + 'K';
  return String(v);
};

const COND_TYPES = [
  { id: 'always',   label: 'Always',   th: 'ทุกคำสั่งซื้อ' },
  { id: 'mrr',      label: 'MRR',      th: 'Monthly Recurring Revenue' },
  { id: 'customer', label: 'Customer', th: 'ประเภทลูกค้า' },
  { id: 'contract', label: 'Contract', th: 'ระยะสัญญา (เดือน)' },
];
const COND_OPERATORS = ['>', '<', '=', '>=', '<=', 'between'];

// DEFAULT_WORKFLOWS is a window global set by data.js / /api/init

const SettingsWorkflowView = () => {
  const _initLive = (window.PRODUCTS || PRODUCTS).filter(p => p.status !== 'deleted');
  const [liveProducts, setLiveProducts] = useState(_initLive);
  const [activeProductId, setActiveProductId] = useState(_initLive[0]?.id || PRODUCTS[0].id);
  const [workflows, setWorkflows] = useState(DEFAULT_WORKFLOWS);
  const [editingStage, setEditingStage] = useState(null);  // { productId, stageIdx }
  const [wfTab, setWfTab] = useState('workflow');           // 'workflow' | 'conditions'
  const [conditions, setConditions] = useState(window.CONDITIONS_DATA || []);
  const [catFilter, setCatFilter] = useState('all');         // 'all' | category string
  const [compCatFilter, setCompCatFilter] = useState('all'); // filter for comparison table
  const [wfUsers, setWfUsers] = useState(window.USERS || []);

  useEffect(() => {
    // Fetch fresh workflow data from DB (DEFAULT_WORKFLOWS in data.js only has legacy products)
    window.apiFetch('/api/workflows').then(r => r.ok ? r.json() : null)
      .then(data => {
        if (data) {
          setWorkflows(data);
          window.DEFAULT_WORKFLOWS = data;
        }
      }).catch(() => {});

    window.apiFetch('/api/products').then(r => r.ok ? r.json() : null)
      .then(data => {
        if (data) {
          window.PRODUCTS = data;
          const live = data.filter(p => p.status !== 'deleted');
          setLiveProducts(live);
          setActiveProductId(prev => live.find(p => p.id === prev) ? prev : (live[0]?.id || prev));
        }
      }).catch(() => {});

    window.apiFetch('/api/conditions').then(r => r.ok ? r.json() : null)
      .then(data => {
        if (data) { setConditions(data); window.CONDITIONS_DATA = data; }
      }).catch(() => {});

    window.apiFetch('/api/users').then(r => r.ok ? r.json() : null)
      .then(data => {
        if (data) { window.USERS = data; setWfUsers(data); }
      }).catch(() => {});
  }, []);

  const activeProduct = liveProducts.find(p => p.id === activeProductId) || liveProducts[0] || PRODUCTS[0];
  const flow = workflows[activeProductId] || [];

  const setFlow = (newFlow) => setWorkflows(w => ({ ...w, [activeProductId]: newFlow }));

  // Persist a product's workflow stages to the DB
  const saveWorkflow = async (productId, stages) => {
    try {
      const r = await window.apiFetch(`/api/workflows/${productId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ stages }),
      });
      if (!r.ok) { const e = await r.json(); showToast(e.error || 'บันทึก workflow ไม่ได้', { variant: 'error' }); return false; }
      // Refresh global workflow cache so SLA timelines reflect the change immediately
      window.apiFetch('/api/workflows').then(r => r.ok ? r.json() : null)
        .then(d => { if (d) window.DEFAULT_WORKFLOWS = d; }).catch(() => {});
      return true;
    } catch { showToast('เกิดข้อผิดพลาด', { variant: 'error' }); return false; }
  };

  const addStage = async () => {
    const firstUser = wfUsers.find(u => (u.status || 'active') !== 'disabled');
    const newFlow = [...flow, { approver: firstUser ? String(firstUser.id) : '', condition: 'always', slaH: 24 }];
    setFlow(newFlow);
    const ok = await saveWorkflow(activeProductId, newFlow);
    if (ok) showToast('เพิ่ม stage แล้ว', { variant: 'success' });
  };
  const moveStage = async (idx, dir) => {
    const ni = idx + dir;
    if (ni < 0 || ni >= flow.length) return;
    const next = [...flow];
    [next[idx], next[ni]] = [next[ni], next[idx]];
    setFlow(next);
    await saveWorkflow(activeProductId, next);
  };
  const removeStage = async (idx) => {
    const newFlow = flow.filter((_, i) => i !== idx);
    setFlow(newFlow);
    const ok = await saveWorkflow(activeProductId, newFlow);
    if (ok) showToast('ลบ stage แล้ว', { variant: 'success' });
  };
  const updateStage = (idx, patch) => setFlow(flow.map((s, i) => i === idx ? { ...s, ...patch } : s));

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      {/* Tab bar */}
      <div style={{ display: 'flex', gap: 2, borderBottom: '2px solid var(--line)', paddingBottom: 0 }}>
        {[{ id: 'workflow', label: 'Workflow', icon: 'sparkles' }, { id: 'conditions', label: 'Conditions', icon: 'filter' }].map(t => (
          <button key={t.id} onClick={() => setWfTab(t.id)} style={{
            background: 'none', border: 'none', cursor: 'pointer', fontFamily: 'inherit',
            padding: '8px 16px', fontSize: 13, fontWeight: wfTab === t.id ? 600 : 400,
            color: wfTab === t.id ? 'var(--brand)' : 'var(--ink-3)',
            borderBottom: wfTab === t.id ? '2px solid var(--brand)' : '2px solid transparent',
            marginBottom: -2, display: 'flex', alignItems: 'center', gap: 6,
          }}>
            <Icon name={t.icon} size={13}/>
            {t.label}
          </button>
        ))}
      </div>

      {/* ── Conditions Tab ── */}
      {wfTab === 'conditions' && (
        <ConditionsTab conditions={conditions} setConditions={setConditions}/>
      )}

      {/* ── Workflow Tab ── */}
      {wfTab === 'workflow' && <>

      {/* Category filter chips */}
      {(() => {
        const cats = ['all', ...[...new Set(liveProducts.map(p => p.category).filter(Boolean))].sort()];
        const filteredProducts = catFilter === 'all' ? liveProducts : liveProducts.filter(p => p.category === catFilter);
        return (
          <>
          {cats.length > 2 && (
            <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
              <span style={{ fontSize: 11, color: 'var(--ink-4)', marginRight: 2 }}>Category:</span>
              {cats.map(cat => {
                const isActive = catFilter === cat;
                const count = cat === 'all' ? liveProducts.length : liveProducts.filter(p => p.category === cat).length;
                return (
                  <button key={cat} onClick={() => {
                    setCatFilter(cat);
                    // If active product not in new filter, switch to first match
                    const filtered = cat === 'all' ? liveProducts : liveProducts.filter(p => p.category === cat);
                    if (!filtered.find(p => p.id === activeProductId) && filtered.length > 0) {
                      setActiveProductId(filtered[0].id);
                    }
                  }} style={{
                    padding: '4px 10px', borderRadius: 20, fontSize: 11.5, cursor: 'pointer',
                    fontFamily: 'Kanit, sans-serif', fontWeight: isActive ? 700 : 500,
                    background: 'var(--bg-2)',
                    color: isActive ? 'var(--ink)' : 'var(--ink-3)',
                    border: `1.5px solid ${isActive ? 'var(--ink-2)' : 'var(--line)'}`,
                    boxShadow: isActive ? 'inset 0 0 0 1px var(--ink-2)' : 'none',
                    transition: 'all 0.12s',
                  }}>
                    {cat === 'all' ? 'All' : cat}
                    <span style={{ marginLeft: 5, fontSize: 10, opacity: isActive ? 0.8 : 0.6 }}>{count}</span>
                  </button>
                );
              })}
            </div>
          )}
          {/* Summary strip */}
          <div style={{ overflowX: 'auto', paddingBottom: 4 }}>
          <div style={{ display: 'flex', gap: 8, minWidth: 'min-content' }}>
            {filteredProducts.map(p => {
          const wf = workflows[p.id] || [];
          const isActive = p.id === activeProductId;
          return (
            <button key={p.id} onClick={() => setActiveProductId(p.id)} style={{
              background: isActive ? 'var(--panel)' : 'var(--bg-2)',
              border: `1px solid ${isActive ? p.color : 'var(--line)'}`,
              borderRadius: 4, padding: 12, cursor: 'pointer', textAlign: 'left',
              fontFamily: 'Kanit, sans-serif',
              boxShadow: isActive ? 'var(--shadow-segment)' : 'none',
              position: 'relative', overflow: 'hidden',
              minWidth: 140, flexShrink: 0,
            }}>
              {isActive && <div style={{ position: 'absolute', top: 0, left: 0, width: 3, height: '100%', background: p.color }}/>}
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8, paddingLeft: isActive ? 4 : 0 }}>
                <ProductGlyph productId={p.id} size={22}/>
                <div style={{ fontSize: 12, fontWeight: 500 }}>{p.name}</div>
              </div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, paddingLeft: isActive ? 4 : 0 }}>
                <span className="num" style={{ fontSize: 18, fontWeight: 500, letterSpacing: '-0.02em' }}>{wf.length}</span>
                <span style={{ fontSize: 10.5, color: 'var(--ink-3)' }}>approval stage{wf.length !== 1 ? 's' : ''}</span>
              </div>
            </button>
          );
            })}
          </div>
          </div>
          </>
        );
      })()}

      {/* Active workflow editor */}
      <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <ProductGlyph productId={activeProduct.id} size={28}/>
            <div>
              <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Approval workflow · {activeProduct.name}</h3>
              <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>กำหนดลำดับการอนุมัติของ {activeProduct.nameTh}</div>
            </div>
          </div>
          <Button variant="ghost" size="sm" icon="plus" onClick={addStage}>Add stage</Button>
        </div>

        {/* Flow canvas */}
        <div style={{ padding: '20px 18px', background: 'var(--bg-2)', overflowX: 'auto' }} className="matrix-scroll">
          {flow.length === 0 ? (
            <Empty icon="sparkles" title="ยังไม่มีขั้นตอนอนุมัติ" hint="คลิก Add stage เพื่อสร้างขั้นแรก"/>
          ) : (
            <div style={{ display: 'flex', alignItems: 'stretch', gap: 8, minWidth: 'min-content' }}>
              {/* Submitted node (always first) */}
              <FlowEndCap icon="plus" label="Order submitted" subLabel="คำสั่งซื้อถูกส่ง" color="var(--ink)" filled/>
              <FlowArrow/>
              {flow.map((stage, idx) => (
                <React.Fragment key={stage.id}>
                  <StageCard
                    stage={stage} idx={idx} total={flow.length}
                    conditions={conditions} users={wfUsers}
                    onEdit={() => setEditingStage({ productId: activeProductId, idx })}
                    onMove={(dir) => moveStage(idx, dir)}
                    onRemove={() => removeStage(idx)}
                    onUpdate={(patch) => updateStage(idx, patch)}/>
                  <FlowArrow/>
                </React.Fragment>
              ))}
              <FlowEndCap icon="check" label="Approved" subLabel="พร้อม provisioning" color="var(--positive)" filled/>
            </div>
          )}
        </div>

        {/* Footer rules */}
        <div style={{ padding: '12px 18px', borderTop: '1px solid var(--line)', display: 'flex', alignItems: 'center', gap: 24, flexWrap: 'wrap' }}>
          <RuleInline icon="info"  text="ขั้นที่มีเงื่อนไขเฉพาะจะถูกข้ามอัตโนมัติเมื่อไม่ตรงเงื่อนไข"/>
          <RuleInline icon="clock" text="SLA นับจากเวลาที่ผู้อนุมัติได้รับ — เกินเวลา ระบบจะส่ง escalation"/>
          <RuleInline icon="alert" text="ผู้สมัครและผู้อนุมัติคนเดียวกันจะข้ามขั้นนั้นโดยอัตโนมัติ"/>
        </div>
      </div>

      {/* Compare across products */}
      <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)' }}>
          <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Cross-product comparison</h3>
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>เปรียบเทียบ workflow ของแต่ละ product</div>
        </div>
        {(() => {
          const compCats = ['all', ...[...new Set(liveProducts.map(p => p.category).filter(Boolean))].sort()];
          const compFiltered = compCatFilter === 'all' ? liveProducts : liveProducts.filter(p => p.category === compCatFilter);
          return (<>
            {compCats.length > 2 && (
              <div style={{ padding: '10px 18px 0', display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
                <span style={{ fontSize: 11, color: 'var(--ink-4)', marginRight: 2 }}>Category:</span>
                {compCats.map(cat => {
                  const isActive = compCatFilter === cat;
                  const count = cat === 'all' ? liveProducts.length : liveProducts.filter(p => p.category === cat).length;
                  return (
                    <button key={cat} onClick={() => setCompCatFilter(cat)} style={{
                      padding: '4px 10px', borderRadius: 20, fontSize: 11.5, cursor: 'pointer',
                      fontFamily: 'Kanit, sans-serif', fontWeight: isActive ? 700 : 500,
                      background: 'var(--bg-2)',
                      color: isActive ? 'var(--ink)' : 'var(--ink-3)',
                      border: `1.5px solid ${isActive ? 'var(--ink-2)' : 'var(--line)'}`,
                      boxShadow: isActive ? 'inset 0 0 0 1px var(--ink-2)' : 'none',
                      transition: 'all 0.12s',
                    }}>
                      {cat === 'all' ? 'All' : cat}
                      <span style={{ marginLeft: 5, fontSize: 10, opacity: isActive ? 0.8 : 0.6 }}>{count}</span>
                    </button>
                  );
                })}
              </div>
            )}
        <div className="matrix-scroll" style={{ overflowX: 'auto', marginTop: compCats.length > 2 ? 10 : 0 }}>
          <table style={{ width: '100%', minWidth: 980, borderCollapse: 'collapse', fontSize: 12 }}>
            <thead>
              <tr style={{ background: 'var(--bg-2)' }}>
                <th className="eyebrow" style={{ padding: '12px', textAlign: 'left', fontWeight: 500, borderBottom: '1px solid var(--line)', minWidth: 180, width: 180 }}>Product</th>
                {[1,2,3,4,5].map(n => (
                  <th key={n} className="eyebrow" style={{ padding: '12px 8px', textAlign: 'center', fontWeight: 500, borderBottom: '1px solid var(--line)', minWidth: 160 }}>Stage {n}</th>
                ))}
                <th className="eyebrow" style={{ padding: '12px', textAlign: 'right', fontWeight: 500, borderBottom: '1px solid var(--line)' }}>Total SLA</th>
              </tr>
            </thead>
            <tbody>
              {compFiltered.map((p, i) => {
                const wf = workflows[p.id] || [];
                const totalSla = wf.reduce((s, x) => s + x.slaH, 0);
                return (
                  <tr key={p.id} style={{ borderBottom: i === compFiltered.length - 1 ? 'none' : '1px solid var(--line-2)' }}>
                    <td style={{ padding: '10px 12px' }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                        <ProductGlyph productId={p.id} size={22}/>
                        <span style={{ fontSize: 12.5, fontWeight: 500 }}>{p.name}</span>
                      </div>
                    </td>
                    {[0,1,2,3,4].map(n => {
                      const stage = wf[n];
                      if (!stage) return <td key={n} style={{ padding: '10px 8px', textAlign: 'center', color: 'var(--ink-4)' }}>—</td>;
                      const user = wfUsers.find(u => String(u.id) === String(stage.approver)) || { name: '?', role: '—' };
                      const color = roleColor(user.role);
                      return (
                        <td key={n} style={{ padding: '10px 8px', textAlign: 'center' }}>
                          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '3px 8px 3px 4px', background: 'var(--bg-2)', borderRadius: 2, maxWidth: 180 }}>
                            <Avatar name={user.name} size={18}/>
                            <div style={{ textAlign: 'left', minWidth: 0 }}>
                              <div style={{ fontSize: 11, fontWeight: 500, lineHeight: 1.2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{user.name}</div>
                              <div style={{ fontSize: 9.5, color, lineHeight: 1.2 }}>{user.role}</div>
                            </div>
                          </div>
                          {stage.condition !== 'always' && (
                            <div style={{ fontSize: 9.5, color: 'var(--ink-3)', marginTop: 2 }}>
                              if {condLabel(stage.condition, conditions)}
                            </div>
                          )}
                        </td>
                      );
                    })}
                    <td className="num" style={{ padding: '10px 12px', textAlign: 'right', fontWeight: 500 }}>
                      {totalSla}<span style={{ fontSize: 10, color: 'var(--ink-3)', marginLeft: 3, fontWeight: 400 }}>h</span>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
          </>);
        })()}
      </div>

      {/* Edit modal */}
      <Modal open={!!editingStage}
        title="Edit approval stage"
        subtitle={editingStage && `${(liveProducts.find(p => p.id === editingStage.productId) || {name: ''}).name} · Stage ${editingStage.idx + 1}`}
        onClose={() => setEditingStage(null)} width={520}
        footer={<>
          <Button variant="ghost" onClick={() => setEditingStage(null)}>Cancel</Button>
          <Button variant="primary" icon="check" onClick={async () => {
            const pId = editingStage.productId;
            const ok = await saveWorkflow(pId, workflows[pId]);
            if (ok) showToast('บันทึก workflow แล้ว', { variant: 'success' });
            setEditingStage(null);
          }}>Save changes</Button>
        </>}>
        {editingStage && (() => {
          const stage = workflows[editingStage.productId][editingStage.idx];
          // Group users by team for clarity in the picker
          const activeUsers = wfUsers.filter(u => (u.status || 'active') !== 'disabled');
          const usersByTeam = activeUsers.reduce((acc, u) => {
            const team = u.team || 'Others';
            (acc[team] = acc[team] || []).push(u);
            return acc;
          }, {});
          const currentUser = wfUsers.find(u => String(u.id) === String(stage.approver));
          return (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              {/* Approver picker */}
              <Field label="Approver" required hint="เลือกผู้อนุมัติจากรายชื่อผู้ใช้ระบบ">
                <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 10px', background: 'var(--bg-2)', borderRadius: 3, marginBottom: 8 }}>
                  <Avatar name={currentUser?.name || '?'} size={32}/>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 13, fontWeight: 500 }}>{currentUser?.name || 'Unassigned'}</div>
                    <div style={{ fontSize: 11, color: roleColor(currentUser?.role) }}>{currentUser?.role}</div>
                  </div>
                  <div className="num" style={{ fontSize: 10.5, color: 'var(--ink-3)' }}>{currentUser?.email}</div>
                </div>
                <Select value={stage.approver} onChange={e => updateStage(editingStage.idx, { approver: e.target.value })}>
                  {Object.entries(usersByTeam).map(([team, users]) => (
                    <optgroup key={team} label={team}>
                      {users.map(u => (
                        <option key={u.id} value={u.id}>{u.name} — {u.role}</option>
                      ))}
                    </optgroup>
                  ))}
                </Select>
              </Field>

              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
                <Field label="Condition" hint="ขั้นนี้จะถูกใช้เมื่อ…">
                  <Select value={stage.condition}
                    onChange={e => updateStage(editingStage.idx, { condition: e.target.value })}>
                    {(conditions.length > 0 ? conditions : Object.entries(CONDITIONS_FALLBACK).map(([k,v]) => ({ id: k, label: v.label, labelTh: v.th }))).map(c => (
                      <option key={c.id} value={c.id}>{c.label}{c.labelTh ? ' — ' + c.labelTh : ''}</option>
                    ))}
                  </Select>
                </Field>
                <Field label="SLA (hours)" required>
                  <TextInput type="number" value={stage.slaH}
                    onChange={e => updateStage(editingStage.idx, { slaH: parseInt(e.target.value) || 0 })}/>
                </Field>
                <Field label="Backup approver" hint="สำรองเมื่อ Approver ไม่ว่า">
                  <Select defaultValue="">
                    <option value="">— ไม่ระบุ —</option>
                    {activeUsers.filter(u => u.id !== stage.approver).map(u => (
                      <option key={u.id} value={u.id}>{u.name} — {u.role}</option>
                    ))}
                  </Select>
                </Field>
                <Field label="Escalation" hint="เกิน SLA จะส่งต่อ">
                  <Select defaultValue="manager">
                    <option value="manager">Direct manager</option>
                    <option value="cto">CTO Office</option>
                    <option value="none">No escalation</option>
                  </Select>
                </Field>
              </div>
              <Field label="Internal note">
                <Textarea defaultValue={`Approve ${(liveProducts.find(p => p.id === editingStage.productId) || activeProduct).name} order — verify pricing and contract terms`}/>
              </Field>
            </div>
          );
        })()}
      </Modal>
      </>}
    </div>
  );
};

const StageCard = ({ stage, idx, total, onEdit, onMove, onRemove, onUpdate, conditions, users }) => {
  const _allUsers = users && users.length ? users : (window.USERS || []);
  const user = _allUsers.find(u => String(u.id) === String(stage.approver)) || { name: 'Unassigned', role: '—' };
  const color = roleColor(user.role);
  const cLabel   = condLabel(stage.condition, conditions);
  const cLabelTh = condLabelTh(stage.condition, conditions);
  return (
    <div style={{
      background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4,
      width: 240, minWidth: 240, padding: 14, display: 'flex', flexDirection: 'column', gap: 10,
      position: 'relative',
    }}>
      {/* Stage badge */}
      <div style={{
        position: 'absolute', top: -8, left: 12,
        background: color, color: '#fff',
        padding: '2px 8px', borderRadius: 2,
        fontSize: 10, fontWeight: 600, letterSpacing: '0.06em', textTransform: 'uppercase', fontFamily: 'IBM Plex Mono',
      }}>Stage {idx + 1}</div>

      {/* Move controls */}
      <div style={{ position: 'absolute', top: 8, right: 8, display: 'flex', gap: 2 }}>
        <button onClick={() => onMove(-1)} disabled={idx === 0}
          style={{ ...stageBtn, opacity: idx === 0 ? 0.3 : 1, cursor: idx === 0 ? 'not-allowed' : 'pointer' }} title="Move left">
          <Icon name="chevronLeft" size={10}/>
        </button>
        <button onClick={() => onMove(1)} disabled={idx === total - 1}
          style={{ ...stageBtn, opacity: idx === total - 1 ? 0.3 : 1, cursor: idx === total - 1 ? 'not-allowed' : 'pointer' }} title="Move right">
          <Icon name="chevron" size={10}/>
        </button>
      </div>

      {/* Approver user */}
      <div style={{ marginTop: 6 }}>
        <div className="eyebrow" style={{ fontSize: 9.5, marginBottom: 6 }}>Approver</div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <Avatar name={user.name} size={28}/>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 12.5, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{user.name}</div>
            <div style={{ fontSize: 10.5, color }}>{user.role}</div>
          </div>
        </div>
      </div>

      {/* Condition */}
      <div>
        <div className="eyebrow" style={{ fontSize: 9.5, marginBottom: 4 }}>Trigger</div>
        <div style={{ fontSize: 11.5, color: 'var(--ink)', fontWeight: stage.condition === 'always' ? 400 : 500 }}>
          {cLabel}
        </div>
        <div style={{ fontSize: 10.5, color: 'var(--ink-3)' }}>{cLabelTh}</div>
      </div>

      {/* SLA */}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', borderTop: '1px solid var(--line-2)', paddingTop: 8 }}>
        <div>
          <div className="eyebrow" style={{ fontSize: 9.5 }}>SLA</div>
          <div className="num" style={{ fontSize: 16, fontWeight: 500, letterSpacing: '-0.01em' }}>
            {stage.slaH}<span style={{ fontSize: 10, color: 'var(--ink-3)', marginLeft: 2, fontWeight: 400 }}>h</span>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 4 }}>
          <button onClick={onEdit} style={stageBtn} title="Edit"><Icon name="edit" size={11}/></button>
          <button onClick={onRemove} style={{ ...stageBtn, color: 'var(--negative)' }} title="Remove"><Icon name="close" size={11}/></button>
        </div>
      </div>
    </div>
  );
};

const stageBtn = {
  width: 22, height: 22, padding: 0,
  background: 'var(--bg-2)', border: 'none', borderRadius: 3,
  cursor: 'pointer', color: 'var(--ink-2)',
  display: 'grid', placeItems: 'center',
};

const FlowEndCap = ({ icon, label, subLabel, color, filled }) => (
  <div style={{
    background: filled ? color : 'var(--panel)',
    color: filled ? '#fff' : color,
    border: `1px solid ${color}`, borderRadius: 4,
    padding: '14px 16px', minWidth: 130, display: 'flex', flexDirection: 'column', justifyContent: 'center',
  }}>
    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
      <Icon name={icon} size={12}/>
      <span style={{ fontSize: 12, fontWeight: 500 }}>{label}</span>
    </div>
    <div style={{ fontSize: 10.5, opacity: filled ? 0.8 : 0.7, marginTop: 3 }}>{subLabel}</div>
  </div>
);

const FlowArrow = () => (
  <div style={{ display: 'flex', alignItems: 'center', color: 'var(--ink-4)', flexShrink: 0 }}>
    <span style={{ width: 16, height: 1, background: 'var(--line-3)', display: 'block' }}/>
    <Icon name="chevron" size={11}/>
  </div>
);

const RuleInline = ({ icon, text }) => (
  <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, color: 'var(--ink-3)' }}>
    <Icon name={icon} size={11}/>
    <span>{text}</span>
  </div>
);

// ─── Reasons & Quick fill Settings ───────────────────────────────────────────

const REASONS_TABS = [
  { id: 'approve',      label: 'Approve',           th: 'อนุมัติ',              color: '#16a34a' },
  { id: 'request_info', label: 'Request more Info', th: 'ขอข้อมูลเพิ่มเติม',   color: '#d97706' },
  { id: 'reject',       label: 'Reject',            th: 'ปฏิเสธ',              color: '#dc2626' },
];

const ReasonSection = ({ tab, section, sectionLabel, items, onAdd, onEdit, onDelete }) => {
  const [adding, setAdding]   = React.useState(false);
  const [addText, setAddText] = React.useState('');
  const [editId, setEditId]   = React.useState(null);
  const [editText, setEditText] = React.useState('');
  const [saving, setSaving]   = React.useState(false);

  const handleAdd = async () => {
    if (!addText.trim()) return;
    setSaving(true);
    await onAdd(tab, section, addText.trim());
    setAddText('');
    setAdding(false);
    setSaving(false);
  };

  const handleEdit = async (id) => {
    if (!editText.trim()) return;
    setSaving(true);
    await onEdit(id, editText.trim());
    setEditId(null);
    setSaving(false);
  };

  const handleDelete = async (id) => {
    if (!window.confirm('ลบรายการนี้?')) return;
    await onDelete(id);
  };

  return (
    <div style={{ marginBottom: 24 }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
        <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--ink-2)' }}>{sectionLabel}</div>
        <button
          onClick={() => { setAdding(true); setAddText(''); }}
          style={{ display: 'flex', alignItems: 'center', gap: 5, padding: '4px 10px', background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 4, cursor: 'pointer', fontSize: 12, color: 'var(--ink-2)' }}
        >
          <Icon name="plus" size={11}/> เพิ่ม
        </button>
      </div>

      {items.length === 0 && !adding && (
        <div style={{ fontSize: 12, color: 'var(--ink-4)', padding: '10px 0' }}>ยังไม่มีรายการ</div>
      )}

      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        {items.map((item, idx) => (
          <div key={item.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 10px', background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 4 }}>
            <span style={{ fontSize: 11, color: 'var(--ink-4)', width: 18, textAlign: 'center' }}>{idx + 1}</span>
            {editId === item.id ? (
              <>
                <input
                  value={editText}
                  onChange={e => setEditText(e.target.value)}
                  onKeyDown={e => { if (e.key === 'Enter') handleEdit(item.id); if (e.key === 'Escape') setEditId(null); }}
                  autoFocus
                  style={{ flex: 1, fontSize: 13, padding: '3px 8px', border: '1px solid var(--accent)', borderRadius: 3, outline: 'none' }}
                />
                <button onClick={() => handleEdit(item.id)} disabled={saving} style={{ fontSize: 11, padding: '3px 10px', background: 'var(--accent)', color: '#fff', border: 'none', borderRadius: 3, cursor: 'pointer' }}>บันทึก</button>
                <button onClick={() => setEditId(null)} style={{ fontSize: 11, padding: '3px 8px', background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 3, cursor: 'pointer' }}>ยกเลิก</button>
              </>
            ) : (
              <>
                <span style={{ flex: 1, fontSize: 13, color: 'var(--ink-1)' }}>{item.text}</span>
                <button onClick={() => { setEditId(item.id); setEditText(item.text); }} style={{ fontSize: 11, padding: '2px 8px', background: 'transparent', border: '1px solid var(--line)', borderRadius: 3, cursor: 'pointer', color: 'var(--ink-3)' }}>แก้ไข</button>
                <button onClick={() => handleDelete(item.id)} style={{ fontSize: 11, padding: '2px 8px', background: 'transparent', border: '1px solid #fca5a5', borderRadius: 3, cursor: 'pointer', color: '#dc2626' }}>ลบ</button>
              </>
            )}
          </div>
        ))}
      </div>

      {adding && (
        <div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
          <input
            value={addText}
            onChange={e => setAddText(e.target.value)}
            onKeyDown={e => { if (e.key === 'Enter') handleAdd(); if (e.key === 'Escape') setAdding(false); }}
            placeholder={`พิมพ์${sectionLabel}...`}
            autoFocus
            style={{ flex: 1, fontSize: 13, padding: '6px 10px', border: '1px solid var(--accent)', borderRadius: 3, outline: 'none' }}
          />
          <button onClick={handleAdd} disabled={saving || !addText.trim()} style={{ fontSize: 12, padding: '6px 14px', background: 'var(--accent)', color: '#fff', border: 'none', borderRadius: 3, cursor: 'pointer' }}>เพิ่ม</button>
          <button onClick={() => setAdding(false)} style={{ fontSize: 12, padding: '6px 10px', background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 3, cursor: 'pointer' }}>ยกเลิก</button>
        </div>
      )}
    </div>
  );
};

const EMPTY_CONFIGS = () => ({
  approve:      { reasons: [], quickfill: [] },
  request_info: { reasons: [], quickfill: [] },
  reject:       { reasons: [], quickfill: [] },
});

const SettingsReasonsView = ({ setView }) => {
  const [activeTab, setActiveTab] = React.useState('approve');
  const [configs, setConfigs]     = React.useState(null);
  const [loading, setLoading]     = React.useState(true);
  const [error, setError]         = React.useState(null);

  React.useEffect(() => {
    // Use already-loaded global first (fast path), then refresh from API
    if (window.APPROVAL_CONFIGS) {
      setConfigs(JSON.parse(JSON.stringify(window.APPROVAL_CONFIGS)));
      setLoading(false);
      return;
    }
    window.apiFetch('/api/approval-configs')
      .then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); })
      .then(data => {
        window.APPROVAL_CONFIGS = data;
        setConfigs(data);
        setLoading(false);
      })
      .catch(e => {
        // Fallback to empty if API not ready yet (server may need restart)
        setConfigs(EMPTY_CONFIGS());
        setLoading(false);
      });
  }, []);

  const handleAdd = async (tab, section, text) => {
    const r = await window.apiFetch('/api/approval-configs', {
      method: 'POST',
      body: JSON.stringify({ tab, section, text }),
    });
    if (!r.ok) { alert('เพิ่มไม่สำเร็จ'); return; }
    const item = await r.json();
    setConfigs(prev => ({
      ...prev,
      [tab]: { ...prev[tab], [section]: [...(prev[tab][section] || []), item] },
    }));
    // sync global
    if (window.APPROVAL_CONFIGS) {
      window.APPROVAL_CONFIGS[tab][section].push(item);
    }
  };

  const handleEdit = async (id, text) => {
    const r = await window.apiFetch(`/api/approval-configs/${id}`, {
      method: 'PATCH',
      body: JSON.stringify({ text }),
    });
    if (!r.ok) { alert('แก้ไขไม่สำเร็จ'); return; }
    const updated = await r.json();
    setConfigs(prev => {
      const next = { ...prev };
      for (const tab of Object.keys(next)) {
        for (const sec of Object.keys(next[tab])) {
          next[tab][sec] = next[tab][sec].map(it => it.id === id ? updated : it);
        }
      }
      return next;
    });
    // sync global
    if (window.APPROVAL_CONFIGS) {
      for (const tab of Object.keys(window.APPROVAL_CONFIGS)) {
        for (const sec of Object.keys(window.APPROVAL_CONFIGS[tab])) {
          window.APPROVAL_CONFIGS[tab][sec] = window.APPROVAL_CONFIGS[tab][sec].map(it => it.id === id ? updated : it);
        }
      }
    }
  };

  const handleDelete = async (id) => {
    const r = await window.apiFetch(`/api/approval-configs/${id}`, { method: 'DELETE' });
    if (!r.ok) { alert('ลบไม่สำเร็จ'); return; }
    setConfigs(prev => {
      const next = { ...prev };
      for (const tab of Object.keys(next)) {
        for (const sec of Object.keys(next[tab])) {
          next[tab][sec] = next[tab][sec].filter(it => it.id !== id);
        }
      }
      return next;
    });
    // sync global
    if (window.APPROVAL_CONFIGS) {
      for (const tab of Object.keys(window.APPROVAL_CONFIGS)) {
        for (const sec of Object.keys(window.APPROVAL_CONFIGS[tab])) {
          window.APPROVAL_CONFIGS[tab][sec] = window.APPROVAL_CONFIGS[tab][sec].filter(it => it.id !== id);
        }
      }
    }
  };

  const tabInfo = REASONS_TABS.find(t => t.id === activeTab) || REASONS_TABS[0];

  if (loading) return <div style={{ padding: 40, textAlign: 'center', color: 'var(--ink-4)' }}>กำลังโหลด...</div>;
  if (error)   return <div style={{ padding: 40, textAlign: 'center', color: 'var(--negative)' }}>{error}</div>;

  return (
    <>
      {/* Tab bar */}
      <div style={{ display: 'flex', gap: 2, marginBottom: 24, borderBottom: '1px solid var(--line)', paddingBottom: 0 }}>
        {REASONS_TABS.map(tab => (
          <button
            key={tab.id}
            onClick={() => setActiveTab(tab.id)}
            style={{
              padding: '8px 18px', fontSize: 13, fontWeight: activeTab === tab.id ? 600 : 400,
              background: 'transparent', border: 'none', borderBottom: activeTab === tab.id ? `2px solid ${tab.color}` : '2px solid transparent',
              color: activeTab === tab.id ? tab.color : 'var(--ink-3)',
              cursor: 'pointer', marginBottom: -1, transition: 'color 0.15s',
            }}
          >
            {tab.label}
          </button>
        ))}
      </div>

      {/* Tab description */}
      <div style={{ marginBottom: 20, fontSize: 12.5, color: 'var(--ink-3)' }}>
        ตั้งค่า Dropdown <strong style={{ color: tabInfo.color }}>{tabInfo.label}</strong> ที่จะแสดงในหน้า Approvals
      </div>

      {/* Two columns: Reasons | Quick Fill */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 24 }}>
        {/* Reasons */}
        <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 6, padding: 20 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 16 }}>
            <div style={{ width: 8, height: 8, borderRadius: '50%', background: tabInfo.color }}/>
            <span style={{ fontSize: 14, fontWeight: 600 }}>Reasons</span>
            <span style={{ fontSize: 11, color: 'var(--ink-3)' }}>เหตุผลสำหรับ Dropdown</span>
          </div>
          <ReasonSection
            tab={activeTab}
            section="reasons"
            sectionLabel="Reason"
            items={(configs[activeTab] || {}).reasons || []}
            onAdd={handleAdd}
            onEdit={handleEdit}
            onDelete={handleDelete}
          />
        </div>

        {/* Quick Fill */}
        <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 6, padding: 20 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 16 }}>
            <div style={{ width: 8, height: 8, borderRadius: '50%', background: tabInfo.color }}/>
            <span style={{ fontSize: 14, fontWeight: 600 }}>Quick Fill</span>
            <span style={{ fontSize: 11, color: 'var(--ink-3)' }}>ข้อความสำเร็จรูปสำหรับ Remark</span>
          </div>
          <ReasonSection
            tab={activeTab}
            section="quickfill"
            sectionLabel="Quick Fill"
            items={(configs[activeTab] || {}).quickfill || []}
            onAdd={handleAdd}
            onEdit={handleEdit}
            onDelete={handleDelete}
          />
        </div>
      </div>
    </>
  );
};

// ─── Provision Setting ────────────────────────────────────────────────────────

const PROV_ICONS = [
  { value: 'file',    label: 'Document' },
  { value: 'shield',  label: 'Security' },
  { value: 'edit',    label: 'Contract' },
  { value: 'cog',     label: 'Technical' },
  { value: 'users',   label: 'Team' },
  { value: 'phone',   label: 'Phone' },
  { value: 'check',   label: 'Verify' },
  { value: 'clock',   label: 'Time' },
  { value: 'info',    label: 'Info' },
  { value: 'building',label: 'Office' },
];
const PROV_COLORS = [
  '#6366f1','#3b82f6','#0ea5e9','#10b981',
  '#f59e0b','#ef4444','#ec4899','#8b5cf6',
];

// Drag-handle icon (6-dot grip)
const GripIcon = ({ color = 'var(--ink-4)' }) => (
  <svg width="10" height="16" viewBox="0 0 10 16" fill="none" style={{ display: 'block' }}>
    {[0,1,2].map(row => [0,1].map(col => (
      <circle key={`${row}-${col}`} cx={col === 0 ? 2 : 8} cy={3 + row * 5} r={1.5} fill={color}/>
    )))}
  </svg>
);

const ProvStepCard = ({ step, idx, isLast, onEdit, onDelete, dragProps, isDragging, isDropTarget, dropPosition }) => {
  const [hover, setHover] = React.useState(false);
  const active = hover || isDragging;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
      {/* Drop indicator — ABOVE */}
      {isDropTarget && dropPosition === 'before' && (
        <div style={{ height: 3, borderRadius: 2, background: 'var(--accent)', margin: '2px 0', boxShadow: '0 0 6px var(--accent)' }}/>
      )}

      <div style={{ display: 'flex', alignItems: 'stretch', gap: 0, opacity: isDragging ? 0.35 : 1 }}>
        {/* Drag handle strip */}
        <div
          {...dragProps}
          style={{
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            width: 28, flexShrink: 0, borderRadius: '6px 0 0 6px',
            background: active ? 'var(--bg-2)' : 'transparent',
            border: `1px solid ${active ? step.color + '44' : 'var(--line)'}`,
            borderRight: 'none',
            cursor: 'grab', transition: 'all 0.15s',
          }}
          title="ลากเพื่อเรียงลำดับ"
        >
          <GripIcon color={active ? step.color : 'var(--ink-4)'}/>
        </div>

        {/* Step block */}
        <div
          onMouseEnter={() => setHover(true)}
          onMouseLeave={() => setHover(false)}
          style={{
            background: active ? 'var(--bg-2)' : 'var(--panel)',
            border: `1px solid ${active ? step.color + '88' : 'var(--line)'}`,
            borderRadius: '0 6px 6px 0', padding: '14px 16px',
            display: 'flex', alignItems: 'center', gap: 14,
            flex: 1, transition: 'all 0.15s', cursor: 'default',
            boxShadow: active ? `0 2px 8px ${step.color}18` : 'none',
          }}
        >
          {/* Step number + icon */}
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4, flexShrink: 0 }}>
            <div style={{
              width: 34, height: 34, borderRadius: '50%',
              background: step.color + '18', border: `1.5px solid ${step.color}44`,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}>
              <Icon name={step.icon} size={14} color={step.color}/>
            </div>
            <span style={{ fontSize: 10, fontWeight: 700, color: step.color, letterSpacing: '0.04em' }}>
              {String(idx + 1).padStart(2, '0')}
            </span>
          </div>

          {/* Content */}
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontWeight: 600, fontSize: 13.5 }}>{step.label}</div>
            <div style={{ fontSize: 12, color: 'var(--ink-3)', marginTop: 2 }}>{step.labelTh}</div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginTop: 8 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 4, fontSize: 11.5, color: 'var(--ink-2)' }}>
                <Icon name="users" size={11} color="var(--ink-3)"/>
                {step.owner}
              </div>
              {step.days ? (
                <div style={{ display: 'flex', alignItems: 'center', gap: 4, fontSize: 11.5, color: 'var(--ink-2)' }}>
                  <Icon name="clock" size={11} color="var(--ink-3)"/>
                  {step.days} วัน
                </div>
              ) : (
                <div style={{ display: 'flex', alignItems: 'center', gap: 4, fontSize: 11.5, color: 'var(--ink-4)' }}>
                  <Icon name="clock" size={11} color="var(--ink-4)"/>
                  ไม่ระบุเวลา
                </div>
              )}
            </div>
          </div>

          {/* Actions — visible on hover */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 4, opacity: hover ? 1 : 0, transition: 'opacity 0.15s', flexShrink: 0 }}>
            <button onClick={onEdit} title="แก้ไข" style={{ ...stageBtn, color: 'var(--accent)' }}><Icon name="edit" size={12}/></button>
            <button onClick={onDelete} title="ลบ" style={{ ...stageBtn, color: 'var(--negative)' }}><Icon name="close" size={11}/></button>
          </div>
        </div>
      </div>

      {/* Drop indicator — AFTER (only on last drop target) */}
      {isDropTarget && dropPosition === 'after' && (
        <div style={{ height: 3, borderRadius: 2, background: 'var(--accent)', margin: '2px 0', boxShadow: '0 0 6px var(--accent)' }}/>
      )}

      {/* Connector line (not last) */}
      {!isLast && !isDropTarget && (
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: 20, paddingLeft: 28 }}>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', height: '100%' }}>
            <div style={{ width: 2, flex: 1, background: 'var(--line-3)' }}/>
            <Icon name="chevronDown" size={10} color="var(--ink-4)"/>
            <div style={{ width: 2, flex: 1, background: 'var(--line-3)' }}/>
          </div>
        </div>
      )}
      {/* Connector replaced by drop indicator spacing */}
      {!isLast && isDropTarget && <div style={{ height: 4 }}/>}
    </div>
  );
};

// Shared form fields for Add / Edit modal
const ProvStepForm = ({ initial, onClose, onSave }) => {
  const [label,   setLabel]   = React.useState(initial?.label   || '');
  const [labelTh, setLabelTh] = React.useState(initial?.labelTh || '');
  const [owner,   setOwner]   = React.useState(initial?.owner   || '');
  const [days,    setDays]    = React.useState(initial?.days    || '');
  const [icon,    setIcon]    = React.useState(initial?.icon    || 'cog');
  const [color,   setColor]   = React.useState(initial?.color   || '#6366f1');
  const [saving,  setSaving]  = React.useState(false);
  const [err,     setErr]     = React.useState('');

  const handleSave = async () => {
    if (!label.trim()) { setErr('กรุณาระบุชื่อขั้นตอน'); return; }
    setSaving(true);
    setErr('');
    const ok = await onSave({ label: label.trim(), labelTh: labelTh.trim(), owner: owner.trim(), days: days ? parseInt(days) : null, icon, color });
    if (!ok) { setSaving(false); setErr('บันทึกไม่สำเร็จ กรุณาลองใหม่'); }
  };

  const inputStyle = {
    width: '100%', padding: '8px 10px', fontSize: 13,
    border: '1px solid var(--line)', borderRadius: 4, boxSizing: 'border-box',
    background: 'var(--panel)', color: 'var(--ink)',
  };

  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.4)', zIndex: 1200, display: 'flex', alignItems: 'center', justifyContent: 'center' }}
      onClick={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div style={{ background: 'var(--panel)', borderRadius: 6, width: 460, border: '1px solid var(--line)', boxShadow: '0 8px 32px rgba(0,0,0,0.2)' }}>
        {/* Header */}
        <div style={{ padding: '16px 20px', borderBottom: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <div style={{ width: 28, height: 28, borderRadius: '50%', background: color + '22', border: `1.5px solid ${color}66`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              <Icon name={icon} size={13} color={color}/>
            </div>
            <span style={{ fontWeight: 600, fontSize: 15 }}>{initial ? 'Edit Step' : 'Add Provisioning Step'}</span>
          </div>
          <button onClick={onClose} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--ink-3)' }}><Icon name="close" size={15}/></button>
        </div>

        {/* Body */}
        <div style={{ padding: '20px', display: 'flex', flexDirection: 'column', gap: 14 }}>
          {/* Icon & Color row */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--ink-2)', display: 'block', marginBottom: 6 }}>ไอคอน</label>
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
                {PROV_ICONS.map(ic => (
                  <button key={ic.value} title={ic.label} onClick={() => setIcon(ic.value)} style={{
                    width: 30, height: 30, borderRadius: 5, cursor: 'pointer',
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    background: icon === ic.value ? color + '22' : 'var(--bg-2)',
                    border: `1.5px solid ${icon === ic.value ? color : 'var(--line)'}`,
                  }}>
                    <Icon name={ic.value} size={13} color={icon === ic.value ? color : 'var(--ink-3)'}/>
                  </button>
                ))}
              </div>
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--ink-2)', display: 'block', marginBottom: 6 }}>สี</label>
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                {PROV_COLORS.map(c => (
                  <button key={c} onClick={() => setColor(c)} title={c} style={{
                    width: 22, height: 22, borderRadius: '50%', background: c, cursor: 'pointer',
                    border: `2.5px solid ${color === c ? 'var(--ink)' : 'transparent'}`,
                    boxShadow: color === c ? `0 0 0 1px ${c}` : 'none',
                  }}/>
                ))}
              </div>
            </div>
          </div>

          {/* Label EN */}
          <div>
            <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--ink-2)', display: 'block', marginBottom: 5 }}>ชื่อขั้นตอน (EN) <span style={{ color: 'var(--negative)' }}>*</span></label>
            <input value={label} onChange={e => setLabel(e.target.value)} placeholder="เช่น Document review" style={inputStyle}/>
          </div>

          {/* Label TH */}
          <div>
            <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--ink-2)', display: 'block', marginBottom: 5 }}>ชื่อขั้นตอน (TH)</label>
            <input value={labelTh} onChange={e => setLabelTh(e.target.value)} placeholder="เช่น ตรวจสอบเอกสาร" style={inputStyle}/>
          </div>

          {/* Owner + Days */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--ink-2)', display: 'block', marginBottom: 5 }}>Owner / ทีมรับผิดชอบ</label>
              <input value={owner} onChange={e => setOwner(e.target.value)} placeholder="เช่น KYC team" style={inputStyle}/>
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--ink-2)', display: 'block', marginBottom: 5 }}>ระยะเวลา (วัน)</label>
              <input type="number" value={days} onChange={e => setDays(e.target.value)} placeholder="ไม่ระบุ = ไม่จำกัด" min="1" style={inputStyle}/>
            </div>
          </div>

          {err && <div style={{ fontSize: 12, color: 'var(--negative)', background: 'var(--negative-bg,#fef2f2)', padding: '6px 10px', borderRadius: 4 }}>{err}</div>}
        </div>

        {/* Footer */}
        <div style={{ padding: '12px 20px', borderTop: '1px solid var(--line)', display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
          <button onClick={onClose} style={{ padding: '7px 16px', background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 4, cursor: 'pointer', fontSize: 13, fontFamily: 'Kanit, sans-serif' }}>ยกเลิก</button>
          <button onClick={handleSave} disabled={saving} style={{ padding: '7px 18px', background: saving ? 'var(--ink-4)' : 'var(--accent)', color: '#fff', border: 'none', borderRadius: 4, cursor: saving ? 'not-allowed' : 'pointer', fontSize: 13, fontWeight: 600, fontFamily: 'Kanit, sans-serif' }}>
            {saving ? 'กำลังบันทึก…' : 'บันทึก'}
          </button>
        </div>
      </div>
    </div>
  );
};

const SettingsProvisionView = () => {
  const liveProducts = (window.PRODUCTS || PRODUCTS).filter(p => p.status !== 'deleted');
  const [activeProductId, setActiveProductId] = React.useState(liveProducts[0]?.id || '');
  // steps keyed by productId  { [productId]: step[] }
  const [steps,    setSteps]    = React.useState({});
  const [loading,  setLoading]  = React.useState({});  // { [productId]: bool }
  const [loaded,   setLoaded]   = React.useState({});  // { [productId]: bool }
  const [showAdd,  setShowAdd]  = React.useState(false);
  const [editStep, setEditStep] = React.useState(null);
  const [catFilter, setCatFilter] = React.useState('all');

  // Drag state
  const [dragIdx, setDragIdx] = React.useState(null);
  const [dropIdx, setDropIdx] = React.useState(null);
  const [dropPos, setDropPos] = React.useState(null);

  const filteredProducts = catFilter === 'all' ? liveProducts : liveProducts.filter(p => p.category === catFilter);
  const activeProduct    = liveProducts.find(p => p.id === activeProductId) || liveProducts[0];
  const activeSteps      = steps[activeProductId] || [];
  const cats = ['all', ...[...new Set(liveProducts.map(p => p.category).filter(Boolean))].sort()];

  // Load ALL product steps on mount — so every product chip shows correct count immediately
  React.useEffect(() => {
    window.apiFetch('/api/product-prov-steps')
      .then(r => r.json())
      .then(data => {
        if (!Array.isArray(data)) return;
        // Group by productId
        const grouped = {};
        for (const s of data) {
          if (!grouped[s.productId]) grouped[s.productId] = [];
          grouped[s.productId].push(s);
        }
        // Mark all products that appear in data as loaded
        const newLoaded = {};
        for (const pid of Object.keys(grouped)) newLoaded[pid] = true;
        // Also mark products with 0 steps that have been implicitly loaded
        for (const p of liveProducts) if (!grouped[p.id]) { grouped[p.id] = []; newLoaded[p.id] = true; }
        setSteps(grouped);
        setLoaded(newLoaded);
      })
      .catch(() => {});
  }, []);

  // When switching to a product not yet loaded (e.g. added after mount), load individually
  React.useEffect(() => {
    if (!activeProductId || loaded[activeProductId] || loading[activeProductId]) return;
    setLoading(l => ({ ...l, [activeProductId]: true }));
    window.apiFetch(`/api/product-prov-steps?productId=${encodeURIComponent(activeProductId)}`)
      .then(r => r.json())
      .then(data => {
        setSteps(s => ({ ...s, [activeProductId]: Array.isArray(data) ? data : [] }));
        setLoaded(l => ({ ...l, [activeProductId]: true }));
      })
      .catch(() => setSteps(s => ({ ...s, [activeProductId]: [] })))
      .finally(() => setLoading(l => ({ ...l, [activeProductId]: false })));
  }, [activeProductId]);

  // ── CRUD helpers ─────────────────────────────────────────────────────────────
  const handleAdd = async (fields) => {
    try {
      const r = await window.apiFetch('/api/product-prov-steps', {
        method: 'POST',
        body: JSON.stringify({ productId: activeProductId, ...fields }),
      });
      if (!r.ok) return false;
      const newStep = await r.json();
      setSteps(s => ({ ...s, [activeProductId]: [...(s[activeProductId] || []), newStep] }));
      setShowAdd(false);
      return true;
    } catch { return false; }
  };

  const handleEdit = async (fields) => {
    try {
      const r = await window.apiFetch(`/api/product-prov-steps/${editStep.id}`, {
        method: 'PATCH',
        body: JSON.stringify(fields),
      });
      if (!r.ok) return false;
      const updated = await r.json();
      setSteps(s => ({ ...s, [activeProductId]: (s[activeProductId] || []).map(st => st.id === updated.id ? updated : st) }));
      setEditStep(null);
      return true;
    } catch { return false; }
  };

  const handleDelete = async (step) => {
    if (!window.confirm(`ลบขั้นตอน "${step.label}" ออก?`)) return;
    try {
      await window.apiFetch(`/api/product-prov-steps/${step.id}`, { method: 'DELETE' });
      setSteps(s => ({ ...s, [activeProductId]: (s[activeProductId] || []).filter(st => st.id !== step.id) }));
    } catch { alert('ลบไม่สำเร็จ'); }
  };

  // ── Drag & Drop ──────────────────────────────────────────────────────────────
  const handleDragStart = (idx) => (e) => {
    setDragIdx(idx);
    e.dataTransfer.effectAllowed = 'move';
    e.dataTransfer.setData('text/plain', String(idx));
  };
  const handleDragEnd = () => {
    setDragIdx(null); setDropIdx(null); setDropPos(null);
  };
  const handleDragOver = (idx) => (e) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
    const rect = e.currentTarget.getBoundingClientRect();
    setDropIdx(idx);
    setDropPos(e.clientY < rect.top + rect.height / 2 ? 'before' : 'after');
  };
  const handleDragLeave = () => { setDropIdx(null); setDropPos(null); };
  const handleDrop = (idx) => (e) => {
    e.preventDefault();
    const fromIdx = dragIdx;
    if (fromIdx === null || fromIdx === idx) { handleDragEnd(); return; }
    const next = [...activeSteps];
    const [moved] = next.splice(fromIdx, 1);
    let toIdx = dropPos === 'after' ? idx + 1 : idx;
    if (fromIdx < idx) toIdx = dropPos === 'after' ? idx : idx - 1;
    toIdx = Math.max(0, Math.min(toIdx, next.length));
    next.splice(toIdx, 0, moved);
    // Optimistic update
    setSteps(s => ({ ...s, [activeProductId]: next }));
    handleDragEnd();
    // Persist reorder
    window.apiFetch('/api/product-prov-steps-reorder', {
      method: 'PATCH',
      body: JSON.stringify(next.map((st, i) => ({ id: st.id, sortOrder: i + 1 }))),
    }).catch(() => {});
  };

  const totalDays = activeSteps.reduce((sum, s) => sum + (s.days || 0), 0);
  const isLoading = loading[activeProductId];

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>

      {/* Category filter chips */}
      {cats.length > 2 && (
        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
          <span style={{ fontSize: 11, color: 'var(--ink-4)', marginRight: 2 }}>Category:</span>
          {cats.map(cat => {
            const isActive = catFilter === cat;
            const count = cat === 'all' ? liveProducts.length : liveProducts.filter(p => p.category === cat).length;
            return (
              <button key={cat} onClick={() => setCatFilter(cat)} style={{
                padding: '4px 10px', borderRadius: 20, fontSize: 11.5, cursor: 'pointer',
                fontFamily: 'Kanit, sans-serif', fontWeight: isActive ? 700 : 500,
                background: 'var(--bg-2)', color: isActive ? 'var(--ink)' : 'var(--ink-3)',
                border: `1.5px solid ${isActive ? 'var(--ink-2)' : 'var(--line)'}`,
                boxShadow: isActive ? 'inset 0 0 0 1px var(--ink-2)' : 'none',
              }}>
                {cat === 'all' ? 'All' : cat}
                <span style={{ marginLeft: 5, fontSize: 10, opacity: isActive ? 0.8 : 0.6 }}>{count}</span>
              </button>
            );
          })}
        </div>
      )}

      {/* Product selector strip */}
      <div style={{ overflowX: 'auto', paddingBottom: 4 }}>
        <div style={{ display: 'flex', gap: 8, minWidth: 'min-content' }}>
          {filteredProducts.map(p => {
            const pSteps = steps[p.id] || [];
            const isActive = p.id === activeProductId;
            return (
              <button key={p.id} onClick={() => setActiveProductId(p.id)} style={{
                background: isActive ? 'var(--panel)' : 'var(--bg-2)',
                border: `1px solid ${isActive ? p.color : 'var(--line)'}`,
                borderRadius: 4, padding: 12, cursor: 'pointer', textAlign: 'left',
                fontFamily: 'Kanit, sans-serif',
                boxShadow: isActive ? 'var(--shadow-segment)' : 'none',
                position: 'relative', overflow: 'hidden', minWidth: 150, flexShrink: 0,
              }}>
                {isActive && <div style={{ position: 'absolute', top: 0, left: 0, width: 3, height: '100%', background: p.color }}/>}
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8, paddingLeft: isActive ? 4 : 0 }}>
                  <ProductGlyph productId={p.id} size={22}/>
                  <div style={{ fontSize: 12, fontWeight: 500 }}>{p.name}</div>
                </div>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, paddingLeft: isActive ? 4 : 0 }}>
                  <span className="num" style={{ fontSize: 18, fontWeight: 500 }}>{loaded[p.id] ? pSteps.length : '—'}</span>
                  <span style={{ fontSize: 10.5, color: 'var(--ink-3)' }}>step{pSteps.length !== 1 ? 's' : ''}</span>
                </div>
              </button>
            );
          })}
        </div>
      </div>

      {/* Step editor panel */}
      <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 6 }}>
        {/* Panel header */}
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <ProductGlyph productId={activeProduct?.id} size={30}/>
            <div>
              <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Provisioning steps · {activeProduct?.name}</h3>
              <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 3 }}>
                {isLoading ? 'กำลังโหลด…' : `${activeSteps.length} ขั้นตอน · รวม ${totalDays} วัน (ไม่นับขั้นตอนที่ไม่ระบุเวลา)`}
              </div>
            </div>
          </div>
          <button onClick={() => setShowAdd(true)} style={{
            display: 'flex', alignItems: 'center', gap: 6,
            padding: '7px 14px', background: 'var(--accent)', color: '#fff',
            border: 'none', borderRadius: 4, cursor: 'pointer', fontSize: 12.5, fontWeight: 600,
            fontFamily: 'Kanit, sans-serif',
          }}>
            <Icon name="plus" size={12} color="#fff"/> Add step
          </button>
        </div>

        {/* Steps layout: left = vertical flow, right = summary */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 260px', gap: 0 }}>
          {/* Left: steps list */}
          <div style={{ padding: '18px', borderRight: '1px solid var(--line)', minHeight: 200 }}>
            {isLoading ? (
              <div style={{ padding: '48px 24px', textAlign: 'center', color: 'var(--ink-3)', fontSize: 13 }}>
                <div style={{ fontSize: 24, marginBottom: 10 }}>⏳</div>กำลังโหลดข้อมูล…
              </div>
            ) : activeSteps.length === 0 ? (
              <div style={{ padding: '48px 24px', textAlign: 'center' }}>
                <div style={{ fontSize: 32, marginBottom: 10 }}>🔧</div>
                <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 6 }}>ยังไม่มีขั้นตอน Provisioning</div>
                <div style={{ fontSize: 12, color: 'var(--ink-3)', marginBottom: 16 }}>คลิก Add step เพื่อสร้างขั้นตอนแรก</div>
                <button onClick={() => setShowAdd(true)} style={{
                  padding: '8px 18px', background: 'var(--accent)', color: '#fff',
                  border: 'none', borderRadius: 4, cursor: 'pointer', fontSize: 13, fontWeight: 600,
                  fontFamily: 'Kanit, sans-serif',
                }}>+ Add step</button>
              </div>
            ) : (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
                {/* Start cap */}
                <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 4, padding: '8px 12px', background: '#1e293b', borderRadius: 6 }}>
                  <div style={{ width: 8, height: 8, borderRadius: '50%', background: '#fff' }}/>
                  <span style={{ fontSize: 12, fontWeight: 600, color: '#fff' }}>Order Approved</span>
                  <span style={{ fontSize: 11, color: '#94a3b8', marginLeft: 4 }}>เริ่มต้นกระบวนการ</span>
                </div>
                <div style={{ width: 2, height: 12, background: 'var(--line-3)', margin: '0 auto' }}/>

                {activeSteps.map((step, idx) => (
                  <ProvStepCard
                    key={step.id}
                    step={step}
                    idx={idx}
                    isLast={idx === activeSteps.length - 1}
                    onEdit={() => setEditStep(step)}
                    onDelete={() => handleDelete(step)}
                    isDragging={dragIdx === idx}
                    isDropTarget={dropIdx === idx && dragIdx !== idx}
                    dropPosition={dropPos}
                    dragProps={{
                      draggable: true,
                      onDragStart: handleDragStart(idx),
                      onDragEnd: handleDragEnd,
                      onDragOver: handleDragOver(idx),
                      onDragLeave: handleDragLeave,
                      onDrop: handleDrop(idx),
                    }}
                  />
                ))}

                {/* End cap */}
                <div style={{ width: 2, height: 12, background: 'var(--line-3)', margin: '0 auto' }}/>
                <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 12px', background: '#ecfdf5', border: '1px solid #bbf7d0', borderRadius: 6 }}>
                  <div style={{ width: 8, height: 8, borderRadius: '50%', background: '#16a34a' }}/>
                  <span style={{ fontSize: 12, fontWeight: 600, color: '#15803d' }}>Order Active</span>
                  <span style={{ fontSize: 11, color: '#6b7280', marginLeft: 4 }}>Provisioning สำเร็จ</span>
                </div>
              </div>
            )}
          </div>

          {/* Right: summary sidebar */}
          <div style={{ padding: '18px 16px', display: 'flex', flexDirection: 'column', gap: 14 }}>
            {activeSteps.length > 0 && (
              <>
                <div>
                  <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 10 }}>สรุปขั้นตอน</div>
                  {activeSteps.map((step, idx) => (
                    <div key={step.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '6px 0', borderBottom: idx < activeSteps.length - 1 ? '1px solid var(--line-2)' : 'none' }}>
                      <div style={{ width: 18, height: 18, borderRadius: '50%', background: step.color + '22', border: `1px solid ${step.color}44`, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                        <span style={{ fontSize: 9, fontWeight: 700, color: step.color }}>{idx + 1}</span>
                      </div>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontSize: 11.5, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{step.label}</div>
                        <div style={{ fontSize: 10.5, color: 'var(--ink-3)' }}>{step.owner || '—'}</div>
                      </div>
                      <div style={{ fontSize: 11, color: 'var(--ink-3)', flexShrink: 0 }}>{step.days ? `${step.days}d` : '—'}</div>
                    </div>
                  ))}
                </div>

                {/* Timeline estimate */}
                {totalDays > 0 && (
                  <div style={{ background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 4, padding: '12px 14px' }}>
                    <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 }}>ระยะเวลารวม</div>
                    <div style={{ display: 'flex', alignItems: 'baseline', gap: 4 }}>
                      <span className="num" style={{ fontSize: 26, fontWeight: 500 }}>{totalDays}</span>
                      <span style={{ fontSize: 12, color: 'var(--ink-3)' }}>วันทำการโดยประมาณ</span>
                    </div>
                    <div style={{ marginTop: 12, display: 'flex', gap: 2 }}>
                      {activeSteps.filter(s => s.days).map((step, i) => (
                        <div key={i} title={`${step.label}: ${step.days} วัน`} style={{
                          height: 6, borderRadius: 3, background: step.color, flex: step.days,
                        }}/>
                      ))}
                    </div>
                    <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 4 }}>
                      <span style={{ fontSize: 10, color: 'var(--ink-4)' }}>Day 1</span>
                      <span style={{ fontSize: 10, color: 'var(--ink-4)' }}>Day {totalDays}</span>
                    </div>
                  </div>
                )}
              </>
            )}

            <div style={{ fontSize: 11, color: 'var(--ink-4)', padding: '8px 10px', background: 'var(--bg-2)', borderRadius: 4, lineHeight: 1.5 }}>
              💡 แต่ละ product สามารถกำหนด provisioning steps ได้อิสระ<br/>
              ลากเพื่อเรียงลำดับ · ขั้นตอนที่ไม่ระบุวันไม่นับในระยะเวลารวม
            </div>
          </div>
        </div>
      </div>

      {/* Add modal */}
      {showAdd && <ProvStepForm onClose={() => setShowAdd(false)} onSave={handleAdd}/>}

      {/* Edit modal */}
      {editStep && <ProvStepForm initial={editStep} onClose={() => setEditStep(null)} onSave={handleEdit}/>}
    </div>
  );
};

Object.assign(window, { SETTINGS_ITEMS, SettingsLayout, SettingsCatalogView, SettingsCategoriesView, SettingsStatusView, SettingsWorkflowView, SettingsDocumentsView, SettingsTeamsView, SettingsUserView, ProfileTab, SettingsReasonsView, SettingsProvisionView });
