// Data Sources page (client view) + SER admin pages: Klantbeheer, Connectors, AI providers

const { useState: uS_adm } = React;
const ANALYTICS_API = window.SER_ANALYTICS_API || 'https://perceptive-adventure-production-1a21.up.railway.app';

function getAuthHeader() {
  const token = localStorage.getItem('ser-analytics-token') || '';
  return { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' };
}

// ============== DATA SOURCES (client view) ==============
function SourcesDashboard() {
  const D = window.ANALYTICS_DATA;
  const client = D.ANALYTICS_CLIENTS[0];
  const required = D.CONNECTORS.filter(c => c.required);
  const optional = D.CONNECTORS.filter(c => !c.required);

  return (
    <div style={{display:'flex', flexDirection:'column', gap:22}}>
      <PlaceholderHeaderS title="Databronnen"
        desc="Een overzicht van alle data die je dashboards voedt. Vier bronnen zijn standaard voor elke klant; de rest wordt door SER op verzoek gekoppeld."/>

      {/* Required */}
      <div className="dash-section-head">
        <div className="left">
          <h2>Standaard · vereist</h2>
          <span className="sub">Deze 4 bronnen zijn altijd gekoppeld voor alle klanten</span>
        </div>
      </div>
      <div className="src-grid">
        {required.map(c => <SourceCard key={c.id} conn={c} state={client.connectors[c.id]}/>)}
      </div>

      {/* Optional */}
      <div className="dash-section-head" style={{marginTop:8}}>
        <div className="left">
          <h2>Optioneel · door SER te koppelen</h2>
          <span className="sub">{Object.keys(client.connectors).filter(k => !D.CONNECTORS.find(c => c.id === k)?.required).length} actief van {optional.length} beschikbaar</span>
        </div>
        <button className="btn-ghost-sm">Vraag koppeling aan</button>
      </div>
      <div className="src-grid">
        {optional.map(c => <SourceCard key={c.id} conn={c} state={client.connectors[c.id]}/>)}
      </div>

      {/* SER proprietary signals */}
      <div className="prop-banner">
        <div>
          <div className="eyebrow"><span className="dot-ser"></span>SER · proprietary signals</div>
          <h2>Data die je nergens anders krijgt</h2>
          <p>Eigen scrapes, NLP-analyses en ML-voorspellingen die SER zelf bouwt en onderhoudt. Standaard inbegrepen voor alle klanten — geen extra API-koppeling nodig.</p>
        </div>
      </div>
      <div className="src-grid">
        {D.PROPRIETARY_SIGNALS.map(s => (
          <div key={s.id} className="src-card prop">
            <div className="src-head">
              <div className="src-ico prop">{D.Icons[s.icon] || D.Icons.spark}</div>
              <div style={{flex:1, minWidth:0}}>
                <div className="src-cat">{s.category}</div>
                <div className="src-name">{s.label}</div>
                <div className="src-sub">{s.sub}</div>
              </div>
              <span className="src-status ok">Actief</span>
            </div>
            <p className="src-desc">{s.desc}</p>
            <div className="src-sample"><strong>Voorbeeld:</strong> {s.sample}</div>
            <div className="src-foot">
              <span><strong>Methode:</strong> {s.method}</span>
              <span><strong>Frisheid:</strong> {s.refresh}</span>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

function SourceCard({ conn, state }) {
  const D = window.ANALYTICS_DATA;
  const connected = !!state;
  const sIcon = state?.status || (connected ? 'ok' : 'off');
  return (
    <div className={`src-card ${connected ? '' : 'off'}`}>
      <div className="src-head">
        <div className="src-ico">{conn.label.slice(0,2).toUpperCase()}</div>
        <div style={{flex:1, minWidth:0}}>
          <div className="src-cat">{conn.category}</div>
          <div className="src-name">{conn.label}</div>
          {state && <div className="src-sub" style={{fontFamily:'var(--font-mono)', fontSize:11}}>{state.account}</div>}
        </div>
        <span className={`src-status ${sIcon}`}>
          {sIcon === 'ok' ? '✓ Verbonden' : sIcon === 'warn' ? '! Vertraagd' : sIcon === 'err' ? '✕ Fout' : 'Niet verbonden'}
        </span>
      </div>
      {state ? (
        <div className="src-foot">
          <span><strong>Frisheid:</strong> {state.freshness}</span>
          {state.since && <span><strong>Sinds:</strong> {state.since}</span>}
        </div>
      ) : (
        <div className="src-foot off">
          <span>Nog niet gekoppeld</span>
          {conn.required ? <span className="req-pill">Verplicht</span> : <button className="btn-ghost-sm">Aanvragen</button>}
        </div>
      )}
    </div>
  );
}

// ============== AI Settings per klant ==============
function AiSettingsSection({ client }) {
  const [key, setKey] = uS_adm('');
  const [model, setModel] = uS_adm('claude-sonnet-4-5-20250929');
  const [aiEnabled, setAiEnabled] = uS_adm(client.aiEnabled !== false);
  const [saving, setSaving] = uS_adm(false);
  const [saved, setSaved] = uS_adm(false);
  const [showKey, setShowKey] = uS_adm(false);
  const [hasKey, setHasKey] = uS_adm(!!client.hasClaudeKey);

  const save = async () => {
    setSaving(true);
    try {
      await fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/ai-config`, {
        method: 'POST',
        headers: getAuthHeader(),
        body: JSON.stringify({
          anthropic_api_key: key || undefined,
          claude_model: model,
          ai_enabled: aiEnabled,
        }),
      });
      if (key) setHasKey(true);
      setKey('');
      setSaved(true);
      setTimeout(() => setSaved(false), 3000);
    } catch { alert('Opslaan mislukt'); }
    finally { setSaving(false); }
  };

  return (
    <div className="adm-section">
      <h3>AI-instellingen</h3>
      <p className="hint">Bepaal of AI-features actief zijn voor deze klant en welke API-key er wordt gebruikt. Als er geen eigen key is, wordt de SER-key gebruikt.</p>

      <div style={{display:'flex', flexDirection:'column', gap:14, marginTop:14}}>
        {/* AI aan/uit */}
        <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', padding:'12px 14px', background:'var(--ink-25)', borderRadius:10, border:'1px solid var(--ink-100)'}}>
          <div>
            <div style={{fontSize:13, fontWeight:600, color:'var(--ink-900)'}}>AI-features inschakelen</div>
            <div style={{fontSize:12, color:'var(--ink-500)', marginTop:2}}>Business cases, briefings en AI-inzichten voor deze klant</div>
          </div>
          <button onClick={() => setAiEnabled(v => !v)} style={{
            width:40, height:22, borderRadius:999, border:'none', cursor:'pointer', position:'relative',
            background: aiEnabled ? 'var(--ser-teal)' : 'var(--ink-200)', transition:'0.15s',
          }}>
            <span style={{
              position:'absolute', top:3, left: aiEnabled ? 20 : 3,
              width:16, height:16, borderRadius:'50%', background:'white',
              transition:'0.15s', boxShadow:'0 1px 3px rgba(0,0,0,0.2)',
            }}/>
          </button>
        </div>

        {aiEnabled && (
          <>
            {/* Model selectie */}
            <div>
              <label style={{fontSize:12, fontWeight:600, color:'var(--ink-700)', display:'block', marginBottom:6}}>Claude model</label>
              <select value={model} onChange={e => setModel(e.target.value)}
                style={{width:'100%', padding:'9px 12px', border:'1px solid var(--ink-200)', borderRadius:8, fontSize:13}}>
                <option value="claude-sonnet-4-5-20250929">claude-sonnet-4-5 (aanbevolen)</option>
                <option value="claude-haiku-4-5-20251001">claude-haiku-4-5 (snel &amp; goedkoop)</option>
                <option value="claude-opus-4-7">claude-opus-4 (meest capabel)</option>
              </select>
            </div>

            {/* Eigen API key */}
            <div>
              <label style={{fontSize:12, fontWeight:600, color:'var(--ink-700)', display:'block', marginBottom:6}}>
                Anthropic API key
                {hasKey && <span style={{marginLeft:8, color:'var(--ok)', fontWeight:400}}>✓ Eigen key actief</span>}
                {!hasKey && <span style={{marginLeft:8, color:'var(--ink-400)', fontWeight:400}}>— gebruikt SER-key</span>}
              </label>
              <div style={{display:'flex', gap:8}}>
                <input
                  type={showKey ? 'text' : 'password'}
                  value={key}
                  onChange={e => setKey(e.target.value)}
                  placeholder={hasKey ? '••••••••••••• (vervangen)' : 'sk-ant-... (optioneel)'}
                  style={{flex:1, padding:'9px 12px', border:'1px solid var(--ink-200)', borderRadius:8, fontSize:13, fontFamily:'var(--font-mono)'}}
                />
                <button onClick={() => setShowKey(v => !v)}
                  style={{padding:'9px 12px', border:'1px solid var(--ink-200)', borderRadius:8, background:'white', fontSize:12, cursor:'pointer', color:'var(--ink-500)'}}>
                  {showKey ? 'Verberg' : 'Toon'}
                </button>
              </div>
              <div style={{fontSize:11, color:'var(--ink-400)', marginTop:4}}>Laat leeg om de gedeelde SER-key te gebruiken. Eigen key = aparte facturatie.</div>
            </div>
          </>
        )}

        <div style={{display:'flex', alignItems:'center', gap:10}}>
          <button onClick={save} disabled={saving}
            style={{padding:'9px 16px', borderRadius:8, border:'none', background:'var(--ser-navy)', color:'white', fontSize:13, fontWeight:600, cursor:'pointer'}}>
            {saving ? 'Opslaan…' : 'Opslaan'}
          </button>
          {saved && <span style={{fontSize:12, color:'var(--ok)', fontWeight:600}}>✓ Instellingen opgeslagen</span>}
        </div>
      </div>
    </div>
  );
}

function DomainManagement({ client, onUpdate }) {
  const [domains, setDomains] = React.useState(client.domains || []);
  const [newDomain, setNewDomain] = React.useState('');
  const [newLabel, setNewLabel] = React.useState('');
  const [adding, setAdding] = React.useState(false);

  const addDomain = async () => {
    if (!newDomain.trim()) return;
    setAdding(true);
    try {
      const res = await fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/domains`, {
        method: 'POST', headers: getAuthHeader(),
        body: JSON.stringify({ domain: newDomain.trim(), label: newLabel.trim() || newDomain.trim() }),
      });
      const d = await res.json();
      setDomains(prev => [...prev, d.domain]);
      setNewDomain(''); setNewLabel('');
      if (onUpdate) onUpdate(); // Refresh parent
    } catch { alert('Fout bij toevoegen'); }
    finally { setAdding(false); }
  };

  const removeDomain = async (domainId) => {
    if (!confirm('Domein verwijderen?')) return;
    await fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/domains/${domainId}`, {
      method: 'DELETE', headers: getAuthHeader(),
    });
    setDomains(prev => prev.filter(d => d.id !== domainId));
    if (onUpdate) onUpdate(); // Refresh parent
  };

  return (
    <div className="adm-section">
      <h3>Domeinen <span className="cnt">{domains.length}</span></h3>
      <p className="hint">Één klant kan meerdere domeinen hebben (bijv. intratuin.nl, intratuin.be). Elk domein heeft eigen koppelingen en data.</p>

      <div style={{display:'flex', flexDirection:'column', gap:8, marginTop:12}}>
        {domains.map(d => (
          <div key={d.id} style={{display:'flex', alignItems:'center', gap:10, padding:'10px 14px', background:'var(--ink-25)', borderRadius:8, border:'1px solid var(--ink-100)'}}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15 15 0 0 1 0 20"/></svg>
            <div style={{flex:1}}>
              <div style={{fontSize:13, fontWeight:600}}>{d.label}</div>
              <div style={{fontSize:11, color:'var(--ink-500)', fontFamily:'var(--font-mono)'}}>{d.domain}</div>
            </div>
            <span style={{fontSize:10, color:'var(--ink-400)', fontWeight:600}}>{d.country}</span>
            <button onClick={() => removeDomain(d.id)} style={{background:'transparent', border:'none', color:'var(--err)', cursor:'pointer', fontSize:16, padding:'2px 6px'}}>×</button>
          </div>
        ))}

        <div style={{display:'flex', gap:8, marginTop:4}}>
          <input value={newDomain} onChange={e => setNewDomain(e.target.value)} placeholder="domein.nl"
            style={{flex:1, padding:'8px 10px', border:'1px solid var(--ink-200)', borderRadius:8, fontSize:13, fontFamily:'var(--font-mono)'}}
            onKeyDown={e => e.key === 'Enter' && addDomain()} />
          <input value={newLabel} onChange={e => setNewLabel(e.target.value)} placeholder="Label (optioneel)"
            style={{width:140, padding:'8px 10px', border:'1px solid var(--ink-200)', borderRadius:8, fontSize:13}} />
          <button onClick={addDomain} disabled={adding}
            style={{padding:'8px 14px', background:'var(--ser-navy)', color:'white', border:'none', borderRadius:8, fontSize:13, fontWeight:600, cursor:'pointer'}}>
            {adding ? '…' : '+ Toevoegen'}
          </button>
        </div>
      </div>
    </div>
  );
}

// ============== ADMIN: Klanten & Koppelingen (gecombineerd) ==============
function AddClientModal({ onClose, onCreated }) {
  const ANALYTICS_API = window.SER_ANALYTICS_API || '';
  const headers = { Authorization: `Bearer ${localStorage.getItem('ser-analytics-token')}`, 'Content-Type': 'application/json' };
  const [name, setName] = React.useState('');
  const [username, setUsername] = React.useState('');
  const [contact, setContact] = React.useState('');
  const [domain, setDomain] = React.useState('');
  const [loading, setLoading] = React.useState(false);
  const [err, setErr] = React.useState('');

  const handleCreate = async () => {
    if (!name.trim() || !username.trim()) { setErr('Naam en gebruikersnaam zijn verplicht.'); return; }
    setLoading(true); setErr('');
    try {
      const res = await fetch(`${ANALYTICS_API}/api/admin/clients`, {
        method: 'POST', headers,
        body: JSON.stringify({ name: name.trim(), username: username.trim().toLowerCase(), contact: contact.trim(), domain: domain.trim() }),
      });
      const d = await res.json();
      if (!res.ok) { setErr(d.detail || 'Aanmaken mislukt.'); return; }
      onCreated(d.client, d.password);
    } catch { setErr('Verbindingsfout.'); }
    finally { setLoading(false); }
  };

  return (
    <div style={{position:'fixed',inset:0,background:'rgba(14,14,42,0.5)',backdropFilter:'blur(4px)',display:'grid',placeItems:'center',zIndex:200}}
      onClick={onClose}>
      <div style={{background:'white',borderRadius:14,padding:24,width:440,maxWidth:'92vw',boxShadow:'0 12px 40px rgba(0,0,0,0.2)'}}
        onClick={e => e.stopPropagation()}>
        <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:20}}>
          <div style={{fontSize:16,fontWeight:700,color:'var(--ink-900)'}}>Nieuwe klant aanmaken</div>
          <button onClick={onClose} style={{background:'none',border:'none',fontSize:20,cursor:'pointer',color:'var(--ink-400)',lineHeight:1}}>×</button>
        </div>
        {err && <div style={{background:'#fdecea',color:'#c62828',border:'1px solid rgba(229,57,53,0.3)',padding:'10px 12px',borderRadius:8,fontSize:12,marginBottom:14}}>{err}</div>}
        {[
          ['Bedrijfsnaam *', name, setName, 'bijv. Intratuin B.V.', 'text'],
          ['Gebruikersnaam *', username, v => setUsername(v.toLowerCase().replace(/\s/g,'')), 'bijv. intratuin', 'text'],
          ['Contact e-mail', contact, setContact, 'contact@klant.nl', 'email'],
          ['Primair domein', domain, setDomain, 'bijv. intratuin.nl', 'text'],
        ].map(([label, val, setter, placeholder, type]) => (
          <div key={label} style={{marginBottom:14}}>
            <label style={{fontSize:12,fontWeight:600,color:'var(--ink-700)',display:'block',marginBottom:5}}>{label}</label>
            <input type={type} value={val} onChange={e => setter(e.target.value)} placeholder={placeholder}
              style={{width:'100%',padding:'9px 12px',border:'1px solid var(--ink-200)',borderRadius:8,fontSize:13,outline:'none'}}/>
          </div>
        ))}
        <p style={{fontSize:11,color:'var(--ink-400)',marginBottom:16}}>Het wachtwoord wordt automatisch gegenereerd en getoond na aanmaken.</p>
        <div style={{display:'flex',justifyContent:'flex-end',gap:8}}>
          <button onClick={onClose} style={{padding:'8px 16px',borderRadius:8,border:'1px solid var(--ink-200)',background:'white',fontSize:13,cursor:'pointer'}}>Annuleer</button>
          <button onClick={handleCreate} disabled={loading} style={{padding:'8px 16px',borderRadius:8,border:'none',background:'var(--ser-navy)',color:'white',fontSize:13,fontWeight:600,cursor:'pointer'}}>
            {loading ? 'Aanmaken…' : 'Klant aanmaken'}
          </button>
        </div>
      </div>
    </div>
  );
}

function AdminKlantenDashboard() {
  const D = window.ANALYTICS_DATA;
  const ANALYTICS_API = window.SER_ANALYTICS_API || '';
  const headers = () => ({ Authorization: `Bearer ${localStorage.getItem('ser-analytics-token')}`, 'Content-Type': 'application/json' });

  const [clients, setClients] = React.useState([]);
  const [selectedId, setSelectedId] = React.useState(null);
  const [subTab, setSubTab] = React.useState('settings'); // 'settings' | 'connectors' | 'dashboards'
  const [schemas, setSchemas] = React.useState({});
  const [connectors, setConnectors] = React.useState({});
  const [showAdd, setShowAdd] = React.useState(false);
  const [loading, setLoading] = React.useState(true);
  const [search, setSearch] = React.useState('');

  React.useEffect(() => {
    Promise.all([
      fetch(`${ANALYTICS_API}/api/admin/clients`, { headers: headers() }).then(r => r.json()),
      fetch(`${ANALYTICS_API}/api/admin/connectors/schemas`, { headers: headers() }).then(r => r.json()),
    ]).then(([cl, sc]) => {
      const list = cl.clients || [];
      setClients(list);
      setSchemas(sc.schemas || {});
      if (list.length) setSelectedId(list[0].id);
    }).catch(() => {}).finally(() => setLoading(false));
  }, []);

  React.useEffect(() => {
    if (!selectedId) return;
    fetch(`${ANALYTICS_API}/api/admin/clients/${selectedId}/connectors`, { headers: headers() })
      .then(r => r.json()).then(d => setConnectors(d.connectors || {})).catch(() => {});
  }, [selectedId]);

  const selected = clients.find(c => c.id === selectedId);
  const filtered = clients.filter(c => !search || c.name.toLowerCase().includes(search.toLowerCase()) || c.domain?.toLowerCase().includes(search.toLowerCase()));

  const refreshClients = () => {
    fetch(`${ANALYTICS_API}/api/admin/clients`, { headers: headers() })
      .then(r => r.json()).then(d => setClients(d.clients || [])).catch(() => {});
  };

  const subTabs = [
    { id: 'settings',   label: 'Instellingen' },
    { id: 'connectors', label: 'Koppelingen' },
    { id: 'dashboards', label: 'Dashboard-toegang' },
  ];

  if (loading) return <div style={{textAlign:'center', padding:48, color:'var(--ink-400)'}}>Laden…</div>;

  return (
    <div style={{display:'flex', flexDirection:'column', gap:16}}>
      <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', flexWrap:'wrap', gap:10}}>
        <div>
          <h2 style={{margin:0}}>Klanten & Koppelingen</h2>
          <p style={{margin:'4px 0 0', color:'var(--ink-500)', fontSize:13}}>Beheer klanten, databronnen en dashboard-toegang.</p>
        </div>
        <button onClick={() => setShowAdd(true)} style={{padding:'8px 16px', background:'var(--ser-navy)', color:'white', border:'none', borderRadius:8, fontSize:13, fontWeight:600, cursor:'pointer', display:'flex', alignItems:'center', gap:6}}>
          + Nieuwe klant
        </button>
      </div>

      <div style={{display:'grid', gridTemplateColumns:'220px 1fr', gap:16, alignItems:'start'}}>
        {/* Klanten lijst */}
        <div style={{background:'white', border:'1px solid var(--ink-100)', borderRadius:12, overflow:'hidden', position:'sticky', top:20}}>
          <div style={{padding:'10px 12px', borderBottom:'1px solid var(--ink-100)', display:'flex', gap:6}}>
            <input value={search} onChange={e => setSearch(e.target.value)} placeholder="Zoek klant…"
              style={{flex:1, padding:'6px 9px', border:'1px solid var(--ink-200)', borderRadius:6, fontSize:12, outline:'none'}} />
          </div>
          <div style={{maxHeight:'calc(100vh - 260px)', overflowY:'auto'}}>
            {filtered.map(c => {
              const connCount = Object.values(c.id === selectedId ? connectors : {}).filter(v => v.configured).length;
              return (
                <button key={c.id} onClick={() => setSelectedId(c.id)} style={{
                  width:'100%', padding:'11px 14px', textAlign:'left', cursor:'pointer',
                  background: selectedId===c.id ? 'var(--ink-25)' : 'transparent',
                  border:'none', borderBottom:'1px solid var(--ink-100)',
                  borderLeft:`3px solid ${selectedId===c.id ? 'var(--ser-teal)' : 'transparent'}`,
                }}>
                  <div style={{fontSize:13, fontWeight:600, color:'var(--ink-900)'}}>{c.name}</div>
                  <div style={{fontSize:11, color:'var(--ink-400)', marginTop:2, display:'flex', gap:8}}>
                    <span className={`pill ${c.status==='active'?'pill-success':'pill-neutral'}`} style={{padding:'1px 6px', fontSize:9}}>{c.status}</span>
                    {connCount > 0 && <span>{connCount} koppelingen</span>}
                  </div>
                </button>
              );
            })}
          </div>
        </div>

        {/* Detail paneel */}
        {selected ? (
          <div style={{display:'flex', flexDirection:'column', gap:12}}>
            {/* Sub-tabs */}
            <div style={{display:'flex', gap:2, background:'var(--ink-100)', borderRadius:8, padding:3, alignSelf:'flex-start'}}>
              {subTabs.map(t => (
                <button key={t.id} onClick={() => setSubTab(t.id)} style={{
                  padding:'6px 14px', borderRadius:6, border:'none', cursor:'pointer', fontSize:12, fontWeight:600,
                  background: subTab===t.id ? 'white' : 'transparent',
                  color: subTab===t.id ? 'var(--ink-900)' : 'var(--ink-500)',
                  boxShadow: subTab===t.id ? 'var(--shadow-sm)' : 'none',
                }}>{t.label}</button>
              ))}
            </div>

            {/* Instellingen tab */}
            {subTab === 'settings' && (
              <ClientSettingsTab client={selected} onUpdate={refreshClients} ANALYTICS_API={ANALYTICS_API} />
            )}

            {/* Koppelingen tab */}
            {subTab === 'connectors' && (
              <ClientConnectorsTab client={selected} schemas={schemas} connectors={connectors} setConnectors={setConnectors} ANALYTICS_API={ANALYTICS_API} />
            )}

            {/* Dashboard-toegang tab */}
            {subTab === 'dashboards' && (
              <ClientDashboardsTab client={selected} onUpdate={refreshClients} ANALYTICS_API={ANALYTICS_API} />
            )}
          </div>
        ) : (
          <div style={{textAlign:'center', padding:48, color:'var(--ink-400)'}}>Selecteer een klant</div>
        )}
      </div>

      {showAdd && <AddClientModal onClose={() => setShowAdd(false)} onCreated={(client, password) => {
        setClients(prev => [...prev, client]);
        setSelectedId(client.id);
        setShowAdd(false);
        alert(`Klant "${client.name}" aangemaakt.\n\nWachtwoord: ${password}\n\nStuur dit via 1Password Send.`);
      }} />}
    </div>
  );
}

// ── Concurrent beheer per domein ──────────────────────────────────────────────
function CompetitorManagement({ client, domainId }) {
  const headers = { Authorization: `Bearer ${localStorage.getItem('ser-analytics-token')}`, 'Content-Type': 'application/json' };
  const [competitors, setCompetitors] = React.useState([]);
  const [newDomain, setNewDomain] = React.useState('');
  const [adding, setAdding] = React.useState(false);

  React.useEffect(() => {
    if (!domainId) return;
    fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/domains/${domainId}/competitors`, { headers })
      .then(r => r.json()).then(d => setCompetitors(d.competitors || [])).catch(() => {});
  }, [domainId]);

  const add = async () => {
    if (!newDomain.trim()) return;
    setAdding(true);
    try {
      const res = await fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/domains/${domainId}/competitors`, {
        method: 'POST', headers, body: JSON.stringify({ domain: newDomain.trim() }),
      });
      const d = await res.json();
      if (res.ok) { setCompetitors(d.competitors || []); setNewDomain(''); }
      else alert(d.detail);
    } catch { alert('Fout'); } finally { setAdding(false); }
  };

  const remove = async (domain) => {
    await fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/domains/${domainId}/competitors/${domain}`, { method: 'DELETE', headers });
    setCompetitors(prev => prev.filter(c => c.domain !== domain));
  };

  if (!domainId) return null;

  return (
    <div className="adm-section">
      <h3>Concurrenten <span className="cnt">{competitors.length}</span></h3>
      <p className="hint">Voeg concurrent-domeinen toe voor de concurrentie-analyse. De analyse gebruikt Semrush, Ahrefs en/of SerpAPI.</p>

      <div style={{display:'flex', flexDirection:'column', gap:6, marginTop:10}}>
        {competitors.map(c => (
          <div key={c.domain} style={{display:'flex', alignItems:'center', gap:10, padding:'9px 12px', background:'var(--ink-25)', borderRadius:8, border:'1px solid var(--ink-100)'}}>
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15 15 0 0 1 0 20"/></svg>
            <span style={{flex:1, fontSize:13, fontWeight:600, color:'var(--ink-900)', fontFamily:'var(--font-mono)'}}>{c.domain}</span>
            <button onClick={() => remove(c.domain)} style={{background:'transparent', border:'none', color:'var(--err)', cursor:'pointer', padding:'2px 6px', fontSize:16}}>×</button>
          </div>
        ))}

        <div style={{display:'flex', gap:8, marginTop:4}}>
          <input value={newDomain} onChange={e => setNewDomain(e.target.value)} placeholder="concurrent.nl"
            onKeyDown={e => e.key === 'Enter' && add()}
            style={{flex:1, padding:'8px 10px', border:'1px solid var(--ink-200)', borderRadius:7, fontSize:12, fontFamily:'var(--font-mono)'}}/>
          <button onClick={add} disabled={adding} style={{padding:'8px 14px', background:'var(--ser-navy)', color:'white', border:'none', borderRadius:7, fontSize:12, fontWeight:600, cursor:'pointer'}}>
            {adding ? '…' : '+ Toevoegen'}
          </button>
        </div>
      </div>
    </div>
  );
}

// ── Instellingen sub-tab ──────────────────────────────────────────────────────
function ClientSettingsTab({ client, onUpdate, ANALYTICS_API }) {
  const headers = { Authorization: `Bearer ${localStorage.getItem('ser-analytics-token')}`, 'Content-Type': 'application/json' };
  const [resetting, setResetting] = React.useState(false);
  const [newPw, setNewPw] = React.useState(null);
  const [editing, setEditing] = React.useState(false);
  const [editForm, setEditForm] = React.useState({ name: client.name, contact: client.contact, sector: client.sector || '', plan: client.plan || 'Starter' });
  const [saving, setSaving] = React.useState(false);

  const resetPassword = async () => {
    setResetting(true);
    try {
      const d = await fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/reset-password`, { method:'POST', headers, body:'{}' }).then(r => r.json());
      setNewPw(d.password);
    } catch { alert('Fout'); } finally { setResetting(false); }
  };

  const toggleActive = async () => {
    const endpoint = client.status === 'active' ? 'deactivate' : 'activate';
    await fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/${endpoint}`, { method:'POST', headers, body:'{}' });
    onUpdate();
  };

  const saveEdit = async () => {
    setSaving(true);
    try {
      const res = await fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}`, { method:'PATCH', headers, body: JSON.stringify(editForm) });
      if (res.ok) { setEditing(false); onUpdate(); }
      else { const d = await res.json(); alert(d.detail || 'Fout'); }
    } catch { alert('Verbindingsfout'); } finally { setSaving(false); }
  };

  return (
    <div style={{display:'flex', flexDirection:'column', gap:12}}>
      {/* Klant info */}
      <div className="adm-section">
        <div style={{display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:16}}>
          <h3 style={{margin:0}}>{client.name}</h3>
          <div style={{display:'flex', gap:8}}>
            <button onClick={() => setEditing(e => !e)} style={{padding:'6px 12px', borderRadius:7, border:'1px solid var(--ink-200)', background: editing ? 'var(--ink-100)' : 'white', fontSize:12, fontWeight:600, cursor:'pointer'}}>
              {editing ? 'Annuleer' : '✏️ Bewerken'}
            </button>
            <button onClick={resetPassword} disabled={resetting} style={{padding:'6px 12px', borderRadius:7, border:'1px solid var(--ink-200)', background:'white', fontSize:12, fontWeight:600, cursor:'pointer'}}>
              {resetting ? '…' : 'Reset wachtwoord'}
            </button>
            <button onClick={toggleActive} style={{padding:'6px 12px', borderRadius:7, border:`1px solid ${client.status==='active'?'rgba(229,57,53,0.3)':'rgba(0,180,160,0.3)'}`, background:'white', fontSize:12, fontWeight:600, cursor:'pointer', color:client.status==='active'?'var(--err)':'var(--ok)'}}>
              {client.status === 'active' ? 'Deactiveer' : 'Activeer'}
            </button>
          </div>
        </div>

        {editing ? (
          <div style={{display:'flex', flexDirection:'column', gap:10, marginBottom:16}}>
            {[['Naam', 'name', 'Bloemerij B.V.'], ['Contact e-mail', 'contact', 'contact@klant.nl'], ['Sector', 'sector', 'Retail · Bloemen'], ['Plan', 'plan', null]].map(([label, field, placeholder]) => (
              <div key={field}>
                <label style={{fontSize:11, fontWeight:600, color:'var(--ink-700)', display:'block', marginBottom:3}}>{label}</label>
                {field === 'plan' ? (
                  <select value={editForm.plan} onChange={e => setEditForm(p => ({...p, plan: e.target.value}))}
                    style={{width:'100%', padding:'7px 10px', border:'1px solid var(--ink-200)', borderRadius:7, fontSize:12}}>
                    {['Starter','Growth','Enterprise'].map(o => <option key={o}>{o}</option>)}
                  </select>
                ) : (
                  <input value={editForm[field]} onChange={e => setEditForm(p => ({...p, [field]: e.target.value}))} placeholder={placeholder}
                    style={{width:'100%', padding:'7px 10px', border:'1px solid var(--ink-200)', borderRadius:7, fontSize:12}}/>
                )}
              </div>
            ))}
            <button onClick={saveEdit} disabled={saving} style={{padding:'8px 14px', background:'var(--ser-navy)', color:'white', border:'none', borderRadius:7, fontSize:12, fontWeight:600, cursor:'pointer', alignSelf:'flex-start'}}>
              {saving ? 'Opslaan…' : 'Opslaan'}
            </button>
          </div>
        ) : null}

        {newPw && (
          <div style={{background:'var(--ser-teal-50)', border:'1px solid rgba(0,180,160,0.3)', borderRadius:8, padding:'12px 14px', marginBottom:16}}>
            <div style={{fontSize:12, fontWeight:600, color:'#008873', marginBottom:4}}>Nieuw wachtwoord — stuur via 1Password Send:</div>
            <div style={{fontFamily:'var(--font-mono)', fontSize:15, fontWeight:700, color:'var(--ink-900)'}}>{newPw}</div>
            <button onClick={() => { navigator.clipboard?.writeText(newPw); setNewPw(null); }} style={{marginTop:8, padding:'4px 10px', borderRadius:6, border:'none', background:'var(--ser-teal)', color:'white', fontSize:11, fontWeight:600, cursor:'pointer'}}>Kopiëren & sluiten</button>
          </div>
        )}
        <div style={{display:'grid', gridTemplateColumns:'repeat(auto-fit, minmax(160px,1fr))', gap:16}}>
          {[['Gebruikersnaam', client.username],['Contact', client.contact],['Sector', client.sector],['Plan', client.plan],['Laatste login', client.lastLogin||'—'],['Aangemaakt', client.addedAt],['Door', client.addedBy]].map(([l,v]) => (
            <div key={l}><div style={{fontSize:10, textTransform:'uppercase', letterSpacing:'0.06em', color:'var(--ink-400)', fontWeight:600, marginBottom:3}}>{l}</div><div style={{fontSize:13, color:'var(--ink-900)'}}>{v||'—'}</div></div>
          ))}
        </div>
      </div>
      {/* Domeinen */}
      <DomainManagement client={client} onUpdate={onUpdate} />
      {/* Concurrenten */}
      <CompetitorManagement client={client} domainId={client.domains?.[0]?.id} />
      {/* AI instellingen */}
      <AiSettingsSection client={client} />
    </div>
  );
}

// ── SharedServiceAccount: gedeeld SA per domein ──────────────────────────────
function SharedServiceAccount({ client, domainId, onSaved }) {
  const ANALYTICS_API = window.SER_ANALYTICS_API || '';
  const headers = { Authorization: `Bearer ${localStorage.getItem('ser-analytics-token')}`, 'Content-Type': 'application/json' };
  const [info, setInfo] = React.useState(null);
  const [uploading, setUploading] = React.useState(null); // 'default' | 'bigquery' | null
  const [saved, setSaved] = React.useState(null);

  React.useEffect(() => {
    if (!domainId) return;
    fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/domains/${domainId}/service-account`, { headers })
      .then(r => r.json()).then(d => setInfo(d.service_accounts)).catch(() => {});
  }, [domainId]);

  // Toon globale SA-status badge als bron=global (uit Railway env vars)
  const hasGlobal = info && Object.values(info).some(v => v.source === 'global');
  const hasAny = info && Object.values(info).some(v => v.stored);

  const handleUpload = async (saType, file) => {
    const reader = new FileReader();
    reader.onload = async (ev) => {
      setUploading(saType);
      try {
        const res = await fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/domains/${domainId}/service-account`, {
          method: 'POST', headers,
          body: JSON.stringify({ service_account_json: ev.target.result, type: saType }),
        });
        const d = await res.json();
        if (!res.ok) { alert(d.detail || 'Fout bij opslaan'); return; }
        setInfo(prev => ({...prev, [saType]: { stored: true, project_id: d.project_id, client_email: d.client_email }}));
        setSaved(saType); setTimeout(() => setSaved(null), 3000);
        if (onSaved) onSaved();
      } catch { alert('Fout'); } finally { setUploading(null); }
    };
    reader.readAsText(file);
  };

  return (
    <div style={{background:'linear-gradient(135deg, var(--ink-50) 0%, white 100%)', border:'2px dashed var(--ink-200)', borderRadius:12, padding:'16px 20px', marginBottom:16}}>
      <div style={{display:'flex', alignItems:'center', gap:8, marginBottom:12}}>
        <span style={{fontSize:16}}>&#128273;</span>
        <div>
          <div style={{fontSize:13, fontWeight:700, color:'var(--ink-900)'}}>Gedeeld Service Account</div>
          <div style={{fontSize:11, color:'var(--ink-500)'}}>Upload één keer — daarna automatisch gebruikt bij GA4, Search Console en BigQuery</div>
          {hasGlobal && (
            <div style={{display:'inline-flex', alignItems:'center', gap:5, marginTop:4, padding:'2px 8px', borderRadius:999, background:'rgba(0,180,160,0.1)', border:'1px solid rgba(0,180,160,0.25)'}}>
              <span style={{fontSize:10, color:'var(--ok)', fontWeight:700}}>✓ Geconfigureerd via SER-beheer (Railway)</span>
            </div>
          )}
        </div>
      </div>
      <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:12}}>
        {[
          { type: 'default', label: 'GA4 + Search Console', desc: 'Voor Google Analytics en Search Console' },
          { type: 'bigquery', label: 'BigQuery', desc: 'Voor BigQuery datasets en GA4 raw data' },
        ].map(({ type, label, desc }) => {
          const stored = info?.[type];
          return (
            <div key={type} style={{padding:'12px 14px', background:'white', borderRadius:9, border:`1px solid ${stored?.stored ? 'rgba(0,180,160,0.3)' : 'var(--ink-200)'}`}}>
              <div style={{fontSize:12, fontWeight:700, marginBottom:3}}>{label}</div>
              <div style={{fontSize:11, color:'var(--ink-500)', marginBottom:8}}>{desc}</div>
              {stored?.stored ? (
                <div>
                  <div style={{fontSize:11, color:'var(--ok)', fontWeight:600}}>&#10003; Opgeslagen</div>
                  <div style={{fontSize:10, color:'var(--ink-400)', fontFamily:'var(--font-mono)', marginTop:2}}>{stored.client_email}</div>
                  {saved === type && <div style={{fontSize:10, color:'var(--ok)', fontWeight:700, marginTop:2}}>Zojuist bijgewerkt</div>}
                </div>
              ) : (
                <div style={{fontSize:11, color:'var(--ink-400)'}}>Nog niet ingesteld</div>
              )}
              <label style={{display:'inline-flex', alignItems:'center', gap:6, marginTop:8, padding:'5px 10px', borderRadius:6, background:'var(--ser-navy)', color:'white', fontSize:11, fontWeight:600, cursor:'pointer'}}>
                <input type="file" accept=".json" style={{display:'none'}} disabled={uploading === type}
                  onChange={e => e.target.files[0] && handleUpload(type, e.target.files[0])} />
                {uploading === type ? 'Uploaden…' : (stored?.stored ? 'Vervangen' : '+ Uploaden')}
              </label>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ── SmartConnectorForm: discovery-gebaseerde koppeling voor Google bronnen ────
function SmartConnectorForm({ connId, clientId, domainId, onSaved, ANALYTICS_API, hasStoredSA }) {
  const headers = { Authorization: `Bearer ${localStorage.getItem('ser-analytics-token')}`, 'Content-Type': 'application/json' };
  const [saJson, setSaJson] = React.useState('');
  const [discovering, setDiscovering] = React.useState(false);
  const [properties, setProperties] = React.useState(null);
  const [selectedProp, setSelectedProp] = React.useState('');
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState('');

  const discoveryEndpoint = {
    ga4: '/api/connectors/discover/ga4',
    gsc: '/api/connectors/discover/gsc',
    bq:  '/api/connectors/discover/bigquery',
    ga4_bq: '/api/connectors/discover/bigquery',
  }[connId];

  const hasDiscovery = !!discoveryEndpoint;

  const handleFileUpload = (e) => {
    const f = e.target.files[0];
    if (!f) return;
    const reader = new FileReader();
    reader.onload = ev => setSaJson(ev.target.result);
    reader.readAsText(f);
  };

  const saType = (connId === 'bq' || connId === 'ga4_bq') ? 'bigquery' : 'default';

  const handleDiscover = async () => {
    // Als geen eigen JSON geladen: gebruik opgeslagen SA
    const body = saJson
      ? { service_account_json: saJson }
      : { client_id: clientId, domain_id: domainId, sa_type: saType };

    if (!saJson && !clientId) { setErr('Upload een Service Account JSON of sla er eerst één op.'); return; }
    setDiscovering(true); setErr(''); setProperties(null);
    try {
      const res = await fetch(`${ANALYTICS_API}${discoveryEndpoint}`, {
        method: 'POST', headers,
        body: JSON.stringify(body),
      });
      const d = await res.json();
      if (!res.ok) { setErr(d.detail || 'Discovery mislukt'); return; }
      const list = d.properties || d.datasets || [];
      setProperties(list);
      if (list.length === 1) setSelectedProp(list[0].id);
    } catch { setErr('Verbindingsfout'); }
    finally { setDiscovering(false); }
  };

  const handleSave = async () => {
    if (!saJson && !hasStoredSA) { setErr('Geen JSON geladen'); return; }
    setSaving(true); setErr('');
    const payload = saJson
      ? {
          service_account_json: saJson,
          property_id: connId === 'ga4' ? selectedProp : undefined,
          property_url: connId === 'gsc' ? selectedProp : undefined,
          project_id: (connId === 'bq' || connId === 'ga4_bq') ? selectedProp : undefined,
        }
      : {
          client_id: clientId,
          domain_id: domainId,
          sa_type: saType,
          property_id: connId === 'ga4' ? selectedProp : undefined,
          property_url: connId === 'gsc' ? selectedProp : undefined,
          project_id: (connId === 'bq' || connId === 'ga4_bq') ? selectedProp : undefined,
        };
    try {
      const endpoint = domainId
        ? `${ANALYTICS_API}/api/admin/clients/${clientId}/domains/${domainId}/connectors/${connId}`
        : `${ANALYTICS_API}/api/admin/clients/${clientId}/connectors/${connId}`;
      const res = await fetch(endpoint, { method: 'POST', headers, body: JSON.stringify(payload) });
      const d = await res.json();
      if (!res.ok) { setErr(d.detail || 'Opslaan mislukt'); return; }
      onSaved({ configured: true, account: selectedProp || 'Geconfigureerd', freshness: 'Zojuist' });
    } catch { setErr('Verbindingsfout'); }
    finally { setSaving(false); }
  };

  return (
    <div style={{display:'flex', flexDirection:'column', gap:10}}>
      {/* Stap 1: Upload JSON — optioneel als gedeeld SA beschikbaar is */}
      {!hasStoredSA && (
        <div>
          <div style={{fontSize:11, fontWeight:600, color:'var(--ink-600)', marginBottom:4}}>
            {hasDiscovery ? 'Stap 1: Upload Service Account JSON' : 'Service Account JSON'}
          </div>
          <input type="file" accept=".json" onChange={handleFileUpload} style={{fontSize:11, width:'100%'}}/>
          {saJson && <div style={{fontSize:10, color:'var(--ok)', marginTop:2}}>&#10003; JSON geladen</div>}
        </div>
      )}
      {hasStoredSA && !saJson && (
        <div style={{fontSize:11, color:'var(--ok)', padding:'8px 10px', background:'var(--ser-teal-50)', borderRadius:6}}>
          &#10003; Gedeeld service account actief — klik hieronder om properties op te halen
        </div>
      )}
      {hasStoredSA && (
        <div>
          <div style={{fontSize:10, color:'var(--ink-400)', marginBottom:4}}>Of upload een alternatief JSON bestand:</div>
          <input type="file" accept=".json" onChange={handleFileUpload} style={{fontSize:11, width:'100%'}}/>
          {saJson && <div style={{fontSize:10, color:'var(--ok)', marginTop:2}}>&#10003; Alternatief JSON geladen</div>}
        </div>
      )}

      {/* Stap 2: Discovery */}
      {hasDiscovery && (saJson || hasStoredSA) && !properties && (
        <button onClick={handleDiscover} disabled={discovering} style={{
          padding:'7px 12px', borderRadius:7, border:'none', fontSize:12, fontWeight:600, cursor:'pointer',
          background:'var(--ink-100)', color:'var(--ink-700)',
        }}>
          {discovering ? 'Ophalen…' : 'Haal beschikbare properties op'}
        </button>
      )}

      {/* Stap 3: Kies property */}
      {properties !== null && (
        <div>
          <div style={{fontSize:11, fontWeight:600, color:'var(--ink-600)', marginBottom:4}}>
            {hasStoredSA ? 'Kies' : 'Stap 2: Kies'} een property ({properties.length} gevonden)
          </div>
          {properties.length === 0 ? (
            <div style={{fontSize:11, color:'var(--ink-400)'}}>Geen properties gevonden voor dit service account.</div>
          ) : (
            <select value={selectedProp} onChange={e => setSelectedProp(e.target.value)}
              style={{width:'100%', padding:'7px 10px', border:'1px solid var(--ink-200)', borderRadius:7, fontSize:12}}>
              <option value="">Kies…</option>
              {properties.map(p => (
                <option key={p.id} value={p.id}>{p.name} {p.id !== p.name ? `(${p.id})` : ''}</option>
              ))}
            </select>
          )}
        </div>
      )}

      {err && <div style={{fontSize:11, color:'var(--err)'}}>{err}</div>}

      {/* Opslaan */}
      {((saJson || hasStoredSA) && (!hasDiscovery || (properties !== null && selectedProp))) && (
        <button onClick={handleSave} disabled={saving} style={{
          padding:'7px 12px', borderRadius:7, border:'none', fontSize:12, fontWeight:600, cursor:'pointer',
          background:'var(--ser-teal)', color:'white',
        }}>
          {saving ? 'Opslaan…' : 'Opslaan & koppelen'}
        </button>
      )}
    </div>
  );
}

// ── Koppelingen sub-tab ───────────────────────────────────────────────────────
function ClientConnectorsTab({ client, schemas, connectors, setConnectors, ANALYTICS_API }) {
  const headers = { Authorization: `Bearer ${localStorage.getItem('ser-analytics-token')}`, 'Content-Type': 'application/json' };
  const D = window.ANALYTICS_DATA;
  const [configuring, setConfiguring] = React.useState(null);
  const [formData, setFormData] = React.useState({});
  const [saving, setSaving] = React.useState(false);
  const [saved, setSaved] = React.useState(null);
  const [selectedDomainId, setSelectedDomainId] = React.useState(
    client.domains?.[0]?.id || null
  );
  const selectedDomain = client.domains?.find(d => d.id === selectedDomainId);

  const connGroups = [
    { label: 'Google', ids: ['ga4','gsc','gads','bq','ga4_bq'] },
    { label: 'E-commerce', ids: ['shopify','woo','magento','google_merchant'] },
    { label: 'SEO / Data', ids: ['semrush','ahrefs','serpapi'] },
    { label: 'Paid media', ids: ['meta','tiktok','linkedin','bing_ads'] },
    { label: 'CRM & E-mail', ids: ['hubspot','salesforce','klaviyo','mailchimp'] },
  ];

  React.useEffect(() => {
    if (!selectedDomainId) return;
    fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/domains/${selectedDomainId}/connectors`, { headers })
      .then(r => r.json())
      .then(d => setConnectors(d.connectors || {}))
      .catch(() => setConnectors({}));
  }, [selectedDomainId]);

  const handleSave = async () => {
    if (!configuring) return;
    setSaving(true);
    const url = selectedDomainId
      ? `${ANALYTICS_API}/api/admin/clients/${client.id}/domains/${selectedDomainId}/connectors/${configuring}`
      : `${ANALYTICS_API}/api/admin/clients/${client.id}/connectors/${configuring}`;
    try {
      const res = await fetch(url, { method:'POST', headers, body: JSON.stringify(formData) });
      const d = await res.json();
      if (!res.ok) { alert(d.detail || 'Fout'); return; }
      setConnectors(prev => ({...prev, [configuring]: {status:'ok', account: formData.property_id||formData.project_id||formData.store_url||formData.customer_id||'Geconfigureerd', configured:true, freshness:'Zojuist'}}));
      setSaved(configuring); setConfiguring(null); setFormData({});
      setTimeout(() => setSaved(null), 3000);
    } catch { alert('Verbindingsfout'); } finally { setSaving(false); }
  };

  const handleRemove = async (connId) => {
    if (!confirm('Koppeling verwijderen?')) return;
    const url = selectedDomainId
      ? `${ANALYTICS_API}/api/admin/clients/${client.id}/domains/${selectedDomainId}/connectors/${connId}`
      : `${ANALYTICS_API}/api/admin/clients/${client.id}/connectors/${connId}`;
    await fetch(url, { method:'DELETE', headers });
    setConnectors(prev => { const n={...prev}; delete n[connId]; return n; });
  };

  return (
    <div style={{display:'flex', flexDirection:'column', gap:12}}>
      {client.domains?.length > 1 && (
        <div style={{display:'flex', gap:4, marginBottom:12, flexWrap:'wrap'}}>
          {client.domains.map(d => (
            <button key={d.id} onClick={() => setSelectedDomainId(d.id)} style={{
              padding:'5px 12px', borderRadius:6, border:'none', cursor:'pointer', fontSize:12, fontWeight:600,
              background: selectedDomainId===d.id ? 'var(--ser-navy)' : 'var(--ink-100)',
              color: selectedDomainId===d.id ? 'white' : 'var(--ink-600)',
            }}>{d.label || d.domain}</button>
          ))}
        </div>
      )}
      {!client.domains?.length && (
        <div style={{padding:'12px 14px', background:'var(--ser-gold-50)', border:'1px solid rgba(245,165,35,0.3)', borderRadius:8, fontSize:12, color:'#b37800', marginBottom:12}}>
          Voeg eerst een domein toe via Instellingen → Domeinen.
        </div>
      )}
      {selectedDomainId && (
        <SharedServiceAccount
          client={client}
          domainId={selectedDomainId}
          onSaved={() => {/* connector forms auto-use stored SA */}}
        />
      )}
      {connGroups.map(group => (
        <div key={group.label} style={{background:'white', border:'1px solid var(--ink-100)', borderRadius:12, overflow:'hidden'}}>
          <div style={{padding:'10px 16px', borderBottom:'1px solid var(--ink-100)', fontSize:11, fontWeight:700, color:'var(--ink-700)', background:'var(--ink-25)', textTransform:'uppercase', letterSpacing:'0.06em'}}>{group.label}</div>
          <div style={{display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(220px, 1fr))'}}>
            {group.ids.map(connId => {
              const schema = schemas[connId];
              const conn = connectors[connId];
              const connDef = D.CONNECTORS?.find(c => c.id === connId);
              if (!connDef && !schema) return null;
              const label = connDef?.label || connId.toUpperCase();
              const isConfiguring = configuring === connId;
              return (
                <div key={connId} style={{padding:'12px 14px', borderBottom:'1px solid var(--ink-50)', borderRight:'1px solid var(--ink-50)'}}>
                  <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom: isConfiguring ? 10 : 0}}>
                    <div>
                      <div style={{fontSize:12, fontWeight:600}}>{label}</div>
                      <div style={{fontSize:10, color: conn?.configured ? 'var(--ok)' : (schema?.note ? 'var(--ink-400)' : 'var(--ink-400)'), marginTop:2}}>
                        {conn?.configured ? `✓ ${conn.account}` : schema?.note ? 'OAuth vereist' : 'Niet gekoppeld'}
                      </div>
                      {saved === connId && <div style={{fontSize:10, color:'var(--ok)', fontWeight:700}}>✓ Opgeslagen</div>}
                    </div>
                    {!schema?.note && (
                      <div style={{display:'flex', gap:4, flexShrink:0}}>
                        {conn?.configured && !isConfiguring && <button onClick={() => handleRemove(connId)} style={{background:'transparent', border:'none', color:'var(--err)', fontSize:11, cursor:'pointer', padding:'2px 6px'}}>×</button>}
                        <button onClick={() => { setConfiguring(isConfiguring ? null : connId); setFormData({}); }}
                          style={{padding:'4px 9px', borderRadius:5, border:'none', fontSize:11, fontWeight:600, cursor:'pointer', background: isConfiguring?'var(--ink-100)':'var(--ser-navy)', color: isConfiguring?'var(--ink-700)':'white'}}>
                          {isConfiguring ? 'Annuleer' : (conn?.configured ? 'Wijzig' : '+')}
                        </button>
                      </div>
                    )}
                  </div>
                  {isConfiguring && (
                    ['ga4','gsc','bq','ga4_bq'].includes(connId) ? (
                      <SmartConnectorForm
                        connId={connId}
                        clientId={client.id}
                        domainId={selectedDomainId}
                        ANALYTICS_API={ANALYTICS_API}
                        hasStoredSA={!!selectedDomainId}
                        onSaved={(conn) => {
                          setConnectors(prev => ({...prev, [connId]: conn}));
                          setSaved(connId); setConfiguring(null);
                          setTimeout(() => setSaved(null), 3000);
                        }}
                      />
                    ) : (schema?.fields?.length > 0 ? (
                      /* bestaand formulier voor niet-Google connectors */
                      <div style={{display:'flex', flexDirection:'column', gap:6}}>
                        {schema.fields.map(field => (
                          <div key={field.id}>
                            <div style={{fontSize:10, fontWeight:600, color:'var(--ink-600)', marginBottom:3}}>{field.label}</div>
                            {field.type==='file' ? (
                              <input type="file" accept=".json" onChange={e => { const f=e.target.files[0]; if(!f)return; const r=new FileReader(); r.onload=ev=>setFormData(p=>({...p,[field.id]:ev.target.result})); r.readAsText(f); }} style={{fontSize:10, width:'100%'}}/>
                            ) : field.type==='select' ? (
                              <select value={formData[field.id]||field.options?.[0]||''} onChange={e=>setFormData(p=>({...p,[field.id]:e.target.value}))} style={{width:'100%', padding:'5px 8px', border:'1px solid var(--ink-200)', borderRadius:5, fontSize:11}}>
                                {(field.options||[]).map(o=><option key={o}>{o}</option>)}
                              </select>
                            ) : (
                              <input type={field.type==='password'?'password':'text'} value={formData[field.id]||''} placeholder={field.placeholder||''} onChange={e=>setFormData(p=>({...p,[field.id]:e.target.value}))} style={{width:'100%', padding:'5px 8px', border:'1px solid var(--ink-200)', borderRadius:5, fontSize:11}}/>
                            )}
                          </div>
                        ))}
                        <button onClick={handleSave} disabled={saving} style={{padding:'6px 12px', background:'var(--ser-teal)', color:'white', border:'none', borderRadius:5, fontSize:11, fontWeight:600, cursor:'pointer'}}>
                          {saving ? 'Opslaan…' : 'Opslaan'}
                        </button>
                      </div>
                    ) : null)
                  )}
                </div>
              );
            })}
          </div>
        </div>
      ))}
    </div>
  );
}

// ── Dashboard-toegang sub-tab ─────────────────────────────────────────────────
function ClientDashboardsTab({ client, onUpdate, ANALYTICS_API }) {
  const D = window.ANALYTICS_DATA;
  const headers = { Authorization: `Bearer ${localStorage.getItem('ser-analytics-token')}`, 'Content-Type': 'application/json' };
  const [enabled, setEnabled] = React.useState(new Set(client.dashboards || []));
  const [saving, setSaving] = React.useState(false);
  const [saved, setSaved] = React.useState(false);

  const toggle = (id) => {
    setEnabled(prev => { const n = new Set(prev); n.has(id) ? n.delete(id) : n.add(id); return n; });
  };

  const saveAccess = async () => {
    setSaving(true);
    try {
      await fetch(`${ANALYTICS_API}/api/admin/clients/${client.id}/dashboards`, {
        method:'PATCH', headers, body: JSON.stringify({ dashboards: Array.from(enabled) })
      });
      setSaved(true); setTimeout(() => setSaved(false), 3000);
      onUpdate();
    } catch { alert('Fout bij opslaan'); } finally { setSaving(false); }
  };

  const clientVisible = D.DASHBOARDS?.filter(d => d.clientVisible && !d.staffOnly) || [];

  return (
    <div className="adm-section">
      <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:14}}>
        <div>
          <h3 style={{margin:0}}>Dashboard-toegang voor {client.name}</h3>
          <p style={{margin:'4px 0 0', fontSize:12, color:'var(--ink-500)'}}>Bepaal welke tabs deze klant ziet. {enabled.size}/{clientVisible.length} ingeschakeld.</p>
        </div>
        <div style={{display:'flex', gap:8, alignItems:'center'}}>
          {saved && <span style={{fontSize:12, color:'var(--ok)', fontWeight:600}}>✓ Opgeslagen</span>}
          <button onClick={() => setEnabled(new Set(clientVisible.map(d => d.id)))} style={{padding:'6px 12px', borderRadius:7, border:'1px solid var(--ink-200)', background:'white', fontSize:12, cursor:'pointer'}}>Alle aan</button>
          <button onClick={() => setEnabled(new Set())} style={{padding:'6px 12px', borderRadius:7, border:'1px solid var(--ink-200)', background:'white', fontSize:12, cursor:'pointer'}}>Alle uit</button>
          <button onClick={saveAccess} disabled={saving} style={{padding:'6px 14px', borderRadius:7, border:'none', background:'var(--ser-navy)', color:'white', fontSize:12, fontWeight:600, cursor:'pointer'}}>
            {saving ? 'Opslaan…' : 'Opslaan'}
          </button>
        </div>
      </div>
      <div style={{display:'flex', flexDirection:'column', gap:6}}>
        {clientVisible.map(d => {
          const on = enabled.has(d.id);
          return (
            <div key={d.id} onClick={() => toggle(d.id)} style={{
              display:'flex', alignItems:'center', gap:12, padding:'10px 14px', borderRadius:8, cursor:'pointer',
              background: on ? 'var(--ser-teal-50)' : 'var(--ink-25)',
              border:`1px solid ${on ? 'rgba(0,180,160,0.25)' : 'var(--ink-100)'}`,
            }}>
              <span style={{fontSize:16}}>{D.Icons?.[d.icon] || '📊'}</span>
              <div style={{flex:1}}>
                <div style={{fontSize:13, fontWeight:600, color:'var(--ink-900)'}}>{d.label}</div>
                {d.flagship && <div style={{fontSize:10, color:'var(--ser-gold)', fontWeight:700}}>★ Vlaggenschip</div>}
                {d.status==='beta' && <div style={{fontSize:10, color:'#7c5cff', fontWeight:600}}>β BETA</div>}
              </div>
              <button type="button" onClick={e => { e.stopPropagation(); toggle(d.id); }} style={{
                width:36, height:20, borderRadius:999, border:'none', cursor:'pointer', position:'relative', flexShrink:0,
                background: on ? 'var(--ser-teal)' : 'var(--ink-200)', transition:'0.15s',
              }}>
                <span style={{position:'absolute', top:2, left: on?18:2, width:16, height:16, borderRadius:'50%', background:'white', transition:'0.15s', boxShadow:'0 1px 3px rgba(0,0,0,0.2)'}}/>
              </button>
            </div>
          );
        })}
      </div>
    </div>
  );
}
window.AdminKlantenDashboard = AdminKlantenDashboard;

// ============== ADMIN: Klantbeheer ==============
function AdminClientsDashboard() {
  const D = window.ANALYTICS_DATA;
  const [openId, setOpenId] = uS_adm(D.ANALYTICS_CLIENTS[0].id);
  const [showNew, setShowNew] = uS_adm(false);
  const [search, setSearch] = uS_adm('');
  const open = D.ANALYTICS_CLIENTS.find(c => c.id === openId);

  const toggleDashboard = (dashId) => {
    const current = open.enabledDashboards || [];
    const updated = current.includes(dashId)
      ? current.filter(d => d !== dashId)
      : [...current, dashId];
    // Update in-memory (prototype)
    open.enabledDashboards = updated;
  };

  return (
    <div style={{display:'flex', flexDirection:'column', gap:22}}>
      <PlaceholderHeaderS title="Klantbeheer · Admin" desc="Voeg klanten toe, beheer portal-toegang en bepaal welke dashboards zichtbaar zijn per klant."
        right={<button onClick={() => setShowNew(true)} className="btn-primary-sm">{D.Icons.plus} Klant toevoegen</button>}/>

      <div className="adm-layout">
        <aside className="adm-list">
          <div className="adm-list-head">
            <span>{D.ANALYTICS_CLIENTS.length} klanten</span>
            <input className="adm-search" placeholder="Zoek…" value={search} onChange={e => setSearch(e.target.value)}/>
          </div>
          {D.ANALYTICS_CLIENTS.filter(c =>
            !search || c.name.toLowerCase().includes(search.toLowerCase()) || c.domain?.toLowerCase().includes(search.toLowerCase())
          ).map(c => (
            <button key={c.id} className={`adm-client-row ${openId === c.id ? 'active' : ''}`} onClick={() => setOpenId(c.id)}>
              <div className="av" style={{background:`linear-gradient(135deg, ${c.color || '#7c5cff'}, #1e1e5a)`}}>{c.initials}</div>
              <div style={{flex:1, minWidth:0}}>
                <div className="nm">{c.name}</div>
                <div className="sub">{c.domain || c.sector}</div>
              </div>
              <span className={`plan-pill ${c.plan?.toLowerCase()}`}>{c.plan}</span>
            </button>
          ))}
        </aside>

        <main className="adm-detail">
          <div className="adm-detail-head">
            <div className="av lg" style={{background:`linear-gradient(135deg, ${open.color || '#7c5cff'}, #1e1e5a)`}}>{open.initials}</div>
            <div style={{flex:1}}>
              <h2>{open.name}</h2>
              <div className="adm-meta-row">
                <span>{open.sector}</span>
                <span>·</span>
                <span>{open.domain}</span>
                <span>·</span>
                <span>AM: {open.accountManager}</span>
                <span>·</span>
                <span>Sinds {open.onboardedAt}</span>
              </div>
            </div>
            <button className="btn-ghost-sm">Bekijk dashboard →</button>
          </div>

          <div className="adm-twocol">
            <div className="adm-section">
              <h3>Portal-gebruikers <span className="cnt">{open.portalUsers?.length || 0}</span></h3>
              <div className="adm-users">
                {(open.portalUsers || []).map((u, i) => (
                  <div key={i} className="adm-user">
                    <div className="av sm">{u.name.split(' ').map(n => n[0]).join('').slice(0,2)}</div>
                    <div style={{flex:1, minWidth:0}}>
                      <div className="nm">{u.name}</div>
                      <div className="sub">{u.email} · laatst gezien {u.lastSeen}</div>
                    </div>
                    <span className="role-pill">{u.role}</span>
                  </div>
                ))}
                <button className="btn-ghost-sm wide">{D.Icons.plus} Gebruiker uitnodigen</button>
              </div>
            </div>

            <div className="adm-section">
              <h3>Tab-toegang <span className="cnt">{open.enabledDashboards?.length || 0}/{D.DASHBOARDS.filter(d => d.clientVisible).length}</span></h3>
              <p className="hint">Bepaal welke tabs deze klant ziet in het portal.</p>
              <div className="adm-tabs">
                {D.DASHBOARDS.filter(d => d.clientVisible).map(d => {
                  const enabled = open.enabledDashboards?.includes(d.id);
                  return (
                    <div key={d.id} className={`adm-tab-row ${enabled ? 'on' : ''}`}>
                      <span className="ico">{D.Icons[d.icon]}</span>
                      <span className="lbl">{d.label}</span>
                      {d.flagship && <span className="flag-mini">★</span>}
                      <label className="switch" onClick={() => toggleDashboard(d.id)}>
                        <input type="checkbox" checked={enabled} onChange={() => {}} readOnly/>
                        <span className="slider"></span>
                      </label>
                    </div>
                  );
                })}
              </div>
            </div>
          </div>

          <AiSettingsSection client={open} />

          <DomainManagement client={open} />

          <div className="adm-section">
            <h3>Gekoppelde databronnen <span className="cnt">{Object.keys(open.connectors || {}).length}/{D.CONNECTORS.length}</span></h3>
            <p className="hint">Connectiebeheer staat onder <strong>Koppelingen</strong>.</p>
            <div className="adm-conn-grid">
              {D.CONNECTORS.map(c => {
                const st = open.connectors?.[c.id];
                return (
                  <div key={c.id} className={`adm-conn-mini ${st ? st.status : 'off'}`}>
                    <span className="ic">{c.label.slice(0,2).toUpperCase()}</span>
                    <span className="nm">{c.label}</span>
                    {c.required && <span className="req">verplicht</span>}
                  </div>
                );
              })}
            </div>
          </div>
        </main>
      </div>

      {showNew && (
        <div className="bc-modal-backdrop" onClick={() => setShowNew(false)}>
          <div className="bc-modal" onClick={e => e.stopPropagation()}>
            <button className="bc-modal-close" onClick={() => setShowNew(false)}>×</button>
            <h3>Klant toevoegen</h3>
            <p style={{color:'var(--ink-500)', fontSize:13}}>Maak een nieuwe klant aan. Vereiste connectoren worden automatisch geïnitialiseerd zodra je inlog-credentials uitnodigt.</p>
            <div className="adm-form">
              <label>Bedrijfsnaam<input placeholder="bv. Bloemerij"/></label>
              <label>Domein<input placeholder="bloemerij.nl"/></label>
              <label>Sector<input placeholder="Retail · Bloemen & Planten"/></label>
              <label>Account-manager
                <select><option>Joost van Dijk</option><option>Lotte Verhoeven</option></select>
              </label>
              <label>Plan
                <select><option>Starter</option><option>Growth</option><option>Enterprise</option></select>
              </label>
              <label>Primaire contactpersoon (e-mail)<input type="email" placeholder="contact@klant.nl"/></label>
            </div>
            <div style={{display:'flex', gap:8, justifyContent:'flex-end', marginTop:18}}>
              <button onClick={() => setShowNew(false)} className="btn-ghost-bc">Annuleer</button>
              <button onClick={() => setShowNew(false)} className="btn-primary-bc">Klant aanmaken</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ============== ADMIN: Connectors ==============
function AdminConnectorsDashboard() {
  const D = window.ANALYTICS_DATA;
  const ANALYTICS_API = window.SER_ANALYTICS_API || '';
  const [clients, setClients] = React.useState([]);
  const [selectedId, setSelectedId] = React.useState(null);
  const [schemas, setSchemas] = React.useState({});
  const [connectors, setConnectors] = React.useState({});
  const [configuring, setConfiguring] = React.useState(null); // connector_id
  const [formData, setFormData] = React.useState({});
  const [saving, setSaving] = React.useState(false);
  const [saved, setSaved] = React.useState(null);
  const [loadingConn, setLoadingConn] = React.useState(false);

  const headers = { Authorization: `Bearer ${localStorage.getItem('ser-analytics-token')}`, 'Content-Type': 'application/json' };

  React.useEffect(() => {
    // Laad clients en schemas
    Promise.all([
      fetch(`${ANALYTICS_API}/api/admin/clients`, { headers }).then(r => r.json()),
      fetch(`${ANALYTICS_API}/api/admin/connectors/schemas`, { headers }).then(r => r.json()),
    ]).then(([clientsData, schemasData]) => {
      const cl = clientsData.clients || [];
      setClients(cl);
      setSchemas(schemasData.schemas || {});
      if (cl.length) setSelectedId(cl[0].id);
    }).catch(() => {});
  }, []);

  React.useEffect(() => {
    if (!selectedId) return;
    setLoadingConn(true);
    fetch(`${ANALYTICS_API}/api/admin/clients/${selectedId}/connectors`, { headers })
      .then(r => r.json())
      .then(d => setConnectors(d.connectors || {}))
      .catch(() => setConnectors({}))
      .finally(() => setLoadingConn(false));
  }, [selectedId]);

  const handleSave = async () => {
    if (!configuring) return;
    setSaving(true);
    try {
      const res = await fetch(`${ANALYTICS_API}/api/admin/clients/${selectedId}/connectors/${configuring}`, {
        method: 'POST', headers, body: JSON.stringify(formData),
      });
      const d = await res.json();
      if (!res.ok) { alert(d.detail || 'Fout bij opslaan'); return; }
      setConnectors(prev => ({ ...prev, [configuring]: { status:'ok', account: formData.property_id || formData.project_id || formData.store_url || formData.customer_id || 'Geconfigureerd', configured: true, freshness:'Zojuist' } }));
      setSaved(configuring);
      setConfiguring(null);
      setFormData({});
      setTimeout(() => setSaved(null), 3000);
    } catch { alert('Verbindingsfout'); }
    finally { setSaving(false); }
  };

  const handleRemove = async (connId) => {
    if (!confirm('Koppeling verwijderen?')) return;
    await fetch(`${ANALYTICS_API}/api/admin/clients/${selectedId}/connectors/${connId}`, { method: 'DELETE', headers });
    setConnectors(prev => { const n = {...prev}; delete n[connId]; return n; });
  };

  const selected = clients.find(c => c.id === selectedId);

  // Groepeer connectoren
  const connGroups = [
    { label: 'Google', ids: ['ga4','gsc','gads','bq'] },
    { label: 'E-commerce', ids: ['shopify','woo','magento'] },
    { label: 'SEO / Data', ids: ['semrush','ahrefs','serpapi'] },
    { label: 'Paid media', ids: ['meta','tiktok','linkedin'] },
    { label: 'CRM & E-mail', ids: ['hubspot','salesforce','klaviyo','mailchimp'] },
  ];

  return (
    <div style={{display:'flex', flexDirection:'column', gap:20}}>
      <div style={{display:'flex', alignItems:'center', justifyContent:'space-between'}}>
        <div>
          <h2 style={{margin:0}}>Koppelingen beheer</h2>
          <p style={{margin:'4px 0 0', color:'var(--ink-500)', fontSize:13}}>Configureer databronnen per klant. Gevoelige sleutels worden versleuteld opgeslagen.</p>
        </div>
      </div>

      <div style={{display:'grid', gridTemplateColumns:'220px 1fr', gap:16, alignItems:'start'}}>
        {/* Klanten lijst */}
        <div style={{background:'white', border:'1px solid var(--ink-100)', borderRadius:12, overflow:'hidden'}}>
          <div style={{padding:'10px 14px', borderBottom:'1px solid var(--ink-100)', fontSize:11, fontWeight:600, color:'var(--ink-500)', textTransform:'uppercase', letterSpacing:'0.06em'}}>Klanten</div>
          {clients.map(c => {
            const conn = c.id === selectedId ? connectors : {};
            const configured = Object.values(conn).filter(v => v.configured).length;
            return (
              <button key={c.id} onClick={() => setSelectedId(c.id)} style={{
                width:'100%', padding:'12px 14px', textAlign:'left',
                background: selectedId===c.id ? 'var(--ink-25)' : 'transparent',
                border:'none', borderBottom:'1px solid var(--ink-100)', cursor:'pointer',
                borderLeft:`3px solid ${selectedId===c.id ? 'var(--ser-teal)' : 'transparent'}`
              }}>
                <div style={{fontSize:13, fontWeight:600, color:'var(--ink-900)'}}>{c.name}</div>
                <div style={{fontSize:11, color:'var(--ink-400)', marginTop:2}}>{configured} bron{configured !== 1 ? 'nen' : ''} gekoppeld</div>
              </button>
            );
          })}
        </div>

        {/* Connector grid */}
        <div style={{display:'flex', flexDirection:'column', gap:16}}>
          {selected && connGroups.map(group => (
            <div key={group.label} style={{background:'white', border:'1px solid var(--ink-100)', borderRadius:12, overflow:'hidden'}}>
              <div style={{padding:'12px 16px', borderBottom:'1px solid var(--ink-100)', fontSize:12, fontWeight:700, color:'var(--ink-700)', background:'var(--ink-25)'}}>
                {group.label}
              </div>
              <div style={{display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(240px, 1fr))', gap:0}}>
                {group.ids.map(connId => {
                  const schema = schemas[connId];
                  const conn = connectors[connId];
                  const connDef = D.CONNECTORS?.find(c => c.id === connId);
                  if (!connDef && !schema) return null;
                  const label = connDef?.label || connId.toUpperCase();
                  const isConfigured = conn?.configured;
                  const hasOAuthNote = schema?.note;
                  const isConfiguring = configuring === connId;

                  return (
                    <div key={connId} style={{padding:'14px 16px', borderBottom:'1px solid var(--ink-50)', borderRight:'1px solid var(--ink-50)'}}>
                      <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom: isConfiguring ? 12 : 0}}>
                        <div>
                          <div style={{fontSize:13, fontWeight:600, color:'var(--ink-900)'}}>{label}</div>
                          {isConfigured && <div style={{fontSize:11, color:'var(--ok)', marginTop:2}}>✓ {conn.account} · {conn.freshness}</div>}
                          {!isConfigured && !hasOAuthNote && <div style={{fontSize:11, color:'var(--ink-400)', marginTop:2}}>Niet geconfigureerd</div>}
                          {hasOAuthNote && <div style={{fontSize:11, color:'var(--ink-400)', marginTop:2, maxWidth:180}}>{schema.note}</div>}
                          {saved === connId && <div style={{fontSize:11, color:'var(--ok)', fontWeight:600, marginTop:2}}>✓ Opgeslagen</div>}
                        </div>
                        {!hasOAuthNote && (
                          <div style={{display:'flex', gap:6, flexShrink:0}}>
                            {isConfigured && !isConfiguring && (
                              <button onClick={() => handleRemove(connId)} style={{background:'transparent', border:'1px solid rgba(229,57,53,0.3)', color:'var(--err)', borderRadius:6, padding:'4px 10px', fontSize:11, cursor:'pointer'}}>Verwijder</button>
                            )}
                            <button onClick={() => { setConfiguring(isConfiguring ? null : connId); setFormData({}); }}
                              style={{background: isConfiguring ? 'var(--ink-100)' : 'var(--ser-navy)', color: isConfiguring ? 'var(--ink-700)' : 'white', border:'none', borderRadius:6, padding:'4px 10px', fontSize:11, fontWeight:600, cursor:'pointer'}}>
                              {isConfiguring ? 'Annuleer' : (isConfigured ? 'Wijzig' : 'Koppelen')}
                            </button>
                          </div>
                        )}
                      </div>

                      {/* Configuratie-formulier */}
                      {isConfiguring && schema?.fields?.length > 0 && (
                        <div style={{display:'flex', flexDirection:'column', gap:8, marginTop:4}}>
                          {schema.fields.map(field => (
                            <div key={field.id}>
                              <label style={{fontSize:11, fontWeight:600, color:'var(--ink-700)', display:'block', marginBottom:4}}>{field.label}</label>
                              {field.type === 'select' ? (
                                <select value={formData[field.id] || field.options?.[0] || ''}
                                  onChange={e => setFormData(p => ({...p, [field.id]: e.target.value}))}
                                  style={{width:'100%', padding:'7px 10px', border:'1px solid var(--ink-200)', borderRadius:6, fontSize:12}}>
                                  {(field.options||[]).map(o => <option key={o}>{o}</option>)}
                                </select>
                              ) : field.type === 'file' ? (
                                <div>
                                  <input type="file" accept=".json" onChange={e => {
                                    const f = e.target.files[0];
                                    if (!f) return;
                                    const reader = new FileReader();
                                    reader.onload = ev => setFormData(p => ({...p, [field.id]: ev.target.result}));
                                    reader.readAsText(f);
                                  }} style={{fontSize:11, width:'100%'}}/>
                                  <div style={{fontSize:10, color:'var(--ink-400)', marginTop:2}}>Upload Service Account JSON van Google Cloud Console</div>
                                </div>
                              ) : (
                                <input type={field.type === 'password' ? 'password' : 'text'}
                                  value={formData[field.id] || ''}
                                  placeholder={field.placeholder || ''}
                                  onChange={e => setFormData(p => ({...p, [field.id]: e.target.value}))}
                                  style={{width:'100%', padding:'7px 10px', border:'1px solid var(--ink-200)', borderRadius:6, fontSize:12, fontFamily: field.type==='password' ? 'var(--font-mono)' : 'inherit'}}/>
                              )}
                            </div>
                          ))}
                          <button onClick={handleSave} disabled={saving}
                            style={{padding:'8px 14px', background:'var(--ser-teal)', color:'white', border:'none', borderRadius:6, fontSize:12, fontWeight:600, cursor:'pointer', marginTop:4}}>
                            {saving ? 'Opslaan…' : 'Opslaan & koppelen'}
                          </button>
                        </div>
                      )}
                    </div>
                  );
                })}
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function AiProviderCard({ provider, onSaved }) {
  const [showModal, setShowModal] = uS_adm(false);
  const [newKey, setNewKey] = uS_adm('');
  const [newModel, setNewModel] = uS_adm(provider.defaultModel || '');
  const [saving, setSaving] = uS_adm(false);
  const [saved, setSaved] = uS_adm(false);
  const [isOn, setIsOn] = uS_adm(provider.status === 'connected');

  const keyField = provider.id === 'claude' ? 'claude_api_key'
                 : provider.id === 'openai' ? 'openai_api_key'
                 : null;
  const modelField = provider.id === 'claude' ? 'claude_model' : null;

  const handleSave = async () => {
    if (!newKey.trim() && !modelField) return;
    setSaving(true);
    try {
      const payload = {};
      if (newKey.trim() && keyField) payload[keyField] = newKey.trim();
      if (modelField && newModel) payload[modelField] = newModel;
      await fetch(`${ANALYTICS_API}/api/admin/ai-config`, {
        method: 'POST', headers: getAuthHeader(), body: JSON.stringify(payload),
      });
      setIsOn(true); setSaved(true); setShowModal(false); setNewKey('');
      if (onSaved) onSaved();
    } catch(e) {
      alert('Opslaan mislukt');
    } finally { setSaving(false); }
  };

  return (
    <div className={`ai-prov-card ${isOn ? '' : 'off'} ${provider.primary ? 'primary' : ''}`}>
      {showModal && (
        <div style={{position:'fixed',inset:0,background:'rgba(14,14,42,0.5)',backdropFilter:'blur(4px)',display:'grid',placeItems:'center',zIndex:200}}
          onClick={() => setShowModal(false)}>
          <div style={{background:'white',borderRadius:14,padding:24,width:420,maxWidth:'92vw',boxShadow:'0 12px 40px rgba(0,0,0,0.2)'}}
            onClick={e => e.stopPropagation()}>
            <div style={{fontWeight:700,fontSize:16,marginBottom:4}}>{provider.label} — API key instellen</div>
            <div style={{fontSize:13,color:'var(--ink-500)',marginBottom:20}}>De key wordt opgeslagen op de server en is daarna actief voor alle AI-features.</div>
            {keyField && (
              <div style={{marginBottom:16}}>
                <label style={{fontSize:12,fontWeight:600,color:'var(--ink-700)',display:'block',marginBottom:6}}>API key</label>
                <input type="password" value={newKey} onChange={e => setNewKey(e.target.value)}
                  placeholder={provider.id === 'claude' ? 'sk-ant-...' : 'sk-...'}
                  style={{width:'100%',padding:'10px 12px',border:'1px solid var(--ink-200)',borderRadius:8,fontSize:13,fontFamily:'var(--font-mono)',outline:'none'}}
                  onKeyDown={e => e.key === 'Enter' && handleSave()} autoFocus/>
              </div>
            )}
            {provider.models?.length > 0 && (
              <div style={{marginBottom:20}}>
                <label style={{fontSize:12,fontWeight:600,color:'var(--ink-700)',display:'block',marginBottom:6}}>Standaard model</label>
                <select value={newModel} onChange={e => setNewModel(e.target.value)}
                  style={{width:'100%',padding:'10px 12px',border:'1px solid var(--ink-200)',borderRadius:8,fontSize:13}}>
                  {provider.models.map(m => <option key={m}>{m}</option>)}
                </select>
              </div>
            )}
            <div style={{display:'flex',gap:8,justifyContent:'flex-end'}}>
              <button onClick={() => setShowModal(false)}
                style={{padding:'8px 16px',borderRadius:8,border:'1px solid var(--ink-200)',background:'white',fontSize:13,cursor:'pointer'}}>
                Annuleer
              </button>
              <button onClick={handleSave} disabled={saving}
                style={{padding:'8px 16px',borderRadius:8,border:'none',background:'var(--ser-navy)',color:'white',fontSize:13,fontWeight:600,cursor:'pointer'}}>
                {saving ? 'Opslaan…' : 'Opslaan'}
              </button>
            </div>
          </div>
        </div>
      )}

      {provider.primary && <span className="primary-badge">Primair</span>}
      <div className="ai-prov-head">
        <div className={`ai-prov-logo logo-${provider.id}`}>
          {provider.id === 'claude' ? '✦' : provider.id === 'openai' ? '◉' : provider.id === 'gemini' ? '◈' : '◆'}
        </div>
        <div style={{flex:1, minWidth:0}}>
          <div className="ai-prov-name">{provider.label}</div>
          <div className="ai-prov-sub">{provider.sub}</div>
        </div>
        <span className={`ai-prov-status ${isOn ? 'on' : 'off'}`}>
          {isOn ? '● Verbonden' : '○ Niet geconfigureerd'}
        </span>
      </div>

      <div className="ai-prov-row">
        <span className="lbl">Standaard model</span>
        <span className="val">
          <span style={{fontFamily:'var(--font-mono)',fontSize:12}}>{newModel || provider.defaultModel || '—'}</span>
        </span>
      </div>

      <div className="ai-prov-row">
        <span className="lbl">API-key</span>
        <span className="val">
          {isOn ? (
            <>
              <code style={{fontFamily:'var(--font-mono)',fontSize:12}}>{'•'.repeat(24)}</code>
              <button className="link-btn" onClick={() => setShowModal(true)}>vervang</button>
            </>
          ) : (
            <button className="btn-ghost-sm" onClick={() => setShowModal(true)}>+ API-key invoeren</button>
          )}
        </span>
      </div>

      {saved && <div style={{fontSize:11,color:'var(--ok)',fontWeight:600,marginTop:8}}>✓ Opgeslagen en actief</div>}

      {isOn && (
        <>
          <div className="ai-prov-row">
            <span className="lbl">Verbruik · 30d</span>
            <span className="val">{provider.monthlyTokens} · <strong>{provider.monthlyCost}</strong></span>
          </div>

          <div className="ai-prov-row">
            <span className="lbl">Gebruikt voor</span>
            <span className="val ai-prov-uses">
              {provider.usage?.businesscases && <span className="use-pill">Business cases</span>}
              {provider.usage?.briefings && <span className="use-pill">Briefings</span>}
              {provider.usage?.insights && <span className="use-pill">AI-insights</span>}
              {provider.usage?.chat && <span className="use-pill">Chat / "Vraag AI"</span>}
              {provider.usage?.fallback && <span className="use-pill alt">Fallback</span>}
            </span>
          </div>
        </>
      )}

      <div className="ai-prov-foot">
        {isOn && <button className="btn-ghost-sm">Test verbinding</button>}
        <a className="link-btn">Docs ↗</a>
        {!isOn && <button className="btn-primary-sm">Configureer</button>}
        {isOn && !provider.primary && <button className="btn-ghost-sm">Maak primair</button>}
      </div>
    </div>
  );
}

// ============== ADMIN: Users ==============
function AdminUsersDashboard() {
  const [clients, setClients] = uS_adm([]);

  React.useEffect(() => {
    fetch(`${ANALYTICS_API}/api/admin/clients`, {
      headers: getAuthHeader()
    }).then(r => r.json()).then(d => setClients(d.clients || [])).catch(() => {});
  }, []);

  return (
    <div style={{display:'flex', flexDirection:'column', gap:22}}>
      <h2 style={{margin:0}}>Toegang &amp; rollen</h2>
      <p style={{margin:0, color:'var(--ink-500)', fontSize:13}}>Overzicht van alle gebruikers per klant. Rollen worden beheerd via klantbeheer.</p>

      <div style={{background:'white', border:'1px solid var(--ink-100)', borderRadius:12, overflow:'hidden'}}>
        <table style={{width:'100%', borderCollapse:'collapse', fontSize:13}}>
          <thead>
            <tr style={{background:'var(--ink-25)'}}>
              {['Klant','Naam','E-mail','Rol','Laatste login'].map(h => (
                <th key={h} style={{padding:'10px 16px', textAlign:'left', fontWeight:600, fontSize:11, textTransform:'uppercase', letterSpacing:'0.06em', color:'var(--ink-500)', borderBottom:'1px solid var(--ink-100)'}}>{h}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {clients.flatMap(c => (c.portalUsers || [{ name: c.name, email: c.contact, role: 'Owner', lastSeen: c.lastLogin || '—' }]).map((u, i) => (
              <tr key={`${c.id}-${i}`} style={{borderBottom:'1px solid var(--ink-100)'}}>
                <td style={{padding:'12px 16px', fontWeight:600}}>{c.name}</td>
                <td style={{padding:'12px 16px'}}>{u.name}</td>
                <td style={{padding:'12px 16px', color:'var(--ink-500)', fontFamily:'var(--font-mono)', fontSize:12}}>{u.email || c.contact}</td>
                <td style={{padding:'12px 16px'}}><span style={{padding:'2px 8px', borderRadius:999, background:'var(--ink-100)', fontSize:11, fontWeight:600}}>{u.role || 'Viewer'}</span></td>
                <td style={{padding:'12px 16px', color:'var(--ink-400)', fontSize:12}}>{u.lastSeen || '—'}</td>
              </tr>
            )))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// ============== ADMIN: Documentatie ==============
function AdminDocsDashboard() {
  const API = window.SER_ANALYTICS_API || '';
  return (
    <div style={{display:'flex', flexDirection:'column', gap:20}}>
      <div>
        <h2 style={{margin:0}}>Documentatie &amp; handleidingen</h2>
        <p style={{margin:'4px 0 0', color:'var(--ink-500)', fontSize:13}}>Interne documentatie voor het SER Analytics Platform.</p>
      </div>

      {/* Download sectie */}
      <div style={{background:'white', border:'1px solid var(--ink-100)', borderRadius:12, padding:'20px 24px'}}>
        <h3 style={{margin:'0 0 12px'}}>Platform documentatie</h3>
        <div style={{display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(280px, 1fr))', gap:12}}>
          {[
            { title: 'Technische handleiding', desc: 'Stack, deployment, nieuwe tools toevoegen', icon: '📋', href: `${API}/api/docs/download` },
            { title: 'Databronnen koppelen', desc: 'Service accounts, API keys, OAuth per bron', icon: '🔌', href: '#connectors' },
            { title: 'Business cases schrijven', desc: 'Confidence model, bandbreedtes, AI-prompts', icon: '📊', href: '#cases' },
            { title: 'Prognose & seizoenscorrectie', desc: 'Model-uitleg, minimale data-eisen (BETA)', icon: '📈', href: '#forecast' },
          ].map(d => (
            <a key={d.title} href={d.href} download={d.href.includes('download')} target={d.href.startsWith('http') ? '_blank' : undefined}
              style={{
                display:'flex', gap:14, padding:'14px 16px', borderRadius:10,
                border:'1px solid var(--ink-100)', textDecoration:'none',
                background:'var(--ink-25)', transition:'0.15s',
              }}
              onMouseEnter={e => { e.currentTarget.style.borderColor='var(--ser-teal)'; e.currentTarget.style.background='var(--ser-teal-50)'; }}
              onMouseLeave={e => { e.currentTarget.style.borderColor='var(--ink-100)'; e.currentTarget.style.background='var(--ink-25)'; }}>
              <span style={{fontSize:28}}>{d.icon}</span>
              <div>
                <div style={{fontSize:13, fontWeight:700, color:'var(--ink-900)', marginBottom:3}}>{d.title}</div>
                <div style={{fontSize:12, color:'var(--ink-500)'}}>{d.desc}</div>
              </div>
            </a>
          ))}
        </div>
      </div>

      {/* Nieuwe tool toevoegen — stappenplan */}
      <div style={{background:'white', border:'1px solid var(--ink-100)', borderRadius:12, padding:'20px 24px'}}>
        <h3 style={{margin:'0 0 16px'}}>Nieuwe databron koppelen — stappenplan</h3>
        <ol style={{margin:0, paddingLeft:20, display:'flex', flexDirection:'column', gap:12}}>
          {[
            ['Ga naar Beheer → Koppelingen', 'Selecteer de klant en klik op de databron die je wilt koppelen.'],
            ['Maak een Service Account aan (Google)', 'Voor GA4, Search Console en BigQuery: Google Cloud Console → IAM → Service Accounts → nieuw account → JSON key downloaden.'],
            ['Voeg het account toe als gebruiker', 'GA4: Admin → Account Access Management → voeg het service account email toe (Viewer rol). Zelfde voor Search Console.'],
            ['Upload de JSON en vul het ID in', 'Upload het JSON-bestand in het koppelingenformulier en vul de Property ID / Project ID in.'],
            ['Valideer de koppeling', 'Klik "Opslaan & koppelen". Status wordt groen als de verbinding werkt.'],
          ].map(([title, desc], i) => (
            <li key={i} style={{fontSize:13, color:'var(--ink-700)', lineHeight:1.6}}>
              <strong style={{color:'var(--ink-900)'}}>{title}</strong><br/>
              <span style={{color:'var(--ink-500)'}}>{desc}</span>
            </li>
          ))}
        </ol>
      </div>

      {/* API keys overzicht */}
      <div style={{background:'white', border:'1px solid var(--ink-100)', borderRadius:12, padding:'20px 24px'}}>
        <h3 style={{margin:'0 0 12px'}}>Vereiste API keys per databron</h3>
        <div style={{overflowX:'auto'}}>
          <table style={{width:'100%', borderCollapse:'collapse', fontSize:12}}>
            <thead>
              <tr style={{background:'var(--ink-25)'}}>
                {['Databron','Auth methode','Wat je nodig hebt','Waar te vinden'].map(h => (
                  <th key={h} style={{padding:'9px 14px', textAlign:'left', fontWeight:600, color:'var(--ink-600)', borderBottom:'1px solid var(--ink-100)'}}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {[
                ['GA4','Service Account JSON','JSON + Property ID (9 cijfers)','Google Cloud Console → IAM'],
                ['Search Console','Service Account JSON','Zelfde JSON als GA4 + Property URL','Google Cloud Console → IAM'],
                ['Google Ads','Developer Token + OAuth','Token + Client ID/Secret + Refresh Token','Google Ads API Center'],
                ['BigQuery','Service Account JSON','JSON + Project ID','Google Cloud Console → IAM'],
                ['Shopify','Access Token','Store URL + Admin API Token','Shopify Admin → Apps → Private apps'],
                ['Semrush','API Key','API Key','Semrush Account → API'],
                ['Ahrefs','API Key (V2 of V3)','API Key','Ahrefs Account → API'],
                ['HubSpot','Private App Key','API Key','HubSpot → Settings → Integrations'],
                ['Klaviyo','Private API Key','API Key','Klaviyo → Account → API Keys'],
              ].map((row, i) => (
                <tr key={i} style={{borderBottom:'1px solid var(--ink-100)'}}>
                  {row.map((cell, j) => <td key={j} style={{padding:'10px 14px', color: j===0?'var(--ink-900)':'var(--ink-600)'}}>{cell}</td>)}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

function PlaceholderHeaderS({ title, desc, right }) {
  return (
    <div className="dash-section-head" style={{borderBottom:'1px solid var(--ink-100)', paddingBottom:14}}>
      <div className="left">
        <h2 style={{fontSize:24}}>{title}</h2>
        <span className="sub">{desc}</span>
      </div>
      {right && <div>{right}</div>}
    </div>
  );
}

window.SourcesDashboard = SourcesDashboard;
window.AdminClientsDashboard = AdminClientsDashboard;
window.AdminConnectorsDashboard = AdminConnectorsDashboard;
window.AdminUsersDashboard = AdminUsersDashboard;
window.AdminDocsDashboard = AdminDocsDashboard;
