// ─────────────────────────────────────────────
// DEV_Database.jsx  (V7)
// V7 changes vs V6:
//   - API endpoints → /v7/dev/
//   - Tables: one record, fields nested in JSON
//   - Table key: _oid (not o_id)
//   - Fields: id, code (not o_id, field)
//   - No fieldType — schema is typeless (MEDIUMTEXT)
//     Type is set on the UI object in Design tab
// ─────────────────────────────────────────────

const DB_TABS = [
  { key:'tables',        label:'Tables',        icon:'🗄'  },
  //{ key:'relationships', label:'Relationships', icon:'🔀', soon:true },
  { key:'templates',     label:'Templates',     icon:'💡', soon:true },
  { key:'import',        label:'Import',        icon:'📥'  },
  { key:'export',        label:'Export',        icon:'📤'  },
  { key:'backup',        label:'Backup',        icon:'☁️',  soon:true },
  { key:'library',       label:'Library',       icon:'📚'  },
];

function DEVDatabase({ app, jwt }) {
  const [activeTab,       setActiveTab]       = React.useState('tables');
  const [tables,          setTables]          = React.useState([]);
  const [loading,         setLoading]         = React.useState(true);
  const [error,           setError]           = React.useState(null);
  const [activeTableOid,  setActiveTableOid]  = React.useState(null);
  const [showIconPicker,  setShowIconPicker]  = React.useState(false);

  // Table modal
  const [tableModal, setTableModal] = React.useState(null); // null | 'new' | tableObj
  const [tName,      setTName]      = React.useState('');
  const [tDesc,      setTDesc]      = React.useState('');
  const [tIcon,      setTIcon]      = React.useState('');
  const [tSaving,    setTSaving]    = React.useState(false);
  const [tError,     setTError]     = React.useState(null);

  // Field modal
  const [fieldModal, setFieldModal] = React.useState(null); // null | 'new' | fieldObj
  const [fName,      setFName]      = React.useState('');
  const [fDesc,      setFDesc]      = React.useState('');
  const [fSaving,    setFSaving]    = React.useState(false);
  const [fError,     setFError]     = React.useState(null);

  // Library
  const [library,    setLibrary]    = React.useState({ public:[], private:[] });
  const [libLoading, setLibLoading] = React.useState(false);
  const [libAdding,  setLibAdding]  = React.useState(null);
  const [libInfo,    setLibInfo]    = React.useState(null);  // null | libItem (slide-in)

  // Confirm dialog state — uses shared DOConfirm from DEV_Shared.jsx
  const [confirm, setConfirm] = React.useState(null);

  // ── Field drag-to-reorder ──
  // orderedFields holds the active fields in current (draggable) order.
  // It is re-synced from the table whenever the table or its fields change.
  const [orderedFields, setOrderedFields] = React.useState([]);
  const [fieldsDirty,   setFieldsDirty]   = React.useState(false);
  const [savingOrder,   setSavingOrder]   = React.useState(false);
  const [dbFromIdx,     setDbFromIdx]     = React.useState(null); // visual: row being dragged
  const [dbOverIdx,     setDbOverIdx]     = React.useState(null); // visual: drop target
  const dbDragFrom = React.useRef(null);  // authoritative source idx (avoids stale closures)
  const dbDragOver = React.useRef(null);  // authoritative target idx
  const dbFieldSync = React.useRef('');   // signature of last synced field set

  React.useEffect(() => { loadTables(); }, [app.app_id]);
  React.useEffect(() => {
    if (activeTab === 'library') loadLibrary();
  }, [activeTab, app.app_id]);

  // ── Data loading ────────────────────────────

  async function loadTables() {
    setLoading(true); setError(null);
    try {
      const res  = await apiFetch(`${API_BASE}/v7/dev/apps/${app.app_id}/tables`);
      const data = await res.json();
      if (data.status !== 'ok') throw new Error(data.message);
      const rows = data.tables || [];
      setTables(rows);
      // Auto-select first table if none selected
      if (rows.length && !activeTableOid) setActiveTableOid(rows[0]._oid);
    } catch(err) { setError(err.message); }
    setLoading(false);
  }

  async function loadLibrary() {
    setLibLoading(true);
    try {
      const res  = await apiFetch(`${API_BASE}/v7/dev/library/tables?appId=${app.app_id}`);
      const data = await res.json();
      if (data.status === 'ok') setLibrary({ public: data.public||[], private: data.private||[] });
    } catch(e) {}
    setLibLoading(false);
  }

  // ── Library helpers ──────────────────────────

  // If baseName collides with an existing table, return baseName + " 2", " 3", ...
  // Comparison is case-insensitive and ignores surrounding whitespace.
  function makeUniqueName(baseName, existingNames) {
    const base       = String(baseName || '').trim();
    const existingLC = existingNames.map(n => String(n || '').trim().toLowerCase());
    if (!existingLC.includes(base.toLowerCase())) return base;
    let n = 2;
    while (existingLC.includes(`${base} ${n}`.toLowerCase())) n++;
    return `${base} ${n}`;
  }

  async function addFromLibrary(libItem) {
    setLibAdding(libItem.id);
    try {
      // Auto-rename if a table with this name already exists in the app
      const existingNames = tables.map(t => t.name);
      const newName       = makeUniqueName(libItem.name, existingNames);

      const res  = await apiFetch(`${API_BASE}/v7/dev/library/tables/add-to-app`, {
        method: 'POST',
        body:   JSON.stringify({ appId: app.app_id, libId: libItem.id, name: newName }),
      });
      const data = await res.json();
      if (data.status !== 'ok') throw new Error(data.message);
      await loadTables();
      setActiveTab('tables');
    } catch(e) { alert('Failed to add table: ' + e.message); }
    setLibAdding(null);
  }

  // ── Table CRUD ───────────────────────────────

  function openNewTable() {
    setTName(''); setTDesc(''); setTIcon(''); setTError(null);
    setTableModal('new');
  }

  function openEditTable(t) {
    setTName(t.name); setTDesc(t.desc||''); setTIcon(t.icon||'');
    setTError(null);
    setTableModal(t);
  }

  async function saveTable(e) {
    e.preventDefault();
    setTSaving(true); setTError(null);
    try {
      // ── Duplicate name check (case-insensitive) ──
      const trimmedName = tName.trim();
      const nameLC      = trimmedName.toLowerCase();
      const dupe        = tables.find(t =>
        t.name.trim().toLowerCase() === nameLC &&
        (tableModal === 'new' || t._oid !== tableModal._oid)
      );
      if (dupe) {
        setTError(`A table named "${dupe.name}" already exists.`);
        setTSaving(false);
        return;
      }

      let res, data;
      if (tableModal === 'new') {
        res = await apiFetch(`${API_BASE}/v7/dev/apps/${app.app_id}/tables`, {
          method: 'POST',
          body:   JSON.stringify({ name: tName.trim(), desc: tDesc.trim(), icon: tIcon }),
        });
      } else {
        res = await apiFetch(`${API_BASE}/v7/dev/apps/${app.app_id}/tables/${tableModal._oid}`, {
          method: 'POST',
          body:   JSON.stringify({ name: tName.trim(), desc: tDesc.trim(), icon: tIcon }),
        });
      }
      data = await res.json();
      if (data.status !== 'ok') throw new Error(data.message);
      setTableModal(null);
      await loadTables();
      // Select newly created table
      if (tableModal === 'new' && data.table?._oid) setActiveTableOid(data.table._oid);
    } catch(err) { setTError(err.message); }
    setTSaving(false);
  }

  function confirmDeleteTable(t) {
    setConfirm({
      msg:      `Delete table "${t.name}"?`,
      detail:   'This deletes the table and all of its data. This cannot be undone.',
      okLabel:  'Delete Table',
      okDanger: true,
      onOk:     () => deleteTable(t),
    });
  }

  async function deleteTable(t) {
    setConfirm(null);
    try {
      const res  = await apiFetch(`${API_BASE}/v7/dev/apps/${app.app_id}/tables/${t._oid}`, {
        method: 'POST',
        body:   JSON.stringify({ action: 'delete' }),
      });
      const data = await res.json();
      if (data.status !== 'ok') throw new Error(data.message);
      setActiveTableOid(null);
      setTableModal(null);
      await loadTables();
    } catch(err) { alert('Delete failed: ' + err.message); }
  }

  // ── Field CRUD ───────────────────────────────
  // V7: no fieldType — schema is typeless
  // field.id is UUID, field.code is fN

  function openNewField() {
    setFName(''); setFDesc(''); setFError(null);
    setFieldModal('new');
  }

  function openEditField(f) {
    setFName(f.name); setFDesc(f.desc||''); setFError(null);
    setFieldModal(f);
  }

  async function saveField(e) {
    e.preventDefault();
    setFSaving(true); setFError(null);
    try {
      let res, data;
      if (fieldModal === 'new') {
        // V7: pass tOid so server knows which table JSON to update
        res = await apiFetch(`${API_BASE}/v7/dev/apps/${app.app_id}/fields`, {
          method: 'POST',
          body:   JSON.stringify({
            tOid: currentTable._oid,
            name: fName.trim(),
            desc: fDesc.trim(),
          }),
        });
      } else {
        res = await apiFetch(`${API_BASE}/v7/dev/apps/${app.app_id}/fields/${fieldModal.id}`, {
          method: 'POST',
          body:   JSON.stringify({
            tOid: currentTable._oid,
            name: fName.trim(),
            desc: fDesc.trim(),
          }),
        });
      }
      data = await res.json();
      if (data.status !== 'ok') throw new Error(data.message);
      setFieldModal(null);
      await loadTables();
    } catch(err) { setFError(err.message); }
    setFSaving(false);
  }

  function confirmDeleteField(f) {
    setConfirm({
      msg:      `Delete field "${f.name}"?`,
      detail:   'The column data is preserved but hidden from the app.',
      okLabel:  'Delete Field',
      okDanger: true,
      onOk:     () => deleteField(f),
    });
  }

  async function deleteField(f) {
    setConfirm(null);
    try {
      const res  = await apiFetch(`${API_BASE}/v7/dev/apps/${app.app_id}/fields/${f.id}`, {
        method: 'POST',
        body:   JSON.stringify({ tOid: currentTable._oid, action: 'delete' }),
      });
      const data = await res.json();
      if (data.status !== 'ok') throw new Error(data.message);
      await loadTables();
    } catch(err) { alert('Delete failed: ' + err.message); }
  }

  // ── Derived state ─────────────────────────────
  const currentTable  = tables.find(t => t._oid === activeTableOid);
  // Only show active fields (status !== 0)
  const activeFields  = (currentTable?.fields || []).filter(f => f.status !== 0);

  // Re-sync orderedFields whenever the active field set changes (table switch,
  // add/edit/delete, or a saved reorder reload). Signature includes id+name+desc
  // so edits refresh too. Setting state during render here is the React-endorsed
  // "adjust state when input changes" pattern — no flash, no extra commit.
  const dbFieldSig = (activeTableOid || '') + '#' +
    activeFields.map(f => `${f.id}:${f.name}:${f.desc || ''}`).join('|');
  if (dbFieldSync.current !== dbFieldSig) {
    dbFieldSync.current = dbFieldSig;
    setOrderedFields(activeFields);
    setFieldsDirty(false);
    setDbFromIdx(null);
    setDbOverIdx(null);
  }

  // ── Drag handlers (refs hold the authoritative indices) ──
  function dbDragStart(e, idx) {
    dbDragFrom.current = idx;
    dbDragOver.current = idx;
    setDbFromIdx(idx);
    if (e.dataTransfer) {
      e.dataTransfer.effectAllowed = 'move';
      try { e.dataTransfer.setData('text/plain', String(idx)); } catch(_) {}
    }
  }
  function dbDragEnterRow(idx) {
    dbDragOver.current = idx;
    setDbOverIdx(idx);
  }
  function dbDragOverRow(e) {
    e.preventDefault();
    if (e.dataTransfer) e.dataTransfer.dropEffect = 'move';
  }
  function dbDragEnd() {
    const from = dbDragFrom.current;
    const to   = dbDragOver.current;
    dbDragFrom.current = null;   // null first → idempotent if drop+dragend both fire
    dbDragOver.current = null;
    setDbFromIdx(null);
    setDbOverIdx(null);
    if (from == null || to == null || from === to) return;
    setOrderedFields(prev => {
      const next = [...prev];
      const [moved] = next.splice(from, 1);
      next.splice(to, 0, moved);
      return next;
    });
    setFieldsDirty(true);
  }

  async function saveFieldOrder() {
    if (!currentTable) return;
    setSavingOrder(true);
    try {
      const res  = await apiFetch(`${API_BASE}/v7/dev/apps/${app.app_id}/fields/reorder`, {
        method: 'POST',
        body:   JSON.stringify({ tOid: currentTable._oid, order: orderedFields.map(f => f.id) }),
      });
      const data = await res.json();
      if (data.status !== 'ok') throw new Error(data.message);
      await loadTables();   // reload → sig changes → orderedFields re-syncs, dirty clears
    } catch(err) { alert('Save order failed: ' + err.message); }
    setSavingOrder(false);
  }

  if (loading) return <div style={SDB.empty}>Loading…</div>;
  if (error)   return <div style={SDB.errorBox}>{error}</div>;

  return (
    <div>
      {/* ── Sub-tab bar ── */}
      <div style={SDB.tabBar}>
        {DB_TABS.map(t => (
          <button key={t.key} onClick={() => !t.soon && setActiveTab(t.key)}
            style={{ ...SDB.tabBtn, ...(activeTab===t.key ? SDB.tabBtnActive : {}),
                     ...(t.soon ? { opacity:0.5, cursor:'default' } : {}) }}>
            <span>{t.icon}</span>
            <span>{t.label}</span>
            {t.soon && <span style={SDB.soonBadge}>soon</span>}
          </button>
        ))}
      </div>

      {/* ══ TABLES tab ══════════════════════════ */}
      {activeTab === 'tables' && (
        <>
          {showIconPicker && (
            <IconBrowser
              onSelect={val => { setTIcon(val); setShowIconPicker(false); }}
              onClose={() => setShowIconPicker(false)}
            />
          )}

          <div style={SDB.layout}>

            {/* ── Left sidebar — table list ── */}
            <div style={SDB.sidebar}>
              <div style={SDB.sidebarHeader}>
                <span style={SDB.sidebarTitle}>Tables</span>
                <button style={SDB.addBtn} onClick={openNewTable} title="New table">+</button>
              </div>
              {tables.length === 0 && (
                <div style={SDB.sidebarEmpty}>No tables yet</div>
              )}
              {[...tables].sort((a,b) => (a.sort||0) - (b.sort||0) || a.name.localeCompare(b.name))
                .map(t => (
                  <div key={t._oid}
                    style={{ ...SDB.tableItem, ...(activeTableOid===t._oid ? SDB.tableItemActive : {}) }}
                    onClick={() => setActiveTableOid(t._oid)}>
                    <div style={SDB.tableItemLeft}>
                      {t.icon && <span style={SDB.tableIcon}>{t.icon}</span>}
                      <div>
                        <div style={SDB.tableItemName}>{t.name}</div>
                        <div style={SDB.tableItemMeta}>
                          {t.code} · {(t.fields||[]).filter(f=>f.status!==0).length} fields
                        </div>
                      </div>
                    </div>
                    <button style={SDB.editBtn}
                      onClick={e => { e.stopPropagation(); openEditTable(t); }}>✏️</button>
                  </div>
                ))
              }
            </div>

            {/* ── Right — fields panel ── */}
            <div style={SDB.main}>
              {!currentTable ? (
                <div style={SDB.empty}>
                  {tables.length === 0 ? (
                    <>
                      <div style={SDB.emptyIcon}>⬡</div>
                      <div style={SDB.emptyTitle}>No tables yet</div>
                      <div style={SDB.emptySub}>Create your first table to get started</div>
                      <button style={SDB.createBtn} onClick={openNewTable}>+ New Table</button>
                    </>
                  ) : (
                    <div style={{ color:'#94a3b8' }}>Select a table</div>
                  )}
                </div>
              ) : (
                <>
                  {/* Fields header */}
                  <div style={SDB.fieldsHeader}>
                    <div>
                      <div style={SDB.fieldsTitle}>
                        {currentTable.icon && <span style={{ marginRight:6 }}>{currentTable.icon}</span>}
                        {currentTable.name}
                        <span style={SDB.tableTag}>{currentTable.code}</span>
                        <button style={SDB.pencilBtn}
                          onClick={() => openEditTable(currentTable)} title="Edit table">✏️</button>
                      </div>
                      {currentTable.desc && (
                        <div style={SDB.fieldsDesc}>{currentTable.desc}</div>
                      )}
                    </div>
                    <div style={{ display:'flex', gap:8 }}>
                      {fieldsDirty && (
                        <button style={SDB.saveOrderBtn} onClick={saveFieldOrder}
                          disabled={savingOrder}>
                          {savingOrder ? 'Saving…' : '💾 Save Order'}
                        </button>
                      )}
                      <button style={SDB.addFieldBtn} onClick={openNewField}>+ Add Field</button>
                      <button style={SDB.deleteTableBtn}
                        onClick={() => confirmDeleteTable(currentTable)}>Delete Table</button>
                    </div>
                  </div>

                  {/* Fields list */}
                  {activeFields.length === 0 ? (
                    <div style={{ ...SDB.empty, padding:'40px 0' }}>
                      <div style={SDB.emptySub}>No fields yet — add your first field</div>
                      <button style={{ ...SDB.createBtn, marginTop:12 }}
                        onClick={openNewField}>+ Add Field</button>
                    </div>
                  ) : (
                    <div style={SDB.fieldsList}>
                      <div style={SDB.fieldsListHeader}>
                        <span style={{ flex:'0 0 20px' }}></span>
                        <span style={{ flex:3 }}>Field Name</span>
                        <span style={{ flex:1 }}>Column</span>
                        <span style={{ flex:3 }}>Description</span>
                        <span style={{ flex:'0 0 60px' }}></span>
                      </div>
                      {orderedFields.map((f, idx) => (
                        <div key={f.id}
                          draggable
                          onDragStart={e => dbDragStart(e, idx)}
                          onDragEnter={() => dbDragEnterRow(idx)}
                          onDragOver={dbDragOverRow}
                          onDrop={e => { e.preventDefault(); dbDragEnd(); }}
                          onDragEnd={dbDragEnd}
                          style={{ ...SDB.fieldRow,
                                   ...(dbFromIdx === idx ? SDB.fieldRowDragging : {}),
                                   ...(dbOverIdx === idx && dbFromIdx !== idx
                                       ? SDB.fieldRowDragOver : {}) }}>
                          <span style={SDB.grabHandle} title="Drag to reorder">⠿</span>
                          <span style={{ flex:3, fontWeight:500, color:'#0f1923' }}>{f.name}</span>
                          <span style={{ flex:1, fontFamily:'DM Mono, monospace',
                                         fontSize:11, color:'#94a3b8' }}>{f.code}</span>
                          <span style={{ flex:3, fontSize:12, color:'#94a3b8' }}>{f.desc||'—'}</span>
                          <span style={{ flex:'0 0 60px', display:'flex', gap:6,
                                         justifyContent:'flex-end' }}>
                            <button style={SDB.iconBtn} onClick={() => openEditField(f)}>✏️</button>
                            <button style={{ ...SDB.iconBtn, color:'#dc2626' }}
                              onClick={() => confirmDeleteField(f)}>✕</button>
                          </span>
                        </div>
                      ))}
                    </div>
                  )}
                </>
              )}
            </div>
          </div>

          {/* ── Table modal ── */}
          {tableModal && (
            <div style={SDB.backdrop}
              onClick={e => { if(e.target===e.currentTarget) setTableModal(null); }}>
              <div style={SDB.modal}>
                <div style={SDB.modalHeader}>
                  <div style={SDB.modalTitle}>
                    {tableModal === 'new' ? 'New Table' : `Edit: ${tableModal.name}`}
                  </div>
                  <button style={SDB.closeBtn} onClick={() => setTableModal(null)}>✕</button>
                </div>
                {tError && <div style={SDB.modalError}>{tError}</div>}
                <form onSubmit={saveTable}>
                  <label style={SDB.label}>Table Name *</label>
                  <input style={SDB.input} value={tName}
                    onChange={e => setTName(e.target.value)}
                    placeholder="Contacts, Hotels…" autoFocus required />
                  <label style={SDB.label}>Description</label>
                  <input style={SDB.input} value={tDesc}
                    onChange={e => setTDesc(e.target.value)}
                    placeholder="What does this table store?" />
                  <label style={SDB.label}>Icon <span style={SDB.optional}>(emoji)</span></label>
                  <div style={{ display:'flex', alignItems:'center', gap:8 }}>
                    <input style={{ ...SDB.input, width:60, fontSize:20,
                                   textAlign:'center', padding:'4px', marginBottom:0 }}
                      value={tIcon} onChange={e => setTIcon(e.target.value)}
                      placeholder="🏡" maxLength={4} />
                    <button type="button" onClick={() => setShowIconPicker(true)}
                      style={SDB.browseBtn}>🔍 Browse</button>
                  </div>
                  <div style={SDB.modalFooter}>
                    {tableModal !== 'new' && (
                      <button type="button" style={SDB.deleteBtnSm}
                        onClick={() => { setTableModal(null); confirmDeleteTable(tableModal); }}>
                        Delete
                      </button>
                    )}
                    <div style={{ display:'flex', gap:8, marginLeft:'auto' }}>
                      <button type="button" style={SDB.cancelBtn}
                        onClick={() => setTableModal(null)}>Cancel</button>
                      <button type="submit" style={SDB.submitBtn}
                        disabled={tSaving || !tName.trim()}>
                        {tSaving ? 'Saving…' : tableModal==='new' ? 'Create Table' : 'Save'}
                      </button>
                    </div>
                  </div>
                </form>
              </div>
            </div>
          )}

          {/* ── Field modal ── */}
          {fieldModal && (
            <div style={SDB.backdrop}
              onClick={e => { if(e.target===e.currentTarget) setFieldModal(null); }}>
              <div style={SDB.modal}>
                <div style={SDB.modalHeader}>
                  <div style={SDB.modalTitle}>
                    {fieldModal === 'new'
                      ? `New Field in ${currentTable?.name}`
                      : `Edit: ${fieldModal.name}`}
                  </div>
                  <button style={SDB.closeBtn} onClick={() => setFieldModal(null)}>✕</button>
                </div>
                {fError && <div style={SDB.modalError}>{fError}</div>}
                <form onSubmit={saveField}>
                  <label style={SDB.label}>Field Name *</label>
                  <input style={SDB.input} value={fName}
                    onChange={e => setFName(e.target.value)}
                    placeholder="First Name, Email…" autoFocus required />
                  <label style={SDB.label}>
                    Description <span style={SDB.optional}>(optional)</span>
                  </label>
                  <input style={SDB.input} value={fDesc}
                    onChange={e => setFDesc(e.target.value)}
                    placeholder="What is this field for?" />
                  <div style={SDB.fieldNote}>
                    💡 Field type is set in the <strong>Design</strong> tab when placing
                    this field on a layout.
                  </div>
                  <div style={SDB.modalFooter}>
                    {fieldModal !== 'new' && (
                      <button type="button" style={SDB.deleteBtnSm}
                        onClick={() => { setFieldModal(null); confirmDeleteField(fieldModal); }}>
                        Delete
                      </button>
                    )}
                    <div style={{ display:'flex', gap:8, marginLeft:'auto' }}>
                      <button type="button" style={SDB.cancelBtn}
                        onClick={() => setFieldModal(null)}>Cancel</button>
                      <button type="submit" style={SDB.submitBtn}
                        disabled={fSaving || !fName.trim()}>
                        {fSaving ? 'Saving…' : fieldModal==='new' ? 'Add Field' : 'Save'}
                      </button>
                    </div>
                  </div>
                </form>
              </div>
            </div>
          )}

          {/* ── Confirm dialog (shared) ── */}
          {confirm && <DOConfirm {...confirm} onClose={() => setConfirm(null)} />}
        </>
      )}

      {/* ══ IMPORT tab ══════════════════════════ */}
      {activeTab === 'import' && <DEVDatabaseData app={app} initialTab="imports" />}

      {/* ══ EXPORT tab ══════════════════════════ */}
      {activeTab === 'export' && <DEVDatabaseData app={app} initialTab="exports" />}

      {/* ══ LIBRARY tab ═════════════════════════ */}
      {activeTab === 'library' && (
        <div style={{ marginTop:8 }}>
          <div style={{ display:'flex', justifyContent:'space-between',
                        alignItems:'center', marginBottom:16 }}>
            <div style={{ fontSize:13, color:'#64748b' }}>
              Pre-built table templates you can add to your app
            </div>
            <button onClick={loadLibrary} style={SDB.refreshBtn}>↻ Refresh</button>
          </div>
          {libLoading && (
            <div style={{ padding:'40px', textAlign:'center', color:'#94a3b8' }}>Loading…</div>
          )}
          {!libLoading && (
            <div style={SDB.libTwoCol}>
              {/* PUBLIC column */}
              <div style={SDB.libCol}>
                <div style={SDB.libColHeader}>
                  🌐 PUBLIC <span style={SDB.libColCount}>({library.public.length})</span>
                </div>
                {library.public.length === 0
                  ? <div style={SDB.libEmpty}>No public templates yet.</div>
                  : library.public.map(item => {
                      const fieldCount = (item.fields?.length ?? item.fieldCount ?? 0);
                      return (
                        <div key={item.id} style={SDB.libRow}>
                          {item.icon && <div style={SDB.libRowIcon}>{item.icon}</div>}
                          <div style={SDB.libRowMain}>
                            <div style={SDB.libRowName}>{item.name}</div>
                            {item.desc && <div style={SDB.libRowDesc}>{item.desc}</div>}
                            <div style={SDB.libRowMeta}>{fieldCount} {fieldCount===1?'field':'fields'}</div>
                          </div>
                          <div style={SDB.libRowActions}>
                            <button onClick={() => addFromLibrary(item)}
                              disabled={libAdding===item.id} style={SDB.libAddBtn}>
                              {libAdding===item.id ? 'Adding…' : '+ Add to App'}
                            </button>
                            <button onClick={() => setLibInfo(item)}
                              style={SDB.libInfoBtn} title="View details">?</button>
                          </div>
                        </div>
                      );
                    })
                }
              </div>

              {/* PRIVATE column */}
              <div style={SDB.libCol}>
                <div style={SDB.libColHeader}>
                  🔒 PRIVATE <span style={SDB.libColCount}>({library.private.length})</span>
                </div>
                {library.private.length === 0
                  ? <div style={SDB.libEmpty}>No private templates yet.</div>
                  : library.private.map(item => {
                      const fieldCount = (item.fields?.length ?? item.fieldCount ?? 0);
                      return (
                        <div key={item.id} style={SDB.libRow}>
                          {item.icon && <div style={SDB.libRowIcon}>{item.icon}</div>}
                          <div style={SDB.libRowMain}>
                            <div style={SDB.libRowName}>{item.name}</div>
                            {item.desc && <div style={SDB.libRowDesc}>{item.desc}</div>}
                            <div style={SDB.libRowMeta}>{fieldCount} {fieldCount===1?'field':'fields'}</div>
                          </div>
                          <div style={SDB.libRowActions}>
                            <button onClick={() => addFromLibrary(item)}
                              disabled={libAdding===item.id} style={SDB.libAddBtn}>
                              {libAdding===item.id ? 'Adding…' : '+ Add to App'}
                            </button>
                            <button onClick={() => setLibInfo(item)}
                              style={SDB.libInfoBtn} title="View details">?</button>
                          </div>
                        </div>
                      );
                    })
                }
              </div>
            </div>
          )}

          {/* Slide-in info panel from right edge */}
          {libInfo && (
            <>
              <div style={SDB.libSideBackdrop} onClick={() => setLibInfo(null)} />
              <div style={SDB.libSidePanel}>
                <div style={SDB.libSideHeader}>
                  <div style={SDB.libSideTitle}>
                    {libInfo.icon && <span style={{ fontSize:22 }}>{libInfo.icon}</span>}
                    <span>{libInfo.name}</span>
                  </div>
                  <button style={SDB.closeBtn} onClick={() => setLibInfo(null)}>✕</button>
                </div>
                <div style={SDB.libSideBody}>
                  {libInfo.desc && (
                    <div style={SDB.libSideDesc}>{libInfo.desc}</div>
                  )}
                  <div style={SDB.libSideFieldsLabel}>
                    Fields ({(libInfo.fields || []).length})
                  </div>
                  {(libInfo.fields || []).length === 0
                    ? <div style={{ ...SDB.libEmpty, padding:'8px 0' }}>No fields defined</div>
                    : (
                      <div>
                        {libInfo.fields.map((f, i) => (
                          <div key={i} style={SDB.libSideField}>
                            <div style={SDB.libSideFieldName}>{f.name}</div>
                            {f.desc && <div style={SDB.libSideFieldDesc}>{f.desc}</div>}
                          </div>
                        ))}
                      </div>
                    )
                  }
                </div>
              </div>
            </>
          )}
        </div>
      )}

      {/* ══ COMING SOON tabs ════════════════════ */}
      {['relationships','templates','backup'].includes(activeTab) && (
        <div style={{ padding:'80px 20px', textAlign:'center', color:'#94a3b8' }}>
          <div style={{ fontSize:40, marginBottom:12 }}>
            {activeTab==='relationships' ? '🔀' : activeTab==='templates' ? '💡' : '☁️'}
          </div>
          <div style={{ fontSize:16, fontWeight:600, color:'#374151', marginBottom:6 }}>
            {activeTab.charAt(0).toUpperCase()+activeTab.slice(1)} — Coming Soon
          </div>
          <div style={{ fontSize:13 }}>This feature is on the roadmap</div>
        </div>
      )}
    </div>
  );
}

// ── Styles ────────────────────────────────────
// Prefix: SDB (shared with V6 naming, safe to coexist)
const SDB = {
  tabBar:           { display:'flex', alignItems:'center', gap:0,
                      borderBottom:'2px solid #e2e8f0', marginBottom:20, overflowX:'auto' },
  tabBtn:           { display:'flex', alignItems:'center', gap:6, padding:'10px 16px',
                      background:'none', border:'none', borderBottom:'2px solid transparent',
                      marginBottom:'-2px', fontSize:13, fontWeight:500, color:'#64748b',
                      cursor:'pointer', fontFamily:'DM Sans, sans-serif', whiteSpace:'nowrap',
                      transition:'color 0.15s' },
  tabBtnActive:     { color:'#0f1923', borderBottomColor:'#0f1923', fontWeight:600 },
  soonBadge:        { fontSize:9, fontWeight:700, color:'#94a3b8', background:'#f1f5f9',
                      padding:'1px 5px', borderRadius:8, letterSpacing:'0.05em',
                      textTransform:'uppercase', marginLeft:2 },
  layout:           { display:'flex', gap:0, minHeight:400, border:'1px solid #e2e8f0',
                      borderRadius:12, overflow:'hidden', background:'#fff' },
  sidebar:          { width:240, borderRight:'1px solid #e2e8f0',
                      background:'#f8fafc', flexShrink:0 },
  sidebarHeader:    { display:'flex', alignItems:'center', justifyContent:'space-between',
                      padding:'14px 16px 10px', borderBottom:'1px solid #e2e8f0' },
  sidebarTitle:     { fontSize:11, fontWeight:700, color:'#64748b',
                      letterSpacing:'0.07em', textTransform:'uppercase' },
  addBtn:           { width:24, height:24, borderRadius:6, background:'#0f1923',
                      color:'#fff', border:'none', fontSize:16, cursor:'pointer',
                      lineHeight:'22px', textAlign:'center', fontFamily:'inherit' },
  sidebarEmpty:     { padding:'20px 16px', fontSize:13, color:'#94a3b8', textAlign:'center' },
  tableItem:        { display:'flex', alignItems:'center', justifyContent:'space-between',
                      padding:'10px 16px', cursor:'pointer', borderBottom:'1px solid #f1f5f9',
                      transition:'background 0.1s' },
  tableItemActive:  { background:'#eff6ff', borderLeft:'3px solid #2563eb' },
  tableItemLeft:    { display:'flex', alignItems:'center', gap:8 },
  tableIcon:        { fontSize:18 },
  tableItemName:    { fontSize:13, fontWeight:500, color:'#0f1923' },
  tableItemMeta:    { fontSize:11, color:'#94a3b8', marginTop:1 },
  editBtn:          { background:'none', border:'none', color:'#94a3b8',
                      cursor:'pointer', fontSize:14, padding:'2px 4px' },
  main:             { flex:1, padding:'20px 24px', minWidth:0 },
  fieldsHeader:     { display:'flex', justifyContent:'space-between',
                      alignItems:'flex-start', marginBottom:20 },
  fieldsTitle:      { fontSize:16, fontWeight:700, color:'#0f1923',
                      display:'flex', alignItems:'center', gap:8 },
  tableTag:         { fontSize:11, fontFamily:'DM Mono, monospace', color:'#94a3b8',
                      background:'#f1f5f9', padding:'2px 7px', borderRadius:4 },
  fieldsDesc:       { fontSize:13, color:'#64748b', marginTop:4 },
  pencilBtn:        { background:'none', border:'none', color:'#94a3b8',
                      cursor:'pointer', fontSize:14, padding:'2px 6px',
                      fontFamily:'inherit', opacity:0.6 },
  addFieldBtn:      { padding:'7px 14px', background:'#0f1923', color:'#fff',
                      border:'none', borderRadius:7, fontSize:12, fontWeight:600,
                      cursor:'pointer', fontFamily:'DM Sans, sans-serif' },
  deleteTableBtn:   { padding:'7px 14px', background:'#fff', color:'#dc2626',
                      border:'1px solid #fecaca', borderRadius:7, fontSize:12,
                      cursor:'pointer', fontFamily:'DM Sans, sans-serif' },
  fieldsList:       { border:'1px solid #e2e8f0', borderRadius:8, overflow:'hidden' },
  fieldsListHeader: { display:'flex', alignItems:'center', background:'#f8fafc',
                      padding:'8px 14px', fontSize:10, fontWeight:700, color:'#94a3b8',
                      letterSpacing:'0.06em', textTransform:'uppercase', gap:8 },
  fieldRow:         { display:'flex', alignItems:'center', padding:'11px 14px',
                      gap:8, borderTop:'1px solid #f1f5f9', fontSize:13 },
  fieldRowDragging: { opacity:0.4 },
  fieldRowDragOver: { borderTop:'2px solid #2563eb' },
  grabHandle:       { flex:'0 0 20px', cursor:'grab', color:'#cbd5e1', fontSize:14,
                      textAlign:'center', lineHeight:1, userSelect:'none' },
  saveOrderBtn:     { padding:'7px 14px', background:'#2563eb', color:'#fff',
                      border:'none', borderRadius:7, fontSize:12, fontWeight:600,
                      cursor:'pointer', fontFamily:'DM Sans, sans-serif' },
  iconBtn:          { background:'none', border:'none', color:'#94a3b8',
                      cursor:'pointer', fontSize:14, padding:'2px 4px', fontFamily:'inherit' },
  empty:            { display:'flex', flexDirection:'column', alignItems:'center',
                      justifyContent:'center', padding:'60px 20px', color:'#94a3b8' },
  emptyIcon:        { fontSize:40, marginBottom:12, color:'#e2e8f0' },
  emptyTitle:       { fontSize:16, fontWeight:600, color:'#374151', marginBottom:8 },
  emptySub:         { fontSize:13, color:'#94a3b8', marginBottom:8 },
  createBtn:        { padding:'9px 18px', background:'#0f1923', color:'#fff', border:'none',
                      borderRadius:8, fontSize:13, fontWeight:600, cursor:'pointer',
                      fontFamily:'DM Sans, sans-serif' },
  errorBox:         { background:'#fef2f2', color:'#dc2626', padding:'12px 16px',
                      borderRadius:8, fontSize:13, border:'1px solid #fecaca' },
  fieldNote:        { fontSize:12, color:'#64748b', background:'#f8fafc',
                      border:'1px solid #e2e8f0', borderRadius:6, padding:'8px 12px',
                      marginBottom:14, lineHeight:1.5 },
  libSectionTitle:  { fontSize:11, fontWeight:700, color:'#64748b', textTransform:'uppercase',
                      letterSpacing:'0.07em', marginBottom:12 },
  libEmpty:         { fontSize:13, color:'#94a3b8', padding:'8px 0', marginBottom:16 },
  libGrid:          { display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(200px,1fr))',
                      gap:12, marginBottom:16 },
  libCard:          { background:'#fff', border:'1px solid #e2e8f0', borderRadius:10,
                      padding:'16px', display:'flex', flexDirection:'column', gap:6 },
  libCardName:      { fontSize:14, fontWeight:600, color:'#0f1923' },
  libCardDesc:      { fontSize:12, color:'#64748b' },
  libCardMeta:      { fontSize:11, color:'#2563eb' },
  libAddBtn:        { padding:'7px 14px', background:'#0f1923', color:'#fff',
                      border:'none', borderRadius:7, fontSize:12, fontWeight:600,
                      cursor:'pointer', fontFamily:'DM Sans, sans-serif', whiteSpace:'nowrap' },

  // ── New Library layout: two columns of rows ──
  libTwoCol:        { display:'flex', gap:16, alignItems:'flex-start' },
  libCol:           { flex:1, minWidth:0 },
  libColHeader:     { fontSize:11, fontWeight:700, color:'#64748b',
                      textTransform:'uppercase', letterSpacing:'0.07em',
                      marginBottom:10, padding:'0 4px' },
  libColCount:      { color:'#94a3b8', fontWeight:600, marginLeft:4 },
  libRow:           { background:'#fff', border:'1px solid #e2e8f0', borderRadius:8,
                      padding:'12px 14px', marginBottom:8,
                      display:'flex', alignItems:'center', gap:12 },
  libRowIcon:       { fontSize:24, flexShrink:0, lineHeight:1 },
  libRowMain:       { flex:1, minWidth:0 },
  libRowName:       { fontSize:14, fontWeight:600, color:'#0f1923' },
  libRowDesc:       { fontSize:12, color:'#64748b', marginTop:2 },
  libRowMeta:       { fontSize:11, color:'#2563eb', marginTop:3 },
  libRowActions:    { display:'flex', alignItems:'center', gap:6, flexShrink:0 },
  libInfoBtn:       { width:28, height:28, borderRadius:'50%',
                      background:'#fff', border:'1.5px solid #e2e8f0',
                      color:'#64748b', fontSize:13, fontWeight:700,
                      cursor:'pointer', fontFamily:'DM Sans, sans-serif',
                      lineHeight:1, padding:0 },

  // ── Slide-in info panel from right edge ──
  libSideBackdrop:  { position:'fixed', inset:0, background:'rgba(0,0,0,0.35)', zIndex:200 },
  libSidePanel:     { position:'fixed', top:0, right:0, bottom:0, width:400,
                      maxWidth:'92vw', background:'#fff',
                      boxShadow:'-4px 0 24px rgba(0,0,0,0.15)',
                      zIndex:201, display:'flex', flexDirection:'column' },
  libSideHeader:    { display:'flex', justifyContent:'space-between',
                      alignItems:'center', padding:'16px 20px',
                      borderBottom:'1px solid #e2e8f0', flexShrink:0 },
  libSideTitle:     { display:'flex', alignItems:'center', gap:10,
                      fontSize:16, fontWeight:700, color:'#0f1923',
                      minWidth:0, overflow:'hidden', textOverflow:'ellipsis' },
  libSideBody:      { flex:1, overflowY:'auto', padding:'18px 20px' },
  libSideDesc:      { fontSize:13, color:'#64748b', marginBottom:20,
                      lineHeight:1.5 },
  libSideFieldsLabel:{ fontSize:11, fontWeight:700, color:'#64748b',
                       textTransform:'uppercase', letterSpacing:'0.07em',
                       marginBottom:8 },
  libSideField:     { padding:'10px 0', borderBottom:'1px solid #f1f5f9' },
  libSideFieldName: { fontSize:13, fontWeight:600, color:'#0f1923' },
  libSideFieldDesc: { fontSize:12, color:'#64748b', marginTop:2 },
  refreshBtn:       { padding:'5px 12px', background:'none', border:'1.5px solid #e2e8f0',
                      borderRadius:7, fontSize:12, cursor:'pointer', color:'#374151',
                      fontFamily:'DM Sans, sans-serif' },
  backdrop:         { position:'fixed', inset:0, background:'rgba(0,0,0,0.4)',
                      display:'flex', alignItems:'center', justifyContent:'center', zIndex:200 },
  modal:            { background:'#fff', borderRadius:14, padding:'28px 32px',
                      width:'100%', maxWidth:480, boxShadow:'0 20px 60px rgba(0,0,0,0.2)' },
  modalHeader:      { display:'flex', justifyContent:'space-between',
                      alignItems:'center', marginBottom:20 },
  modalTitle:       { fontSize:16, fontWeight:700, color:'#0f1923' },
  closeBtn:         { background:'none', border:'none', color:'#94a3b8',
                      fontSize:18, cursor:'pointer', padding:0 },
  modalError:       { background:'#fef2f2', color:'#dc2626', padding:'10px 12px',
                      borderRadius:7, fontSize:12, marginBottom:14,
                      border:'1px solid #fecaca' },
  label:            { display:'block', fontSize:12, fontWeight:500,
                      color:'#374151', marginBottom:5 },
  optional:         { color:'#94a3b8', fontWeight:400 },
  input:            { width:'100%', padding:'9px 12px', border:'1.5px solid #e2e8f0',
                      borderRadius:7, fontSize:13, fontFamily:'DM Sans, sans-serif',
                      outline:'none', marginBottom:14, color:'#0f1923', background:'#fff',
                      boxSizing:'border-box' },
  modalFooter:      { display:'flex', alignItems:'center', marginTop:8 },
  cancelBtn:        { padding:'9px 18px', background:'#fff', color:'#374151',
                      border:'1.5px solid #e2e8f0', borderRadius:7, fontSize:13,
                      cursor:'pointer', fontFamily:'DM Sans, sans-serif' },
  submitBtn:        { padding:'9px 20px', background:'#0f1923', color:'#fff',
                      border:'none', borderRadius:7, fontSize:13, fontWeight:600,
                      cursor:'pointer', fontFamily:'DM Sans, sans-serif' },
  deleteBtnSm:      { padding:'9px 16px', background:'#fff', color:'#dc2626',
                      border:'1px solid #fecaca', borderRadius:7, fontSize:13,
                      cursor:'pointer', fontFamily:'DM Sans, sans-serif' },
  browseBtn:        { padding:'6px 10px', background:'#fff', border:'1px solid #e2e8f0',
                      borderRadius:6, fontSize:11, color:'#2563eb', cursor:'pointer',
                      fontFamily:'DM Sans, sans-serif', fontWeight:600 },
};
