/* Dispatch — Settings
 * Loaded by index.html after lib.jsx.
 *
 * The original Settings only has real content under Help Desk. Per the demo
 * spec we surface just the *tables* from there as standalone tabs (no "Help
 * Desk" wrapper): Assignees and Applications — full CRUD against the live API
 * (fetchHelpdeskAssigneesAll / createHelpdeskAssignee / updateHelpdeskAssignee /
 * deleteHelpdeskAssignee and the Applications equivalents). Writes are
 * triager-only, like the original. */

const NO_CATEGORY = '__none__';

function AssigneesSettings() {
  const [rows, setRows] = useState([]);
  const [categories, setCategories] = useState([]);
  const [isTriager, setIsTriager] = useState(false);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [cat, setCat] = useState(NO_CATEGORY);
  const [busy, setBusy] = useState(false);
  const [sort, toggleSort] = useSort('name', 'asc');
  const [page, setPage] = useState(1);
  const [search, setSearch] = useState('');

  async function loadAssignees() {
    const list = await api.fetchHelpdeskAssigneesAll();
    setRows(Array.isArray(list) ? list : []);
  }
  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const [me, meta] = await Promise.all([
          api.fetchHelpdeskMe().catch(() => ({ isTriager: false })),
          api.fetchHelpdeskMetadata().catch(() => ({ categories: [] })),
        ]);
        if (cancelled) return;
        setIsTriager(!!me.isTriager);
        setCategories((meta.categories ?? []).filter(c => c.name !== 'general'));
        await loadAssignees();
        setError(null);
      } catch (e) { if (!cancelled) setError(e.message || 'Help Desk API unreachable'); }
      finally { if (!cancelled) setLoading(false); }
    })();
    return () => { cancelled = true; };
  }, []);

  const catLabel = (n) => !n ? 'No Category' : (categories.find(c => c.name === n)?.label || titleCase(n));

  async function addAssignee(e) {
    e.preventDefault();
    if (!name.trim() || !email.trim()) return;
    setBusy(true); setError(null);
    try {
      await api.createHelpdeskAssignee({ name: name.trim(), email: email.trim(), category: cat === NO_CATEGORY ? null : cat });
      setName(''); setEmail(''); setCat(NO_CATEGORY);
      await loadAssignees();
    } catch (e2) { setError(e2.message || 'Add failed'); }
    finally { setBusy(false); }
  }
  async function update(id, body) { setBusy(true); try { await api.updateHelpdeskAssignee(id, body); await loadAssignees(); } catch (e) { setError(e.message || 'Update failed'); } finally { setBusy(false); } }
  async function remove(a) { setBusy(true); try { await api.deleteHelpdeskAssignee(a.id); await loadAssignees(); } catch (e) { setError(e.message || 'Delete failed'); } finally { setBusy(false); } }

  const q = search.trim().toLowerCase();
  const visible = q ? rows.filter(r => (r.name || '').toLowerCase().includes(q)) : rows;
  const sorted = sortRows(visible, sort, (a, k) => k === 'category' ? catLabel(a.category) : (a[k] ?? ''));
  useEffect(() => { setPage(1); }, [rows.length, sort, search]);
  const pageCount = Math.max(1, Math.ceil(sorted.length / PER_PAGE));
  const paged = sorted.slice((page - 1) * PER_PAGE, page * PER_PAGE);

  return (
    <div className="space-y-4">
      {error && <div className="rounded-md border border-amber-300 bg-amber-50 px-4 py-2 text-sm text-amber-800">{error}</div>}
      {!loading && !isTriager && <div className="rounded-md border bg-muted/40 px-4 py-2 text-sm text-muted-foreground">Read-only — sign in as a triager to manage assignees.</div>}

      {isTriager && (
        <Card><CardContent className="pt-5">
          <form onSubmit={addAssignee} className="flex flex-wrap items-end gap-2">
            <div className="space-y-1.5"><Label>Name</Label><Input className="w-44" value={name} onChange={e => setName(e.target.value)} placeholder="Jane Doe" /></div>
            <div className="space-y-1.5"><Label>Email</Label><Input className="w-56" value={email} onChange={e => setEmail(e.target.value)} placeholder="jane@ucpm.com" /></div>
            <div className="space-y-1.5"><Label>Category</Label>
              <Select className="w-44" value={cat} onChange={e => setCat(e.target.value)}>
                <option value={NO_CATEGORY}>No Category</option>
                {categories.map(c => <option key={c.name} value={c.name}>{c.label}</option>)}
              </Select>
            </div>
            <Button type="submit" disabled={busy || !name.trim() || !email.trim()}>Add assignee</Button>
          </form>
        </CardContent></Card>
      )}

      <Card>
        <div className="flex flex-wrap items-center gap-2 border-b p-3">
          <Input className="w-64" placeholder="Search users by name…" value={search} onChange={e => setSearch(e.target.value)} />
          {search && <span className="text-xs text-muted-foreground">{sorted.length} match{sorted.length === 1 ? '' : 'es'}</span>}
        </div>
        <div className="overflow-x-auto">
          <table className="w-full text-sm">
            <thead className="border-b text-muted-foreground">
              <tr className="[&>th]:px-4 [&>th]:py-2.5 [&>th]:text-left [&>th]:font-medium">
                <SortHeader label="Name" sortKey="name" sort={sort} onSort={toggleSort} />
                <SortHeader label="Email" sortKey="email" sort={sort} onSort={toggleSort} />
                <SortHeader label="Category" sortKey="category" sort={sort} onSort={toggleSort} />
                <SortHeader label="Admin" sortKey="admin" sort={sort} onSort={toggleSort} />
                <SortHeader label="Status" sortKey="isActive" sort={sort} onSort={toggleSort} />
                {isTriager && <th className="text-right">Actions</th>}
              </tr>
            </thead>
            <tbody className="divide-y">
              {loading && rows.length === 0 && <tr><td colSpan={isTriager ? 6 : 5} className="px-4 py-6 text-center text-muted-foreground">Loading…</td></tr>}
              {!loading && rows.length === 0 && <tr><td colSpan={isTriager ? 6 : 5} className="px-4 py-6 text-center text-muted-foreground">No assignees yet.</td></tr>}
              {paged.map(a => (
                <tr key={a.id} className="hover:bg-muted/50">
                  <td className="px-4 py-2.5 font-medium">{a.name}</td>
                  <td className="px-4 py-2.5 text-muted-foreground">{a.email}</td>
                  <td className="px-4 py-2.5">
                    {isTriager
                      ? <Select className="w-40" value={a.category || NO_CATEGORY} onChange={e => update(a.id, { category: e.target.value === NO_CATEGORY ? null : e.target.value })}><option value={NO_CATEGORY}>No Category</option>{categories.map(c => <option key={c.name} value={c.name}>{c.label}</option>)}</Select>
                      : catLabel(a.category)}
                  </td>
                  <td className="px-4 py-2.5">
                    <input type="checkbox" className="h-4 w-4 accent-primary" checked={!!a.admin} disabled={!isTriager || busy}
                      onChange={() => update(a.id, { admin: !a.admin })} title={isTriager ? 'Toggle admin' : 'Admin'} />
                  </td>
                  <td className="px-4 py-2.5">{a.isActive ? <Badge>Active</Badge> : <Badge variant="secondary">Inactive</Badge>}</td>
                  {isTriager && (
                    <td className="px-4 py-2.5 text-right">
                      <div className="flex justify-end gap-2">
                        <Button variant="outline" size="sm" disabled={busy} onClick={() => update(a.id, { isActive: !a.isActive })}>{a.isActive ? 'Deactivate' : 'Activate'}</Button>
                        <Button variant="destructive" size="sm" disabled={busy} onClick={() => remove(a)}>Delete</Button>
                      </div>
                    </td>
                  )}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        <div className="flex items-center justify-between border-t px-4 py-2 text-xs text-muted-foreground">
          <span>{rows.length} assignees</span>
          <Pagination page={page} pageCount={pageCount} onPage={setPage} />
        </div>
      </Card>
    </div>
  );
}

function ApplicationsSettings() {
  const [rows, setRows] = useState([]);
  const [isTriager, setIsTriager] = useState(false);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [name, setName] = useState('');
  const [busy, setBusy] = useState(false);
  const [sort, toggleSort] = useSort('name', 'asc');
  const [page, setPage] = useState(1);

  async function loadApps() { const list = await api.fetchHelpdeskApplications(); setRows(Array.isArray(list) ? list : []); }
  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const me = await api.fetchHelpdeskMe().catch(() => ({ isTriager: false }));
        if (cancelled) return;
        setIsTriager(!!me.isTriager);
        await loadApps(); setError(null);
      } catch (e) { if (!cancelled) setError(e.message || 'Help Desk API unreachable'); }
      finally { if (!cancelled) setLoading(false); }
    })();
    return () => { cancelled = true; };
  }, []);

  async function addApp(e) {
    e.preventDefault();
    if (!name.trim()) return;
    setBusy(true); setError(null);
    try { await api.createHelpdeskApplication(name.trim()); setName(''); await loadApps(); }
    catch (e2) { setError(e2.message || 'Add failed'); }
    finally { setBusy(false); }
  }
  async function remove(a) { setBusy(true); try { await api.deleteHelpdeskApplication(a.id); await loadApps(); } catch (e) { setError(e.message || 'Delete failed'); } finally { setBusy(false); } }

  const sorted = sortRows(rows, sort, (a, k) => a[k] ?? '');
  useEffect(() => { setPage(1); }, [rows.length, sort]);
  const pageCount = Math.max(1, Math.ceil(sorted.length / PER_PAGE));
  const paged = sorted.slice((page - 1) * PER_PAGE, page * PER_PAGE);

  return (
    <div className="space-y-4">
      {error && <div className="rounded-md border border-amber-300 bg-amber-50 px-4 py-2 text-sm text-amber-800">{error}</div>}
      {!loading && !isTriager && <div className="rounded-md border bg-muted/40 px-4 py-2 text-sm text-muted-foreground">Read-only — sign in as a triager to manage applications.</div>}

      {isTriager && (
        <Card><CardContent className="pt-5">
          <form onSubmit={addApp} className="flex flex-wrap items-end gap-2">
            <div className="space-y-1.5"><Label>Application name</Label><Input className="w-64" value={name} onChange={e => setName(e.target.value)} placeholder="e.g. Salesforce" /></div>
            <Button type="submit" disabled={busy || !name.trim()}>Add application</Button>
          </form>
        </CardContent></Card>
      )}

      <Card>
        <div className="overflow-x-auto">
          <table className="w-full text-sm">
            <thead className="border-b text-muted-foreground">
              <tr className="[&>th]:px-4 [&>th]:py-2.5 [&>th]:text-left [&>th]:font-medium">
                <SortHeader label="Application" sortKey="name" sort={sort} onSort={toggleSort} />
                {isTriager && <th className="text-right">Actions</th>}
              </tr>
            </thead>
            <tbody className="divide-y">
              {loading && rows.length === 0 && <tr><td colSpan={isTriager ? 2 : 1} className="px-4 py-6 text-center text-muted-foreground">Loading…</td></tr>}
              {!loading && rows.length === 0 && <tr><td colSpan={isTriager ? 2 : 1} className="px-4 py-6 text-center text-muted-foreground">No applications yet.</td></tr>}
              {paged.map(a => (
                <tr key={a.id} className="hover:bg-muted/50">
                  <td className="px-4 py-2.5 font-medium">{a.name}</td>
                  {isTriager && <td className="px-4 py-2.5 text-right"><Button variant="destructive" size="sm" disabled={busy} onClick={() => remove(a)}>Delete</Button></td>}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        <div className="flex items-center justify-between border-t px-4 py-2 text-xs text-muted-foreground">
          <span>{rows.length} applications</span>
          <Pagination page={page} pageCount={pageCount} onPage={setPage} />
        </div>
      </Card>
    </div>
  );
}

// Settings → Variables: the `variables` key/value table, editable. The Slack
// fallback channel + bot are read live from these (channels change), so this
// replaces the old read-only Slack panel.
function VariablesSettings() {
  const [rows, setRows] = useState(null);
  const [error, setError] = useState(null);
  const [draft, setDraft] = useState({});       // name -> edited value
  const [savingName, setSavingName] = useState(null);
  const [savedName, setSavedName] = useState(null);

  useEffect(() => {
    let cancelled = false;
    api.fetchVariables().then(r => { if (!cancelled) { setRows(Array.isArray(r) ? r : []); setError(null); } }).catch(e => { if (!cancelled) setError(e.message || 'Could not load variables'); });
    return () => { cancelled = true; };
  }, []);

  async function save(v) {
    const value = draft[v.name] ?? v.value ?? '';
    setSavingName(v.name); setError(null);
    try {
      await api.updateVariable(v.name, value);
      setRows(rs => rs.map(x => x.name === v.name ? { ...x, value } : x));
      setDraft(d => { const n = { ...d }; delete n[v.name]; return n; });
      setSavedName(v.name); setTimeout(() => setSavedName(s => s === v.name ? null : s), 1500);
    } catch (e) { setError(e.message || 'Save failed'); }
    finally { setSavingName(null); }
  }

  if (error && !rows) return <Card><CardContent className="pt-6 text-sm text-muted-foreground">Could not load variables: {error}</CardContent></Card>;
  if (!rows) return <Card><CardContent className="pt-6 text-sm text-muted-foreground">Loading…</CardContent></Card>;

  return (
    <Card><CardContent className="space-y-4 pt-6">
      <p className="text-sm text-muted-foreground">App settings stored in the <code className="rounded bg-muted px-1 py-0.5 text-xs">variables</code> table. Edits apply live — the Slack fallback channel and bot are read from here, so you can move channels without a redeploy. (Editing requires triager access.)</p>
      {error && <div className="rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive">{error}</div>}
      {rows.length === 0 && <div className="text-sm text-muted-foreground">No variables defined.</div>}
      <div className="space-y-2">
        {rows.map(v => {
          const val = draft[v.name] ?? v.value ?? '';
          const dirty = draft[v.name] !== undefined && draft[v.name] !== (v.value ?? '');
          return (
            <div key={v.name} className="flex flex-wrap items-center gap-2">
              <code className="w-52 shrink-0 text-xs font-semibold text-muted-foreground">{v.name}</code>
              <Input className="min-w-[12rem] flex-1" value={val} onChange={e => setDraft(d => ({ ...d, [v.name]: e.target.value }))} />
              <Button size="sm" disabled={!dirty || savingName === v.name} onClick={() => save(v)}>
                {savingName === v.name ? 'Saving…' : savedName === v.name ? 'Saved ✓' : 'Save'}
              </Button>
            </div>
          );
        })}
      </div>
    </CardContent></Card>
  );
}

// Settings → User permissions: grant a user access to a module. Just manages
// rows in user_module_access — NOT yet enforced anywhere as access rules.
function UserPermissions() {
  const [rows, setRows] = useState(null);
  const [people, setPeople] = useState([]);
  const [mods, setMods] = useState([]);
  const [error, setError] = useState(null);
  const [newUser, setNewUser] = useState('');
  const [newModule, setNewModule] = useState('');
  const [filterUser, setFilterUser] = useState('all');
  const [busy, setBusy] = useState(false);

  async function load() {
    try {
      const [r, a, m] = await Promise.all([api.fetchUserModuleAccess(), api.fetchHelpdeskAssignees(), api.fetchModules()]);
      setRows(Array.isArray(r) ? r : []);
      setPeople(Array.isArray(a) ? a : []);
      setMods(Array.isArray(m) ? m : []);
      setError(null);
    } catch (e) { setError(e.message || 'Could not load permissions'); }
  }
  useEffect(() => { load(); }, []);

  async function add() {
    if (!newUser || !newModule) return;
    setBusy(true); setError(null);
    try { await api.createUserModuleAccess(newUser, Number(newModule)); setNewUser(''); setNewModule(''); await load(); }
    catch (e) { setError(e.message || 'Add failed'); }
    finally { setBusy(false); }
  }
  async function remove(id) {
    setBusy(true); setError(null);
    try { await api.deleteUserModuleAccess(id); setRows(rs => rs.filter(x => x.id !== id)); }
    catch (e) { setError(e.message || 'Remove failed'); }
    finally { setBusy(false); }
  }

  if (error && !rows) return <Card><CardContent className="pt-6 text-sm text-muted-foreground">Could not load permissions: {error}</CardContent></Card>;
  if (!rows) return <Card><CardContent className="pt-6 text-sm text-muted-foreground">Loading…</CardContent></Card>;

  const filtered = filterUser === 'all' ? rows : rows.filter(r => r.assigneeId === filterUser);

  return (
    <Card><CardContent className="space-y-4 pt-6">
      <p className="text-sm text-muted-foreground">Grant a user access to a module — one row per user + module. Stored only; not enforced as rules yet. (Editing requires triager access.)</p>
      {error && <div className="rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive">{error}</div>}

      <div className="flex flex-wrap items-end gap-2 rounded-lg border p-3">
        <div className="space-y-1"><Label>User</Label>
          <Select className="w-52" value={newUser} onChange={e => setNewUser(e.target.value)}>
            <option value="">Select user…</option>
            {people.map(a => <option key={a.id} value={a.id}>{a.name}</option>)}
          </Select>
        </div>
        <div className="space-y-1"><Label>Module</Label>
          <Select className="w-52" value={newModule} onChange={e => setNewModule(e.target.value)}>
            <option value="">Select module…</option>
            {mods.map(m => <option key={m.id} value={m.id}>{m.name}</option>)}
          </Select>
        </div>
        <Button size="sm" disabled={!newUser || !newModule || busy} onClick={add}>Add permission</Button>
      </div>

      <div className="flex items-center gap-2">
        <Label className="text-muted-foreground">Filter by user</Label>
        <Select className="w-52" value={filterUser} onChange={e => setFilterUser(e.target.value)}>
          <option value="all">All users</option>
          {people.map(a => <option key={a.id} value={a.id}>{a.name}</option>)}
        </Select>
      </div>

      <div className="overflow-x-auto rounded-lg border">
        <table className="w-full text-sm">
          <thead className="border-b text-muted-foreground"><tr className="[&>th]:px-4 [&>th]:py-2.5 [&>th]:text-left [&>th]:font-medium"><th>User</th><th>Module</th><th className="text-right">Actions</th></tr></thead>
          <tbody className="divide-y">
            {filtered.length === 0 && <tr><td colSpan="3" className="px-4 py-6 text-center text-muted-foreground">No permissions{filterUser !== 'all' ? ' for this user' : ''} yet.</td></tr>}
            {filtered.map(r => (
              <tr key={r.id}>
                <td className="px-4 py-2.5 font-medium">{r.userName || r.assigneeId}</td>
                <td className="px-4 py-2.5">{r.moduleName || r.moduleId}</td>
                <td className="px-4 py-2.5 text-right"><Button size="sm" variant="outline" disabled={busy} onClick={() => remove(r.id)}>Remove</Button></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </CardContent></Card>
  );
}

// Read-only list of admins (assignees with admin = true). Elevation happens in
// the Users tab; only admins can do it.
function AdminList() {
  const [rows, setRows] = useState(null);
  const [error, setError] = useState(null);
  useEffect(() => {
    let cancelled = false;
    api.fetchHelpdeskAssigneesAll().then(list => { if (!cancelled) { setRows(Array.isArray(list) ? list.filter(a => a.admin) : []); setError(null); } }).catch(e => { if (!cancelled) setError(e.message || 'Could not load admins'); });
    return () => { cancelled = true; };
  }, []);
  if (error && !rows) return <Card><CardContent className="pt-6 text-sm text-muted-foreground">Could not load admins: {error}</CardContent></Card>;
  if (!rows) return <Card><CardContent className="pt-6 text-sm text-muted-foreground">Loading…</CardContent></Card>;
  return (
    <Card><CardContent className="space-y-4 pt-6">
      <p className="text-sm text-muted-foreground">Users with the <strong>admin</strong> role. Read-only — toggle admin in the <em>Users</em> tab (admins only).</p>
      <div className="overflow-x-auto rounded-lg border">
        <table className="w-full text-sm">
          <thead className="border-b text-muted-foreground"><tr className="[&>th]:px-4 [&>th]:py-2.5 [&>th]:text-left [&>th]:font-medium"><th>Name</th><th>Email</th></tr></thead>
          <tbody className="divide-y">
            {rows.length === 0 && <tr><td colSpan="2" className="px-4 py-6 text-center text-muted-foreground">No admins.</td></tr>}
            {rows.map(a => <tr key={a.id}><td className="px-4 py-2.5 font-medium">{a.name}</td><td className="px-4 py-2.5 text-muted-foreground">{a.email}</td></tr>)}
          </tbody>
        </table>
      </div>
    </CardContent></Card>
  );
}

// Permissions area — nested tabs. Will be gated to admins in the enforcement
// pass (see docs/access-control.md).
// The rules modal — documents docs/access-control.md in-app.
function PermissionsHelp({ onClose }) {
  const Group = ({ title, children }) => (
    <div>
      <div className="mb-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">{title}</div>
      <ul className="list-disc space-y-1 pl-5 text-sm">{children}</ul>
    </div>
  );
  return (
    <Modal open onClose={onClose} title="How permissions work" footer={<Button size="sm" onClick={onClose}>Close</Button>}>
      <div className="space-y-4">
        <p className="text-sm text-muted-foreground">Who can see and do what. Full spec: <code className="rounded bg-muted px-1 py-0.5 text-xs">docs/access-control.md</code>.</p>
        <Group title="Roles">
          <li><strong>Admin</strong> is the elevated role (the Admin checkbox on a user) — separate from triager.</li>
          <li>Only an admin can make someone else an admin.</li>
          <li>You can't remove your own admin, and the last admin can't be removed.</li>
        </Group>
        <Group title="Visibility">
          <li>Everyone always sees <strong>My Tasks</strong>.</li>
          <li><strong>Admins see every module</strong>, including Settings.</li>
          <li>Non-admins see only the modules granted to them here (plus My Tasks).</li>
          <li>This <strong>Permissions</strong> area is admin-only.</li>
        </Group>
        <Group title="Editing">
          <li>Only admins can edit <strong>User permissions</strong> and the <strong>Users</strong> list.</li>
        </Group>
      </div>
    </Modal>
  );
}

function Permissions() {
  const [sub, setSub] = useState('users');
  const [helpOpen, setHelpOpen] = useState(false);
  const subs = [{ id: 'users', label: 'Users' }, { id: 'grants', label: 'User permissions' }, { id: 'admins', label: 'Admin list' }];
  return (
    <div className="space-y-4">
      <div className="flex flex-wrap items-center gap-2">
        <div className="inline-flex flex-wrap gap-1 rounded-lg bg-muted p-1">
          {subs.map(s => (
            <button key={s.id} onClick={() => setSub(s.id)}
              className={cn('rounded-md px-3 py-1.5 text-sm font-medium transition-colors', sub === s.id ? 'bg-background text-foreground shadow' : 'text-muted-foreground hover:text-foreground')}>{s.label}</button>
          ))}
        </div>
        <Button size="sm" variant="outline" className="ml-auto" onClick={() => setHelpOpen(true)} title="How permissions work">? Help</Button>
      </div>
      {sub === 'users' && <AssigneesSettings />}
      {sub === 'grants' && <UserPermissions />}
      {sub === 'admins' && <AdminList />}
      {helpOpen && <PermissionsHelp onClose={() => setHelpOpen(false)} />}
    </div>
  );
}

function Settings() {
  const [tab, setTab] = useState('applications');
  // Permissions is admin-only (docs/access-control.md rule 7).
  const [isAdmin, setIsAdmin] = useState(false);
  useEffect(() => {
    let cancelled = false;
    api.fetchMyAccess().then(a => { if (!cancelled) setIsAdmin(!!a?.isAdmin); }).catch(() => {});
    return () => { cancelled = true; };
  }, []);
  const tabs = [
    { id: 'applications', label: 'Applications' },
    { id: 'variables', label: 'Application variables' },
    ...(isAdmin ? [{ id: 'permissions', label: 'Permissions' }] : []),
  ];
  return (
    <div className="space-y-4">
      <div className="inline-flex flex-wrap gap-1 rounded-lg bg-muted p-1">
        {tabs.map(t => (
          <button key={t.id} onClick={() => setTab(t.id)}
            className={cn('rounded-md px-3 py-1.5 text-sm font-medium transition-colors', tab === t.id ? 'bg-background text-foreground shadow' : 'text-muted-foreground hover:text-foreground')}>{t.label}</button>
        ))}
      </div>
      {tab === 'applications' && <ApplicationsSettings />}
      {tab === 'variables' && <VariablesSettings />}
      {tab === 'permissions' && isAdmin && <Permissions />}
    </div>
  );
}
