/* Admin Panel — shell, overview, users management ====================
   Reachable only by users with users.manage OR integrations.manage.
=================================================================== */

/* Platforms an ad account can be mapped to (drives the Ad-accounts SOURCES
   column + the source-ID editor). Add a platform here and it renders + saves
   everywhere — nothing else is hardcoded. Now unified under Zernio. */
const SRC_PLATFORMS = [
  { id:'meta',     label:'Meta ad account ID',  icon:'meta',     hint:'via Zernio' },
  { id:'google',   label:'Google customer ID',  icon:'google',   hint:'via Zernio' },
  { id:'tiktok',   label:'TikTok advertiser ID', icon:'tiktok',  hint:'via Zernio' },
  { id:'x',        label:'X (Twitter) account ID', icon:'x',      hint:'via Zernio' },
  { id:'linkedin', label:'LinkedIn account ID', icon:'linkedin', hint:'via Zernio' },
];
const SRC_PLATFORM_IDS = SRC_PLATFORMS.map(s=>s.id);

/* ---------- Client-portal shortcut (admin rail footer) -------------
   The mirror of the portal's Settings → "Your other admin tool": one habit for
   "where do I go to manage people". Relay manages the internal TEAM (this app's
   `users` table); the client portal manages CLIENTS (its own `cv_*` tables, often a
   different deployment and database). They are deliberately not merged, so a link is
   the whole integration.

   Two ways it resolves, in order:
     1. Same-origin — on a full-suite deployment `client-admin.html` sits next to this
        file, so we probe for it and need no configuration at all.
     2. Operator-set URL, kept in localStorage. NOT hardcoded: this file ships in the
        full-suite package, so a literal host would leak one operator's URL to the next.
   Nothing renders until one of the two resolves. Per-device by design — it is a
   shortcut, not shared configuration, and it stays out of the API contract. */
const PORTAL_LS_KEY = 'relay.portalAdminUrl';
const readPortalUrl = () => { try { return localStorage.getItem(PORTAL_LS_KEY) || ''; } catch(_){ return ''; } };
/* Same rule the portal's backend enforces on its side: absolute https, or a same-origin
   path. Anything else (javascript:, data:, //host) is refused rather than sanitised. */
const validPortalUrl = u => /^https:\/\/[A-Za-z0-9][^\s"'<>`\\]{2,299}$/.test(u) || /^\/[^\s"'<>`\\/][^\s"'<>`\\]{0,299}$/.test(u);

function PortalShortcut(){
  const [saved, setSaved]       = useState(readPortalUrl);
  const [detected, setDetected] = useState('');
  const [editing, setEditing]   = useState(false);
  const [draft, setDraft]       = useState('');
  const [err, setErr]           = useState('');

  /* Probe once, only when nothing is configured. A 404/network error just means the
     portal is not part of this deployment — stay silent, never surface it as an error. */
  useEffect(()=>{
    if (saved) return;
    let dead = false;
    fetch('/api/cv/admin/auth/status', { credentials:'same-origin' })
      .then(r => { if (!dead && r.ok) setDetected('/client-admin.html'); })
      .catch(()=>{});
    return ()=>{ dead = true; };
  }, [saved]);

  const url = saved || detected;
  const commit = () => {
    const v = draft.trim();
    if (v && !validPortalUrl(v)) { setErr('Use a full https:// address.'); return; }
    try { v ? localStorage.setItem(PORTAL_LS_KEY, v) : localStorage.removeItem(PORTAL_LS_KEY); } catch(_){}
    setSaved(v); setErr(''); setEditing(false);
  };
  const startEdit = () => { setDraft(saved); setErr(''); setEditing(true); };

  if (editing) return (
    <div className="px-3 py-2.5 rounded-xl bg-white dark:bg-ink-800/60 border border-ink-200 dark:border-white/10 space-y-2">
      <div className="text-[11px] font-semibold">Client portal admin</div>
      <input autoFocus value={draft} placeholder="https://…"
        onChange={e=>{ setDraft(e.target.value); setErr(''); }}
        onKeyDown={e=>{ if (e.key==='Enter') commit(); if (e.key==='Escape') setEditing(false); }}
        className="w-full h-8 px-2 rounded-lg border border-ink-200 dark:border-white/10 bg-transparent text-[11px] font-mono outline-none focus:border-accent-500"/>
      {err && <div className="text-[10.5px] text-rose-500">{err}</div>}
      <div className="flex gap-1.5">
        <button onClick={commit} className="h-7 px-2.5 rounded-lg bg-accent-500 hover:bg-accent-600 text-white text-[11px] font-semibold transition">Save</button>
        <button onClick={()=>setEditing(false)} className="h-7 px-2.5 rounded-lg border border-ink-200 dark:border-white/10 text-[11px] font-medium transition">Cancel</button>
      </div>
      <div className="text-[10px] text-ink-500 dark:text-ink-300 leading-snug">Saved on this device only. Leave empty to remove the shortcut.</div>
    </div>
  );

  if (!url) return (
    <button onClick={startEdit}
      className="w-full flex items-center gap-2 px-3 h-9 rounded-xl text-[12px] font-medium text-ink-500 dark:text-ink-300 border border-dashed border-ink-200 dark:border-white/10 hover:text-ink-900 dark:hover:text-white hover:border-accent-400 transition">
      <Icon name="link" size={14}/> Link your client portal
    </button>
  );

  return (
    <div className="flex items-center gap-1">
      <a href={url} target="_blank" rel="noopener noreferrer" title={url}
        className="flex-1 min-w-0 flex items-center gap-2 px-3 h-9 rounded-xl text-[12px] font-medium text-ink-600 dark:text-ink-200 bg-white dark:bg-ink-800/60 border border-ink-200 dark:border-white/10 hover:border-accent-400 hover:text-ink-900 dark:hover:text-white transition">
        <Icon name="link" size={14}/><span className="truncate">Client portal admin</span>
      </a>
      <button onClick={startEdit} title="Change this link"
        className="w-9 h-9 flex-shrink-0 grid place-items-center rounded-xl text-ink-400 hover:text-ink-900 dark:hover:text-white hover:bg-white/60 dark:hover:bg-white/5 transition">
        <Icon name="settings" size={14}/>
      </button>
    </div>
  );
}

/* ---------- Admin avatar menu (top-right) -------------------------- */
function AdminUserMenu({ user, onSignOut }){
  return (
    <Dropdown align="right" width={248} trigger={
      <button className="inline-flex items-center gap-2 h-10 pl-1 pr-2.5 rounded-xl border border-ink-200 hover:border-ink-300 dark:border-white/10 dark:hover:border-white/20 bg-white dark:bg-ink-900/60 transition">
        <Avatar user={user} size={30}/>
        <span className="hidden sm:flex flex-col items-start leading-tight">
          <span className="text-[12.5px] font-semibold">{user.name}</span>
          <span className="text-[10px] text-ink-500 dark:text-ink-300 font-mono">{ROLES[user.role].label}</span>
        </span>
        <Icon name="chev-down" size={13} className="text-ink-400"/>
      </button>
    }>
      {(close)=>(
        <div>
          <div className="px-2.5 py-2.5 flex items-center gap-2.5">
            <Avatar user={user} size={38}/>
            <div className="min-w-0">
              <div className="text-[13px] font-semibold truncate">{user.name}</div>
              <div className="text-[11px] text-ink-500 dark:text-ink-300 font-mono truncate">{user.email}</div>
            </div>
          </div>
          <div className="px-2.5 pb-2"><RoleBadge role={user.role}/></div>
          <div className="border-t border-ink-100 dark:border-white/5 my-1"/>
          <button onClick={()=>{ close(); onSignOut(); }}
            className="w-full flex items-center gap-2 px-2.5 py-2 text-[12.5px] text-rose-600 dark:text-rose-300 hover:bg-rose-50 dark:hover:bg-rose-500/10 rounded-lg">
            <Icon name="link-break" size={14}/> Sign out
          </button>
        </div>
      )}
    </Dropdown>
  );
}

/* ---------- Overview section --------------------------------------- */
function AdminOverview({ users, integrations, audit, onGo }){
  const active = users.filter(u=>u.status==='active').length;
  const byRole = ROLE_ORDER.map(r=>({ role:r, n:users.filter(u=>u.role===r).length })).filter(x=>x.n>0);
  const connected = integrations.filter(i=>i.status==='connected');
  const degraded  = integrations.filter(i=>i.health==='degraded' && i.status==='connected');
  const offline   = integrations.filter(i=>i.status!=='connected');
  const feeds = connectedPlatforms(integrations);
  const platCount = Object.keys(feeds).length;

  const Stat = ({ label, value, sub, tone='#8351ff', icon }) => (
    <Card className="p-5 rounded-2xl relative overflow-hidden">
      <div className="absolute -top-8 -right-8 w-28 h-28 rounded-full blur-2xl opacity-[0.18]" style={{ background:tone }}/>
      <div className="relative">
        <div className="flex items-center gap-2 text-[12px] text-ink-500 dark:text-ink-300">
          <Icon name={icon} size={14} style={{ color:tone }}/> {label}
        </div>
        <div className="text-[34px] font-semibold tracking-tight tabular mt-2 leading-none">{value}</div>
        <div className="text-[11.5px] text-ink-500 dark:text-ink-300 mt-1.5">{sub}</div>
      </div>
    </Card>
  );

  return (
    <div className="space-y-4">
      <div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
        <Stat label="Team members" value={users.length} sub={`${active} active · ${users.length-active} suspended`} tone="#8351ff" icon="settings"/>
        <Stat label="Live feeds" value={platCount} sub="ad platforms streaming" tone="#10b981" icon="zap"/>
        <Stat label="Connections" value={connected.length} sub={`${offline.length} disconnected`} tone="#2f7bff" icon="sparkles"/>
        <Stat label="Health flags" value={degraded.length+offline.length} sub={degraded.length?`${degraded.length} degraded`:'all nominal'} tone={degraded.length||offline.length?'#f59e0b':'#10b981'} icon="alert"/>
      </div>

      <div className="grid grid-cols-12 gap-3">
        <Card className="col-span-12 lg:col-span-7 p-5 rounded-2xl">
          <div className="flex items-center justify-between mb-3">
            <div className="text-[13px] font-semibold">Connection health</div>
            <Btn size="sm" variant="ghost" icon="chev-right" onClick={()=>onGo('integrations')}>Manage</Btn>
          </div>
          <div className="space-y-1.5">
            {integrations.map(i=>{
              const tone = i.status!=='connected' ? '#8b8b80' : i.health==='degraded' ? '#f59e0b' : '#10b981';
              const lbl  = i.status!=='connected' ? 'Disconnected' : i.health==='degraded' ? 'Degraded' : 'Healthy';
              return (
                <div key={i.id} className="flex items-center gap-3 px-3 py-2.5 rounded-xl bg-ink-50 dark:bg-white/[0.03] border border-ink-100 dark:border-white/5">
                  <span className="inline-flex items-center justify-center w-8 h-8 rounded-lg text-ink-900 dark:text-white" style={{ background:`${i.tone}14` }}><BrandIcon name={PROVIDER_ICON[i.provider]||'custom'} size={20}/></span>
                  <div className="flex-1 min-w-0">
                    <div className="text-[13px] font-medium flex items-center gap-2">{i.name}
                      <span className="text-[10px] font-mono uppercase tracking-wide text-ink-400">{i.kind}</span>
                    </div>
                    <div className="text-[11px] text-ink-500 dark:text-ink-300 font-mono truncate">{i.endpoint || 'not configured'}</div>
                  </div>
                  <span className="inline-flex items-center gap-1.5 text-[11.5px] font-medium" style={{ color:tone }}>
                    <span className="w-1.5 h-1.5 rounded-full" style={{ background:tone }}/>{lbl}
                  </span>
                </div>
              );
            })}
          </div>
        </Card>

        <Card className="col-span-12 lg:col-span-5 p-5 rounded-2xl">
          <div className="flex items-center justify-between mb-3">
            <div className="text-[13px] font-semibold">Team by role</div>
            <Btn size="sm" variant="ghost" icon="chev-right" onClick={()=>onGo('users')}>Open team</Btn>
          </div>
          <div className="space-y-2.5">
            {byRole.map(({role,n})=>{
              const r = ROLES[role];
              const pct = Math.round(n/users.length*100);
              return (
                <div key={role}>
                  <div className="flex items-center justify-between text-[12.5px] mb-1">
                    <span className="flex items-center gap-2"><span className="w-2 h-2 rounded-full" style={{ background:r.tone }}/>{r.label}</span>
                    <span className="font-mono text-ink-500">{n}</span>
                  </div>
                  <div className="h-1.5 rounded-full bg-ink-100 dark:bg-white/10 overflow-hidden">
                    <div className="h-full rounded-full" style={{ width:`${pct}%`, background:r.tone }}/>
                  </div>
                </div>
              );
            })}
          </div>
        </Card>

        {audit && (
          <Card className="col-span-12 p-5 rounded-2xl">
            <div className="flex items-center justify-between mb-2">
              <div className="text-[13px] font-semibold">Recent activity</div>
              <Btn size="sm" variant="ghost" icon="chev-right" onClick={()=>onGo('activity')}>Full log</Btn>
            </div>
            <div className="grid md:grid-cols-2 gap-x-4 divide-ink-100 dark:divide-white/5">
              {audit.slice(0,6).map(ev=> <AuditRow key={ev.id} ev={ev}/> )}
            </div>
          </Card>
        )}
      </div>
    </div>
  );
}

/* ---------- Account access editor ---------------------------------- */
function AccountAccess({ value, onChange }){
  const all = value === '*' || (Array.isArray(value) && value.includes('*'));
  const ids = all ? [] : (Array.isArray(value) ? value : []);
  const toggle = (id) => {
    const next = ids.includes(id) ? ids.filter(x=>x!==id) : [...ids, id];
    onChange(next);
  };
  return (
    <div>
      <button type="button" onClick={()=>onChange(all ? [] : '*')}
        className={`w-full flex items-center justify-between px-3 h-10 rounded-xl border text-[13px] font-medium transition
          ${all ? 'border-accent-300 bg-accent-50 text-accent-700 dark:bg-accent-500/15 dark:border-accent-500/40 dark:text-accent-200'
                : 'border-ink-200 dark:border-white/10 hover:bg-ink-50 dark:hover:bg-white/5'}`}>
        <span className="flex items-center gap-2"><Icon name="check" size={14} className={all?'opacity-100':'opacity-0'}/> All accounts</span>
        <span className="text-[11px] font-mono text-ink-400">{ACCOUNTS.length} total</span>
      </button>
      <div className={`mt-2 space-y-1 transition ${all?'opacity-40 pointer-events-none':''}`}>
        {ACCOUNTS.map(a=>{
          const on = all || ids.includes(a.id);
          return (
            <button key={a.id} type="button" onClick={()=>toggle(a.id)}
              className="w-full flex items-center gap-2.5 px-2.5 py-2 rounded-lg hover:bg-ink-100 dark:hover:bg-white/5 text-left transition">
              <span className={`w-4 h-4 rounded grid place-items-center border ${on?'bg-accent-500 border-accent-500':'border-ink-300 dark:border-white/20'}`}>
                {on && <Icon name="check" size={11} className="text-white"/>}
              </span>
              <span className="inline-flex items-center justify-center w-6 h-6 rounded-md bg-ink-900 text-white dark:bg-white dark:text-ink-900 font-bold text-[9px] font-mono">
                {a.name.split(' ').map(s=>s[0]).slice(0,2).join('')}
              </span>
              <span className="flex-1 min-w-0">
                <span className="text-[12.5px] font-medium block truncate">{a.name}</span>
              </span>
              <span className="text-[10.5px] font-mono text-ink-400">{a.tier}</span>
            </button>
          );
        })}
      </div>
    </div>
  );
}

/* ---------- User edit drawer --------------------------------------- */
function UserEditDrawer({ open, user, isNew, onClose, onSave, onDelete, currentUser, users }){
  const blank = { name:'', email:'', role:'viewer', accounts:[], password:'', tone:AVATAR_TONES[0], status:'active', twoFA:false, title:'' };
  const [draft, setDraft] = useState(blank);
  const [showPw, setShowPw] = useState(false);
  const [err, setErr] = useState('');
  useEffect(()=>{ if(open){ setDraft(user ? {...user} : blank); setErr(''); setShowPw(false); } }, [open, user]);

  const set = (k,v)=>setDraft(d=>({...d,[k]:v}));
  const isSelf = currentUser && user && currentUser.id === user.id;

  const save = () => {
    if (!draft.name.trim()) return setErr('Name is required.');
    if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(draft.email)) return setErr('Enter a valid email address.');
    const dup = users.find(u=>u.email.toLowerCase()===draft.email.trim().toLowerCase() && u.id!==draft.id);
    if (dup) return setErr('That email is already in use.');
    if (isNew && (!draft.password || draft.password.length<6)) return setErr('Set a password (min 6 characters).');
    onSave({
      ...draft,
      id: draft.id || ('u_'+Math.random().toString(36).slice(2,9)),
      email: draft.email.trim(),
      name: draft.name.trim(),
      accounts: draft.accounts === '*' ? '*' : draft.accounts,
      lastActive: draft.lastActive || Date.now(),
    });
    onClose();
  };

  return (
    <Drawer open={open} onClose={onClose} width={460}
      title={<><Icon name="settings" size={15}/> {isNew?'Invite team member':'Edit member'}</>}
      footer={
        <>
          {!isNew && !isSelf && (
            <button onClick={()=>{ onDelete(draft.id); onClose(); }}
              className="mr-auto inline-flex items-center gap-1.5 h-9 px-3 rounded-lg text-[12.5px] font-medium text-rose-600 dark:text-rose-300 hover:bg-rose-50 dark:hover:bg-rose-500/10 transition">
              <Icon name="x" size={14}/> Remove
            </button>
          )}
          <Btn variant="ghost" onClick={onClose}>Cancel</Btn>
          <Btn variant="accent" icon="check" onClick={save}>{isNew?'Send invite':'Save changes'}</Btn>
        </>
      }>
      <div className="p-5 space-y-5">
        {err && (
          <div className="flex items-start gap-2 text-[12.5px] text-rose-700 dark:text-rose-300 bg-rose-50 dark:bg-rose-500/10 border border-rose-200 dark:border-rose-500/25 rounded-lg px-3 py-2">
            <Icon name="alert" size={14} className="mt-0.5"/> {err}
          </div>
        )}

        {/* identity */}
        <div className="flex items-center gap-3">
          <Avatar user={draft} size={56}/>
          <div className="flex-1">
            <div className="text-[11px] font-medium text-ink-500 dark:text-ink-300 mb-1.5">Avatar color</div>
            <div className="flex flex-wrap gap-1.5">
              {AVATAR_TONES.map(t=>(
                <button key={t} type="button" onClick={()=>set('tone',t)}
                  className={`w-6 h-6 rounded-lg transition ${draft.tone===t?'ring-2 ring-offset-2 ring-offset-white dark:ring-offset-ink-800':''}`}
                  style={{ background:t, ['--tw-ring-color']:t }}/>
              ))}
            </div>
          </div>
        </div>

        <Field label="Full name">
          <input value={draft.name} onChange={e=>set('name',e.target.value)} placeholder="Jane Doe" className={inputCls}/>
        </Field>
        <div className="grid grid-cols-2 gap-3">
          <Field label="Email">
            <input value={draft.email} onChange={e=>set('email',e.target.value)} placeholder="jane@company.com" className={inputCls}/>
          </Field>
          <Field label="Title (optional)">
            <input value={draft.title||''} onChange={e=>set('title',e.target.value)} placeholder="Media Buyer" className={inputCls}/>
          </Field>
        </div>

        {/* role */}
        <Field label="Role & permission level">
          <div className="space-y-1.5">
            {ROLE_ORDER.map(r=>{
              const role = ROLES[r];
              const on = draft.role===r;
              return (
                <button key={r} type="button" onClick={()=>set('role',r)}
                  className={`w-full flex items-start gap-2.5 px-3 py-2.5 rounded-xl border text-left transition
                    ${on?'border-accent-300 bg-accent-50 dark:bg-accent-500/10 dark:border-accent-500/40':'border-ink-200 dark:border-white/10 hover:bg-ink-50 dark:hover:bg-white/5'}`}>
                  <span className={`mt-0.5 w-4 h-4 rounded-full grid place-items-center border-2 flex-shrink-0`} style={{ borderColor:role.tone }}>
                    {on && <span className="w-2 h-2 rounded-full" style={{ background:role.tone }}/>}
                  </span>
                  <span className="flex-1 min-w-0">
                    <span className="flex items-center gap-2"><span className="text-[13px] font-semibold">{role.label}</span></span>
                    <span className="text-[11.5px] text-ink-500 dark:text-ink-300 block leading-snug">{role.blurb}</span>
                  </span>
                </button>
              );
            })}
          </div>
        </Field>

        {/* accounts */}
        <Field label="Account access" hint="Which ad accounts this member can see">
          <AccountAccess value={draft.accounts} onChange={v=>set('accounts',v)}/>
        </Field>

        {/* password */}
        <Field label={isNew?'Set password':'Reset password'} hint={isNew?'Min 6 characters':'Leave blank to keep current'}>
          <div className="relative">
            <input type={showPw?'text':'password'} value={draft.password||''} onChange={e=>set('password',e.target.value)}
              placeholder={isNew?'••••••••':'Unchanged'} className={inputCls+' pr-11'}/>
            <button type="button" onClick={()=>setShowPw(s=>!s)} className="absolute right-1.5 top-1/2 -translate-y-1/2 h-8 w-8 grid place-items-center rounded-lg text-ink-400 hover:bg-ink-100 dark:hover:bg-white/10">
              <Icon name="eye" size={15}/>
            </button>
          </div>
        </Field>

        {/* toggles */}
        <div className="space-y-2.5 pt-1">
          <div className="flex items-center justify-between px-3 h-12 rounded-xl border border-ink-200 dark:border-white/10">
            <div>
              <div className="text-[13px] font-medium">Two-factor authentication</div>
              <div className="text-[11px] text-ink-500 dark:text-ink-300">{draft.twoFA?'Marked for 2FA — sign-in enforcement ships in a later release':'Disabled'}</div>
            </div>
            <Toggle checked={!!draft.twoFA} onChange={v=>set('twoFA',v)}/>
          </div>
          <div className="flex items-center justify-between px-3 h-12 rounded-xl border border-ink-200 dark:border-white/10">
            <div>
              <div className="text-[13px] font-medium">Account status</div>
              <div className="text-[11px] text-ink-500 dark:text-ink-300">{draft.status==='active'?'Active — can sign in':'Suspended — sign-in blocked'}</div>
            </div>
            <Toggle checked={draft.status==='active'} onChange={v=>set('status', v?'active':'suspended')}/>
          </div>
        </div>
      </div>
    </Drawer>
  );
}

const inputCls = "w-full h-10 px-3 rounded-xl bg-white dark:bg-ink-900/40 border border-ink-200 dark:border-white/10 text-[13.5px] focus:outline-none focus:border-accent-400 focus:ring-2 focus:ring-accent-100 dark:focus:ring-accent-500/20 transition";
function Field({ label, hint, children }){
  return (
    <label className="block">
      <span className="flex items-center justify-between mb-1.5">
        <span className="text-[12px] font-medium text-ink-700 dark:text-ink-200">{label}</span>
        {hint && <span className="text-[10.5px] text-ink-400">{hint}</span>}
      </span>
      {children}
    </label>
  );
}

/* ---------- Users manager ------------------------------------------ */
function UsersManager({ users, setUsers, currentUser, readOnly, pushAudit }){
  const [query, setQuery] = useState('');
  const [roleFilter, setRoleFilter] = useState('all');
  const [edit, setEdit] = useState(null); // {user, isNew} | null

  const filtered = users.filter(u=>{
    if (roleFilter!=='all' && u.role!==roleFilter) return false;
    const q = query.trim().toLowerCase();
    if (!q) return true;
    return u.name.toLowerCase().includes(q) || u.email.toLowerCase().includes(q);
  });

  const [saveErr, setSaveErr] = useState('');
  const saveUser = async (u) => {
    const exists = users.some(x=>x.id===u.id);
    const payload = { name:u.name, email:u.email, role:u.role, accounts:u.accounts,
      tone:u.tone, status:u.status, twoFA:u.twoFA, title:u.title };
    if (u.password) payload.password = u.password;
    try {
      const saved = exists ? await RelayAPI.users.update(u.id, payload) : await RelayAPI.users.create(payload);
      setUsers(arr => { const i = arr.findIndex(x=>x.id===saved.id);
        if (i>=0){ const next=[...arr]; next[i]=saved; return next; } return [...arr, saved]; });
      setSaveErr(''); if (pushAudit) pushAudit();
    } catch(e){ setSaveErr(e.message || 'Could not save member.'); }
  };
  const deleteUser = async (id) => {
    try { await RelayAPI.users.remove(id); setUsers(arr => arr.filter(x=>x.id!==id)); if(pushAudit) pushAudit(); }
    catch(e){ setSaveErr(e.message || 'Could not remove member.'); }
  };
  const fmtAgo = (ts)=>{ if(!ts) return '—'; const s=Math.floor((Date.now()-ts)/1000);
    if(s<60)return s+'s ago'; if(s<3600)return Math.floor(s/60)+'m ago'; if(s<86400)return Math.floor(s/3600)+'h ago'; return Math.floor(s/86400)+'d ago'; };

  return (
    <div>
      <div className="flex items-center justify-between gap-3 mb-4 flex-wrap">
        <div>
          <h2 className="text-[18px] font-semibold tracking-tight">Team & permissions</h2>
          <p className="text-[12.5px] text-ink-500 dark:text-ink-300">{users.length} members · manage roles, access and security.</p>
        </div>
        {!readOnly && (
          <Btn variant="accent" icon="plus" onClick={()=>setEdit({ user:null, isNew:true })}>Invite member</Btn>
        )}
      </div>

      <div className="flex items-center gap-2 mb-3 flex-wrap">
        <div className="relative h-9 w-[240px]">
          <Icon name="search" size={14} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-ink-400"/>
          <input value={query} onChange={e=>setQuery(e.target.value)} placeholder="Search name or email…"
            className="w-full h-full pl-8 pr-3 rounded-lg border border-ink-200 dark:border-white/10 bg-white dark:bg-ink-900/40 text-[12.5px] focus:outline-none focus:border-accent-400"/>
        </div>
        <div className="flex items-center gap-1 bg-ink-100/70 dark:bg-white/5 rounded-lg p-1">
          {['all',...ROLE_ORDER].map(r=>(
            <button key={r} onClick={()=>setRoleFilter(r)}
              className={`px-2.5 h-7 rounded-md text-[12px] font-medium transition ${roleFilter===r?'bg-white dark:bg-ink-800 shadow-card':'text-ink-500 dark:text-ink-300 hover:text-ink-800 dark:hover:text-white'}`}>
              {r==='all'?'All':ROLES[r].label}
            </button>
          ))}
        </div>
      </div>

      {readOnly && (
        <div className="mb-3 flex items-center gap-2 text-[12px] text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-500/10 border border-amber-200 dark:border-amber-500/25 rounded-lg px-3 py-2">
          <Icon name="alert" size={14}/> You can view the team, but only a Super Admin can add or edit members.
        </div>
      )}
      {saveErr && (
        <div className="mb-3 flex items-center gap-2 text-[12px] text-rose-700 dark:text-rose-300 bg-rose-50 dark:bg-rose-500/10 border border-rose-200 dark:border-rose-500/25 rounded-lg px-3 py-2">
          <Icon name="alert" size={14}/> {saveErr}
        </div>
      )}

      <Card className="rounded-2xl overflow-hidden">
        <div className="px-4 py-2.5 grid items-center gap-3 text-[11px] font-medium uppercase tracking-wide text-ink-400 border-b border-ink-200 dark:border-white/10 bg-ink-50/60 dark:bg-white/[0.02]"
          style={{ gridTemplateColumns:'minmax(220px,1.8fr) 130px 1fr 70px 110px 90px 40px' }}>
          <div>Member</div><div>Role</div><div>Account access</div><div>2FA</div><div>Last active</div><div>Status</div><div></div>
        </div>
        {filtered.map(u=>{
          const acc = u.accounts==='*' ? 'All accounts' : `${(u.accounts||[]).length} account${(u.accounts||[]).length===1?'':'s'}`;
          const suspended = u.status==='suspended';
          return (
            <div key={u.id} className={`px-4 py-3 grid items-center gap-3 border-b border-ink-100 dark:border-white/5 last:border-0 hover:bg-ink-50/60 dark:hover:bg-white/[0.03] transition ${suspended?'opacity-60':''}`}
              style={{ gridTemplateColumns:'minmax(220px,1.8fr) 130px 1fr 70px 110px 90px 40px' }}>
              <div className="flex items-center gap-2.5 min-w-0">
                <Avatar user={u} size={36}/>
                <div className="min-w-0">
                  <div className="text-[13px] font-semibold truncate flex items-center gap-1.5">{u.name}
                    {currentUser.id===u.id && <span className="text-[9.5px] font-mono px-1 py-0.5 rounded bg-accent-100 text-accent-700 dark:bg-accent-500/15 dark:text-accent-200">YOU</span>}
                  </div>
                  <div className="text-[11px] text-ink-500 dark:text-ink-300 font-mono truncate">{u.email}</div>
                </div>
              </div>
              <div><RoleBadge role={u.role}/></div>
              <div className="text-[12px] text-ink-600 dark:text-ink-200 truncate">{acc}</div>
              <div>{u.twoFA
                ? <Pill tone="good"><Icon name="check" size={10}/> On</Pill>
                : <span className="text-[11.5px] text-ink-400">Off</span>}</div>
              <div className="text-[11.5px] text-ink-500 dark:text-ink-300 font-mono">{fmtAgo(u.lastActive)}</div>
              <div>{suspended
                ? <Pill tone="bad">Suspended</Pill>
                : <Pill tone="neutral"><span className="w-1.5 h-1.5 rounded-full bg-emerald-500"/> Active</Pill>}</div>
              <div className="flex justify-end">
                {!readOnly && (
                  <button onClick={()=>setEdit({ user:u, isNew:false })}
                    className="h-8 w-8 grid place-items-center rounded-lg hover:bg-ink-100 dark:hover:bg-white/10 text-ink-500">
                    <Icon name="settings" size={15}/>
                  </button>
                )}
              </div>
            </div>
          );
        })}
        {filtered.length===0 && <div className="px-4 py-10 text-center text-[13px] text-ink-400">No members match your filter.</div>}
      </Card>

      <UserEditDrawer
        open={!!edit}
        user={edit?.user}
        isNew={edit?.isNew}
        users={users}
        currentUser={currentUser}
        onClose={()=>setEdit(null)}
        onSave={saveUser}
        onDelete={deleteUser}
      />
    </div>
  );
}

/* ---------- Roles reference ---------------------------------------- */
function RolesReference(){
  const PERMS = [
    { key:'view',                label:'View dashboards & reports' },
    { key:'columns.build',       label:'Build custom columns / reports' },
    { key:'campaigns.edit',      label:'Pause / edit campaigns' },
    { key:'automations.manage',  label:'Create & run automations' },
    { key:'reallocate.apply',    label:'Apply budget reallocation' },
    { key:'integrations.manage', label:'Manage integrations & connections' },
    { key:'accounts.manage',     label:'Manage ad accounts' },
    { key:'users.manage',        label:'Manage team members & roles' },
  ];
  const has = (role, key) => { const p=ROLES[role].perms; return p.includes('*')||p.includes(key); };
  return (
    <div>
      <div className="mb-4">
        <h2 className="text-[18px] font-semibold tracking-tight">Roles & permissions</h2>
        <p className="text-[12.5px] text-ink-500 dark:text-ink-300">What each permission level can do across the workspace.</p>
      </div>
      <Card className="rounded-2xl overflow-hidden">
        <div className="grid border-b border-ink-200 dark:border-white/10 bg-ink-50/60 dark:bg-white/[0.02]"
          style={{ gridTemplateColumns:`minmax(240px,1.4fr) repeat(${ROLE_ORDER.length}, 1fr)` }}>
          <div className="px-4 py-3 text-[12px] font-semibold">Capability</div>
          {ROLE_ORDER.map(r=>(
            <div key={r} className="px-2 py-3 text-center">
              <RoleBadge role={r} size="sm"/>
            </div>
          ))}
        </div>
        {PERMS.map(perm=>(
          <div key={perm.key} className="grid border-b border-ink-100 dark:border-white/5 last:border-0 items-center hover:bg-ink-50/50 dark:hover:bg-white/[0.02]"
            style={{ gridTemplateColumns:`minmax(240px,1.4fr) repeat(${ROLE_ORDER.length}, 1fr)` }}>
            <div className="px-4 py-3 text-[12.5px]">{perm.label}</div>
            {ROLE_ORDER.map(r=>(
              <div key={r} className="px-2 py-3 grid place-items-center">
                {has(r,perm.key)
                  ? <span className="w-5 h-5 rounded-full grid place-items-center" style={{ background:`${ROLES[r].tone}1f` }}><Icon name="check" size={12} style={{ color:ROLES[r].tone }}/></span>
                  : <span className="w-1.5 h-1.5 rounded-full bg-ink-200 dark:bg-white/10"/>}
              </div>
            ))}
          </div>
        ))}
      </Card>
    </div>
  );
}

/* ===================================================================
   Activity / audit log
=================================================================== */
function relTime(ts){
  const s = Math.floor((Date.now()-ts)/1000);
  if (s<60) return s+'s ago';
  if (s<3600) return Math.floor(s/60)+'m ago';
  if (s<86400) return Math.floor(s/3600)+'h ago';
  return Math.floor(s/86400)+'d ago';
}
function AuditRow({ ev, compact }){
  const m = AUDIT_META[ev.action] || { icon:'info', tone:'#8b8b80', verb:ev.action };
  return (
    <div className="flex items-start gap-3 px-3 py-2.5 rounded-xl hover:bg-ink-50 dark:hover:bg-white/[0.03] transition">
      <span className="mt-0.5 inline-flex items-center justify-center w-7 h-7 rounded-lg flex-shrink-0" style={{ background:`${m.tone}1a`, color:m.tone }}>
        <Icon name={m.icon} size={14}/>
      </span>
      <div className="flex-1 min-w-0">
        <div className="text-[12.5px] leading-snug">
          <span className="font-semibold">{ev.actorName}</span>
          <span className="text-ink-500 dark:text-ink-300"> {m.verb} </span>
          <span className="font-medium">{ev.target}</span>
          {ev.detail && <span className="text-ink-500 dark:text-ink-300"> · {ev.detail}</span>}
        </div>
        <div className="text-[10.5px] font-mono text-ink-400 mt-0.5">{relTime(ev.ts)}</div>
      </div>
    </div>
  );
}
function AuditLog({ audit }){
  const [filter, setFilter] = useState('all');
  const groups = [
    { id:'all',   label:'All' },
    { id:'user',  label:'Team' },
    { id:'integration', label:'Connections' },
    { id:'auth',  label:'Sign-in' },
  ];
  const rows = audit.filter(e => filter==='all' || e.action.startsWith(filter));
  return (
    <div>
      <div className="flex items-center justify-between gap-3 mb-4 flex-wrap">
        <div>
          <h2 className="text-[18px] font-semibold tracking-tight">Activity log</h2>
          <p className="text-[12.5px] text-ink-500 dark:text-ink-300">Every change to team, roles & connections — newest first.</p>
        </div>
        <div className="flex items-center gap-1 bg-ink-100/70 dark:bg-white/5 rounded-lg p-1">
          {groups.map(g=>(
            <button key={g.id} onClick={()=>setFilter(g.id)}
              className={`px-2.5 h-7 rounded-md text-[12px] font-medium transition ${filter===g.id?'bg-white dark:bg-ink-800 shadow-card':'text-ink-500 dark:text-ink-300 hover:text-ink-800 dark:hover:text-white'}`}>
              {g.label}
            </button>
          ))}
        </div>
      </div>
      <Card className="rounded-2xl p-2">
        {rows.length===0 && <div className="px-4 py-10 text-center text-[13px] text-ink-400">No activity in this category yet.</div>}
        <div className="divide-y divide-ink-100 dark:divide-white/5">
          {rows.map(ev=> <AuditRow key={ev.id} ev={ev}/> )}
        </div>
      </Card>
    </div>
  );
}

/* ===================================================================
   Branding manager (super admin only)
=================================================================== */
function BrandingManager({ brand, setBrand, currentUser, pushAudit }){
  const isSuper = currentUser.role === 'super_admin';
  const [draft, setDraft] = useState(brand);
  const [err, setErr] = useState('');
  const fileRef = useRef(null);
  useEffect(()=>{ setDraft(brand); }, [brand]);
  const set = (k,v)=>setDraft(d=>({...d,[k]:v}));
  const dirty = JSON.stringify(draft)!==JSON.stringify(brand);

  const onLogo = (file)=>{
    setErr('');
    if (!file) return;
    if (!/image\/(png|jpeg|svg\+xml|webp|gif)/.test(file.type)){ setErr('Use a PNG, JPG, SVG or WebP image.'); return; }
    if (file.size > 1.5*1024*1024){ setErr('Logo must be under 1.5MB.'); return; }
    const r = new FileReader(); r.onload = e=>set('logo', e.target.result); r.readAsDataURL(file);
  };
  const save = ()=>{ setBrand(draft); if(pushAudit) pushAudit(currentUser,'integration.update','Workspace branding', draft.name); };
  const ACCENTS = ['#8351ff','#2f7bff','#10b981','#06b6d4','#f59e0b','#ec4899','#ef4444','#111827'];

  return (
    <div className="max-w-[760px]">
      <div className="mb-4">
        <h2 className="text-[18px] font-semibold tracking-tight">Branding</h2>
        <p className="text-[12.5px] text-ink-500 dark:text-ink-300">Name, tag, accent and logo — applied across the login screen, sidebar and tab title.</p>
      </div>

      {!isSuper && (
        <div className="mb-4 flex items-center gap-2 text-[12.5px] text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-500/10 border border-amber-200 dark:border-amber-500/25 rounded-lg px-3 py-2">
          <Icon name="alert" size={14}/> Only a Super Admin can change branding.
        </div>
      )}

      <div className={`grid md:grid-cols-2 gap-4 ${isSuper?'':'opacity-60 pointer-events-none'}`}>
        {/* live preview */}
        <Card className="p-5 rounded-2xl">
          <div className="text-[11px] uppercase tracking-wide font-semibold text-ink-400 mb-3">Preview</div>
          <div className="rounded-xl bg-ink-900 p-4 flex items-center gap-2.5 mb-3">
            <BrandLogo brand={draft} size={34}/>
            <Wordmark light size={20} brand={draft}/>
          </div>
          <div className="flex items-center gap-2.5 px-3 py-2 rounded-xl border border-ink-200 dark:border-white/10">
            <BrandLogo brand={draft} size={26}/>
            <Wordmark size={16} brand={draft}/>
          </div>
        </Card>

        {/* logo */}
        <Card className="p-5 rounded-2xl">
          <div className="text-[12px] font-medium mb-2">Logo</div>
          <div className="flex items-center gap-3">
            <div className="w-16 h-16 rounded-xl border border-ink-200 dark:border-white/10 grid place-items-center bg-ink-50 dark:bg-white/5 flex-shrink-0">
              <BrandLogo brand={draft} size={40}/>
            </div>
            <div className="flex-1">
              <input ref={fileRef} type="file" accept="image/*" className="hidden" onChange={e=>onLogo(e.target.files[0])}/>
              <Btn size="sm" variant="accent" icon="plus" onClick={()=>fileRef.current.click()}>Upload logo</Btn>
              {draft.logo && <button onClick={()=>set('logo',null)} className="ml-2 text-[12px] text-rose-600 dark:text-rose-300 hover:underline">Remove</button>}
              <div className="text-[10.5px] text-ink-400 mt-1.5">PNG/SVG · square · &lt; 1.5MB. Falls back to the default mark.</div>
            </div>
          </div>
        </Card>

        {/* fields */}
        <Card className="p-5 rounded-2xl md:col-span-2 space-y-4">
          <div className="grid sm:grid-cols-2 gap-4">
            <Field label="Workspace name"><input value={draft.name} onChange={e=>set('name',e.target.value)} placeholder="Relay" className={inputCls}/></Field>
            <Field label="Tag (optional)" hint="small badge next to name"><input value={draft.tag||''} onChange={e=>set('tag',e.target.value)} placeholder="MCP" className={inputCls}/></Field>
          </div>
          <div>
            <div className="text-[12px] font-medium text-ink-700 dark:text-ink-200 mb-1.5">Accent color</div>
            <div className="flex flex-wrap gap-2">
              {ACCENTS.map(c=>(
                <button key={c} onClick={()=>set('accent',c)} className={`w-8 h-8 rounded-lg transition ${draft.accent===c?'ring-2 ring-offset-2 ring-offset-white dark:ring-offset-ink-800':''}`} style={{ background:c, ['--tw-ring-color']:c }}/>
              ))}
            </div>
          </div>
          {err && <div className="text-[12.5px] text-rose-600 dark:text-rose-300 flex items-center gap-2"><Icon name="alert" size={14}/>{err}</div>}
          <div className="flex items-center gap-2 pt-1">
            <Btn variant="accent" icon="check" onClick={save} disabled={!dirty}>Save branding</Btn>
            {dirty && <Btn variant="ghost" onClick={()=>setDraft(brand)}>Discard</Btn>}
            <button onClick={()=>setDraft({...BRAND_DEFAULT})} className="ml-auto text-[12px] text-ink-500 hover:text-ink-800 dark:hover:text-white">Reset to default</button>
          </div>
        </Card>
      </div>
    </div>
  );
}

/* ===================================================================
   Ad accounts manager — superadmin chooses which accounts to pull
=================================================================== */
function AccountEditDrawer({ open, account, isNew, onClose, onSave }){
  const blank = { name:'', handle:'', currency:'USD', tier:'', synced:true, sources:{} };
  const [draft, setDraft] = useState(blank);
  const [err, setErr] = useState('');
  useEffect(()=>{ if(open){ setDraft(account ? {...blank, ...account, sources:{...(account.sources||{})}} : blank); setErr(''); } }, [open, account]);
  const set = (k,v)=>setDraft(d=>({...d,[k]:v}));
  const setSrc = (k,v)=>setDraft(d=>({...d, sources:{...(d.sources||{}), [k]:v}}));
  const save = () => {
    if (!draft.name.trim()) return setErr('Account name is required.');
    /* Persist every mappable platform (was hardcoded to meta/google/tiktok,
       which silently dropped X + LinkedIn source IDs on save). */
    const sources = {};
    SRC_PLATFORMS.forEach(s=>{ const v=(draft.sources||{})[s.id]; if(v && String(v).trim()) sources[s.id]=String(v).trim(); });
    onSave({ ...draft, name:draft.name.trim(), sources }, isNew);
    onClose();
  };
  const srcMeta = SRC_PLATFORMS;
  return (
    <Drawer open={open} onClose={onClose} width={460}
      title={<><Icon name="sparkles" size={15}/> {isNew?'Add ad account':'Edit ad account'}</>}
      footer={<><Btn variant="ghost" onClick={onClose}>Cancel</Btn><Btn variant="accent" icon="check" onClick={save}>{isNew?'Add account':'Save changes'}</Btn></>}>
      <div className="p-5 space-y-5">
        {err && <div className="flex items-start gap-2 text-[12.5px] text-rose-700 dark:text-rose-300 bg-rose-50 dark:bg-rose-500/10 border border-rose-200 dark:border-rose-500/25 rounded-lg px-3 py-2"><Icon name="alert" size={14} className="mt-0.5"/> {err}</div>}
        <div className="grid grid-cols-2 gap-3">
          <Field label="Account name"><input value={draft.name} onChange={e=>set('name',e.target.value)} placeholder="Amasi Ash-Shamal" className={inputCls}/></Field>
          <Field label="Handle (optional)"><input value={draft.handle||''} onChange={e=>set('handle',e.target.value)} placeholder="@amasi" className={inputCls}/></Field>
        </div>
        <div className="grid grid-cols-2 gap-3">
          <Field label="Currency"><input value={draft.currency||'USD'} onChange={e=>set('currency',e.target.value.toUpperCase().slice(0,3))} placeholder="SAR" className={inputCls}/></Field>
          <Field label="Tier (optional)"><input value={draft.tier||''} onChange={e=>set('tier',e.target.value)} placeholder="Performance" className={inputCls}/></Field>
        </div>
        <div className="flex items-center justify-between px-3 h-12 rounded-xl border border-ink-200 dark:border-white/10">
          <div>
            <div className="text-[13px] font-medium">Pull data for this account</div>
            <div className="text-[11px] text-ink-500 dark:text-ink-300">{draft.synced?'Synced — included in data pulls':'Paused — excluded from pulls'}</div>
          </div>
          <Toggle checked={!!draft.synced} onChange={v=>set('synced',v)}/>
        </div>
        <div>
          <div className="text-[12px] font-medium text-ink-700 dark:text-ink-200 mb-2">Platform source IDs</div>
          <div className="space-y-2">
            {srcMeta.map(s=>(
              <div key={s.id} className="flex items-center gap-2">
                <span className="inline-flex items-center justify-center w-7 h-7 rounded-lg bg-ink-100 dark:bg-white/5 text-ink-900 dark:text-white flex-shrink-0"><BrandIcon name={s.icon} size={16}/></span>
                <input value={(draft.sources||{})[s.id]||''} onChange={e=>setSrc(s.id, e.target.value)} placeholder={s.label+' · '+s.hint} className={inputCls+' font-mono text-[12px]'}/>
              </div>
            ))}
          </div>
          <div className="text-[10.5px] text-ink-400 mt-1.5">These map the dashboard account to its external ad accounts. The sync pulls each platform's data using these IDs.</div>
        </div>
      </div>
    </Drawer>
  );
}

function AccountsManager({ accounts, setAccounts, currentUser, readOnly, pushAudit }){
  const [edit, setEdit] = useState(null);
  const [err, setErr] = useState('');
  const save = async (a, isNew) => {
    const payload = { name:a.name, handle:a.handle, currency:a.currency, tier:a.tier, synced:a.synced, sources:a.sources };
    try {
      const saved = isNew ? await RelayAPI.accounts.create(payload) : await RelayAPI.accounts.update(a.id, payload);
      setAccounts(arr => { const i=arr.findIndex(x=>x.id===saved.id); if(i>=0){const n=[...arr];n[i]=saved;return n;} return [...arr, saved]; });
      setErr(''); if (pushAudit) pushAudit();
    } catch(e){ setErr(e.message || 'Could not save account.'); }
  };
  const toggleSync = async (a) => {
    try { const saved = await RelayAPI.accounts.update(a.id, { synced:!a.synced });
      setAccounts(arr => arr.map(x=>x.id===saved.id?saved:x)); if (pushAudit) pushAudit(); }
    catch(e){ setErr(e.message || 'Could not update account.'); }
  };
  const remove = async (id) => {
    if (!confirm('Remove this account from the dashboard? Stored data stays in the warehouse.')) return;
    try { await RelayAPI.accounts.remove(id); setAccounts(arr => arr.filter(x=>x.id!==id)); if (pushAudit) pushAudit(); }
    catch(e){ setErr(e.message || 'Could not remove account.'); }
  };
  const syncedCount = accounts.filter(a=>a.synced).length;

  return (
    <div>
      <div className="flex items-center justify-between gap-3 mb-4 flex-wrap">
        <div>
          <h2 className="text-[18px] font-semibold tracking-tight">Ad accounts</h2>
          <p className="text-[12.5px] text-ink-500 dark:text-ink-300">{accounts.length} accounts · {syncedCount} pulling data. Toggle which accounts sync, or map their platform source IDs.</p>
        </div>
        {!readOnly && <Btn variant="accent" icon="plus" onClick={()=>setEdit({ account:null, isNew:true })}>Add account</Btn>}
      </div>

      {err && <div className="mb-3 flex items-center gap-2 text-[12px] text-rose-700 dark:text-rose-300 bg-rose-50 dark:bg-rose-500/10 border border-rose-200 dark:border-rose-500/25 rounded-lg px-3 py-2"><Icon name="alert" size={14}/> {err}</div>}
      {readOnly && <div className="mb-3 flex items-center gap-2 text-[12px] text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-500/10 border border-amber-200 dark:border-amber-500/25 rounded-lg px-3 py-2"><Icon name="alert" size={14}/> Only admins can manage ad accounts.</div>}

      <Card className="rounded-2xl overflow-hidden">
        <div className="px-4 py-2.5 grid items-center gap-3 text-[11px] font-medium uppercase tracking-wide text-ink-400 border-b border-ink-200 dark:border-white/10 bg-ink-50/60 dark:bg-white/[0.02]"
          style={{ gridTemplateColumns:'minmax(200px,1.6fr) 160px 90px 90px 40px' }}>
          <div>Account</div><div>Sources</div><div>Currency</div><div>Pull</div><div></div>
        </div>
        {accounts.length===0 && <div className="px-4 py-10 text-center text-[13px] text-ink-400">No accounts yet. Click “Add account”.</div>}
        {accounts.map(a=>{
          const src = a.sources || {};
          return (
            <div key={a.id} className={`px-4 py-3 grid items-center gap-3 border-b border-ink-100 dark:border-white/5 last:border-0 hover:bg-ink-50/60 dark:hover:bg-white/[0.03] transition ${a.synced?'':'opacity-60'}`}
              style={{ gridTemplateColumns:'minmax(200px,1.6fr) 160px 90px 90px 40px' }}>
              <div className="min-w-0">
                <div className="text-[13px] font-semibold truncate">{a.name}</div>
                <div className="text-[11px] text-ink-500 dark:text-ink-300 font-mono truncate">{a.handle||a.id}{a.tier?(' · '+a.tier):''}</div>
              </div>
              <div className="flex items-center gap-1.5">
                {(() => {
                  /* Show an icon for every platform this account is actually
                     mapped to (canonical order), incl. X + LinkedIn. Falls back
                     to a dash when nothing is mapped. */
                  const shown = SRC_PLATFORM_IDS.filter(p=>src[p]);
                  return shown.length
                    ? shown.map(p=> <span key={p} title={`${p}: ${src[p]}`} className="inline-flex items-center justify-center w-6 h-6 text-ink-900 dark:text-white"><BrandIcon name={p} size={16}/></span>)
                    : <span className="w-6 h-6 grid place-items-center text-ink-300 dark:text-white/15">·</span>;
                })()}
              </div>
              <div className="text-[12px] font-mono text-ink-600 dark:text-ink-200">{a.currency||'—'}</div>
              <div><span className={readOnly?'pointer-events-none opacity-40':''}><Toggle checked={!!a.synced} onChange={()=>toggleSync(a)} size="sm"/></span></div>
              <div className="flex justify-end">
                {!readOnly && <button onClick={()=>setEdit({ account:a, isNew:false })} className="h-8 w-8 grid place-items-center rounded-lg hover:bg-ink-100 dark:hover:bg-white/10 text-ink-500"><Icon name="settings" size={15}/></button>}
              </div>
            </div>
          );
        })}
      </Card>

      <AccountEditDrawer open={!!edit} account={edit?.account} isNew={edit?.isNew}
        onClose={()=>setEdit(null)} onSave={save}/>
      {!readOnly && accounts.some(a=>!a.synced) && (
        <div className="mt-3 text-[11.5px] text-ink-400">Paused accounts are excluded from data pulls and hidden from non-admin users.</div>
      )}
    </div>
  );
}

/* ===================================================================
   Admin panel shell
=================================================================== */
/* ---------- Client feeds: this dashboard → a client's portal ---------------
   The credentials are issued on the PORTAL side (owner console → Workspaces →
   Connect feed) and pasted here. That order is deliberate: the portal decides who
   may receive, this side decides which account is sent. Neither end can help
   itself to the other's data. */
function ClientFeeds({ accounts, readOnly }){
  const [links, setLinks] = useState(null);
  const [err, setErr] = useState('');
  const [busy, setBusy] = useState('');
  const [adding, setAdding] = useState(false);
  const [draft, setDraft] = useState({ accountId:'', label:'', hookUrl:'', secret:'', windowDays:28, dimMode:'platform' });

  const load = async () => {
    try { setLinks((await RelayAPI.get('/portal/links')).links || []); setErr(''); }
    catch(e){ setErr(e.message || 'Could not load client feeds.'); setLinks([]); }
  };
  useEffect(()=>{ load(); }, []);

  const add = async () => {
    if (!draft.accountId || !draft.hookUrl.trim() || !draft.secret.trim()){
      setErr('Pick an ad account and paste both the feed URL and the key from the portal.'); return;
    }
    setBusy('new');
    try { await RelayAPI.post('/portal/links', draft); setAdding(false);
      setDraft({ accountId:'', label:'', hookUrl:'', secret:'', windowDays:28, dimMode:'platform' }); setErr(''); await load(); }
    catch(e){ setErr(e.message || 'Could not create the feed.'); }
    finally { setBusy(''); }
  };
  const act = async (id, fn, msg) => {
    setBusy(id);
    try { await fn(); setErr(''); await load(); }
    catch(e){ setErr(e.message || msg); }
    finally { setBusy(''); }
  };
  const pushNow = id => act(id, async ()=>{
    const r = await RelayAPI.post(`/portal/links/${id}/push`);
    if (r.result && !r.result.ok) setErr(r.result.error || 'The push was rejected.');
  }, 'Could not push.');

  const accName = id => (accounts.find(a=>a.id===id)||{}).name || id;

  return (
    <div>
      <div className="flex items-start justify-between gap-4 mb-4">
        <div>
          <h2 className="text-[17px] font-bold">Client feeds</h2>
          <p className="text-[12.5px] text-ink-500 dark:text-ink-300 mt-0.5 max-w-[62ch]">
            Send an ad account's daily campaign numbers straight into that client's own dashboard.
            Connect the feed in the client portal first — it gives you a URL and a key to paste here.
          </p>
        </div>
        {!readOnly && <Btn variant="accent" icon="plus" onClick={()=>{ setAdding(a=>!a); setErr(''); }}>Add feed</Btn>}
      </div>

      {err && <div className="flex items-start gap-2 text-[12.5px] text-rose-700 dark:text-rose-300 bg-rose-50 dark:bg-rose-500/10 border border-rose-200 dark:border-rose-500/25 rounded-lg px-3 py-2 mb-4"><Icon name="alert" size={14} className="mt-0.5"/> {err}</div>}

      {adding && !readOnly && (
        <Card className="p-5 mb-4 space-y-4">
          <div className="grid grid-cols-2 gap-3">
            <Field label="Ad account" hint="whose numbers are sent">
              <select value={draft.accountId} onChange={e=>setDraft(d=>({...d, accountId:e.target.value}))} className={inputCls}>
                <option value="">Choose an account…</option>
                {accounts.map(a=><option key={a.id} value={a.id}>{a.name}{a.currency?` · ${a.currency}`:''}</option>)}
              </select>
            </Field>
            <Field label="Client name" hint="label for this list only">
              <input value={draft.label} onChange={e=>setDraft(d=>({...d, label:e.target.value}))} placeholder="defaults to the account name" className={inputCls}/>
            </Field>
          </div>
          <Field label="Feed URL" hint="from the portal's owner console">
            <input value={draft.hookUrl} onChange={e=>setDraft(d=>({...d, hookUrl:e.target.value}))} placeholder="https://portal.example.com/api/cv/hooks/…" className={inputCls}/>
          </Field>
          <div className="grid grid-cols-[1fr_140px] gap-3">
            <Field label="Feed key" hint="shown once, on the portal">
              <input value={draft.secret} onChange={e=>setDraft(d=>({...d, secret:e.target.value}))} placeholder="paste the key" className={inputCls}/>
            </Field>
            <Field label="Resend window" hint="days">
              <input type="number" min="1" max="90" value={draft.windowDays}
                onChange={e=>setDraft(d=>({...d, windowDays:+e.target.value||28}))} className={inputCls}/>
            </Field>
          </div>
          <Field label="Break the client's charts down by" hint="what each bar and series is">
            <select value={draft.dimMode} onChange={e=>setDraft(d=>({...d, dimMode:e.target.value}))} className={inputCls}>
              <option value="platform">Platform — Meta, Google, TikTok…</option>
              <option value="account">Ad account — this account's name</option>
            </select>
          </Field>
          <p className="text-[11.5px] text-ink-500 dark:text-ink-300 leading-relaxed">
            Each run re-sends the last {draft.windowDays} days so late-attributed conversions
            correct themselves on the client's dashboard instead of stacking up. Campaign totals
            only — deliberately, since sending several levels at once would multiply every figure.
            {draft.dimMode==='account'
              ? ' Choose “Ad account” when several accounts feed the same client workspace — it is what keeps each one a separate series instead of merging them all into one platform.'
              : ' Choose “Ad account” instead if several accounts feed the same client workspace, or they will merge into a single platform series.'}
          </p>
          <div className="flex justify-end gap-2">
            <Btn variant="ghost" onClick={()=>{ setAdding(false); setErr(''); }}>Cancel</Btn>
            <Btn variant="accent" icon="check" onClick={add}>{busy==='new'?'Connecting…':'Add feed'}</Btn>
          </div>
        </Card>
      )}

      {links === null ? <Card className="p-8 text-center text-[12.5px] text-ink-400">Loading…</Card>
       : !links.length ? (
        <Card className="p-8 text-center">
          <div className="text-[13px] font-medium mb-1">No client feeds yet</div>
          <div className="text-[12px] text-ink-500 dark:text-ink-300 max-w-[46ch] mx-auto">
            When a client subscribes to both dashboards, connect a feed so your team's work
            shows up on their side automatically — no exports, no double entry.
          </div>
        </Card>
      ) : (
        <Card className="overflow-hidden">
          <table className="w-full">
            <thead><tr className="text-[10.5px] uppercase tracking-wide text-ink-400 border-b border-ink-100 dark:border-white/10">
              <th className="text-left font-semibold px-5 py-2.5">Client</th>
              <th className="text-left font-semibold px-3 py-2.5">Ad account</th>
              <th className="text-left font-semibold px-3 py-2.5">Destination</th>
              <th className="text-right font-semibold px-3 py-2.5">Rows sent</th>
              <th className="text-left font-semibold px-3 py-2.5">Last push</th>
              <th className="text-right font-semibold px-5 py-2.5">Actions</th>
            </tr></thead>
            <tbody>
              {links.map(l=>(
                <tr key={l.id} className="border-b border-ink-50 dark:border-white/5 align-top">
                  <td className="px-5 py-3">
                    <div className="text-[12.5px] font-semibold">{l.label || accName(l.accountId)}</div>
                    <div className="text-[10.5px] text-ink-400">{l.status==='active'?`re-sends ${l.windowDays} days`:'paused'}</div>
                  </td>
                  <td className="px-3 py-3 text-[12px]">
                    {accName(l.accountId)}
                    {l.dimMode==='account' && <div className="text-[10.5px] text-ink-400">shown as its own series</div>}
                  </td>
                  <td className="px-3 py-3 text-[11px] font-mono text-ink-500 dark:text-ink-300 break-all max-w-[220px]">
                    {(()=>{ try { return new URL(l.hookUrl).host; } catch(_){ return l.hookUrl; } })()}
                  </td>
                  <td className="px-3 py-3 text-right tabular text-[12px]">{l.rowsTotal}</td>
                  <td className="px-3 py-3 text-[11px]">
                    <span className={l.lastError?'text-amber-600 dark:text-amber-400':'text-ink-500 dark:text-ink-300'}>
                      {l.lastPush ? relTime(l.lastPush) : 'never'}
                    </span>
                    {l.lastError && <div className="text-[10.5px] text-amber-600 dark:text-amber-400 max-w-[280px]">{l.lastError}</div>}
                  </td>
                  <td className="px-5 py-3 text-right whitespace-nowrap space-x-1">
                    {!readOnly && <>
                      <Btn variant="ghost" onClick={()=>pushNow(l.id)}>{busy===l.id?'…':'Push now'}</Btn>
                      <Btn variant="ghost" onClick={()=>act(l.id, ()=>RelayAPI.put(`/portal/links/${l.id}`, { status:l.status==='active'?'paused':'active' }), 'Could not update.')}>
                        {l.status==='active'?'Pause':'Resume'}
                      </Btn>
                      <Btn variant="ghost" onClick={()=>{
                        /* Stops sending only. Whatever the client already received is theirs,
                           and clearing it is a decision taken on the portal side. */
                        if (!confirm('Stop sending this feed?\n\nData already delivered stays on the client dashboard — remove it from the portal if you need it gone.')) return;
                        act(l.id, ()=>RelayAPI.del(`/portal/links/${l.id}`), 'Could not remove.');
                      }}>Remove</Btn>
                    </>}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </Card>
      )}
    </div>
  );
}

function AdminPanel({ currentUser, users, setUsers, integrations, setIntegrations, accounts, setAccounts, audit, pushAudit, brand, setBrand, onExit, onSignOut, dark, setDark }){
  const canUsers    = can(currentUser, 'users.manage');
  const canInt      = can(currentUser, 'integrations.manage');
  const canAccounts = can(currentUser, 'accounts.manage');
  const isSuper  = currentUser.role === 'super_admin';
  const navItems = [
    { id:'overview',     label:'Overview',     icon:'sparkles', show:true },
    { id:'users',        label:'Team',         icon:'settings', show:canUsers },
    { id:'accounts',     label:'Ad accounts',  icon:'columns',  show:canAccounts },
    { id:'integrations', label:'Integrations', icon:'zap',      show:true },
    { id:'feeds',        label:'Client feeds', icon:'link',     show:canInt },
    { id:'branding',     label:'Branding',     icon:'image',    show:true },
    { id:'activity',     label:'Activity',     icon:'play',     show:true },
    { id:'roles',        label:'Roles',        icon:'columns',  show:true },
  ].filter(i=>i.show);
  const [section, setSection] = useState(canUsers ? 'overview' : 'integrations');

  return (
    <div className="min-h-screen bg-ink-50 dark:bg-ink-900 text-ink-900 dark:text-ink-50">
      {/* top bar */}
      <header className="sticky top-0 z-30 backdrop-blur-md bg-ink-50/85 dark:bg-ink-900/80 border-b border-ink-200 dark:border-white/10">
        <div className="max-w-[1320px] mx-auto px-6 h-16 flex items-center gap-4">
          <div className="flex items-center gap-2.5">
            <BrandLogo brand={brand} size={30}/>
            <Wordmark size={18} brand={brand}/>
            <span className="ml-1 text-[11px] font-mono uppercase tracking-wider px-2 py-1 rounded-md bg-ink-900 text-white dark:bg-white dark:text-ink-900">Admin</span>
          </div>
          <div className="flex-1"/>
          <Btn variant="ghost" icon="chev-left" onClick={onExit}>Back to dashboard</Btn>
          <IconButton title="Toggle theme" onClick={()=>setDark(d=>!d)}><Icon name={dark?'sun':'moon'} size={15}/></IconButton>
          <AdminUserMenu user={currentUser} onSignOut={onSignOut}/>
        </div>
      </header>

      <div className="max-w-[1320px] mx-auto px-6 py-6 grid grid-cols-[210px_1fr] gap-6 items-start">
        {/* rail */}
        <nav className="sticky top-[88px] space-y-1">
          {navItems.map(it=>(
            <button key={it.id} onClick={()=>setSection(it.id)}
              className={`w-full flex items-center gap-2.5 px-3 h-10 rounded-xl text-[13px] font-medium transition text-left
                ${section===it.id?'bg-white dark:bg-ink-800 shadow-card text-ink-900 dark:text-white border border-ink-200 dark:border-white/10':'text-ink-500 dark:text-ink-300 hover:bg-white/60 dark:hover:bg-white/5'}`}>
              <Icon name={it.icon} size={16} className={section===it.id?'text-accent-500':''}/>
              {it.label}
            </button>
          ))}
          <div className="pt-3 mt-3 border-t border-ink-200 dark:border-white/10 space-y-2">
            {canUsers && <PortalShortcut/>}
            <div className="px-3 py-2 rounded-xl bg-white dark:bg-ink-800/60 border border-ink-200 dark:border-white/10">
              <div className="flex items-center gap-2 text-[11px] text-ink-500 dark:text-ink-300 mb-1.5">
                <span className="w-1.5 h-1.5 rounded-full bg-emerald-500"/> MySQL store · live
              </div>
              <div className="text-[11px] text-ink-500 dark:text-ink-300 leading-snug">Team, roles, connections & audit persist to your database.</div>
            </div>
          </div>
        </nav>

        {/* content */}
        <div className="min-w-0">
          {section==='overview'     && <AdminOverview users={users} integrations={integrations} audit={audit} onGo={setSection}/>}
          {section==='users'        && <UsersManager users={users} setUsers={setUsers} currentUser={currentUser} readOnly={!canUsers} pushAudit={pushAudit}/>}
          {section==='accounts'     && <AccountsManager accounts={accounts} setAccounts={setAccounts} currentUser={currentUser} readOnly={!canAccounts} pushAudit={pushAudit}/>}
          {section==='integrations' && <IntegrationsManager integrations={integrations} setIntegrations={setIntegrations} readOnly={!canInt} currentUser={currentUser} pushAudit={pushAudit}/>}
          {section==='feeds'        && <ClientFeeds accounts={accounts} readOnly={!canInt}/>}
          {section==='branding'     && <BrandingManager brand={brand} setBrand={setBrand} currentUser={currentUser} pushAudit={pushAudit}/>}
          {section==='activity'     && <AuditLog audit={audit}/>}
          {section==='roles'        && <RolesReference/>}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { AdminPanel, AdminUserMenu, Avatar, RoleBadge, AuditLog, relTime });
