/* ============================================================
   Omnitok Analytics — Clientes de Connect ↔ marcas (embed)
   Asocia cada cliente de CONNECT (id Mongo) con las marcas de
   analytics a las que tiene acceso: el token oa-embed con claim
   `client` arranca el embed filtrado a esas marcas (fail-closed).
   Datos: GET/PUT /admin/client-brands, GET /admin/connect-clients
   (?refresh=1 relee Connect vía usuario de servicio; X-API-Key).
   ============================================================ */
const { useState:ceS, useEffect:ceE } = React;

function ClientsEmbedView(){
  const es = OA.lang==='es';
  const inp={padding:'8px 11px',border:'1px solid #E5E5E5',borderRadius:8,fontSize:13,boxSizing:'border-box'};
  const btn={padding:'8px 12px',border:'1px solid #E5E5E5',borderRadius:8,fontSize:13,fontWeight:600,background:'#fff',cursor:'pointer'};
  const btnP={padding:'8px 14px',border:'1px solid #4D4A9D',borderRadius:8,fontSize:13,fontWeight:700,background:'#4D4A9D',color:'#fff',cursor:'pointer'};
  const [clients,setClients]=ceS(null);      // roster (cache D1)
  const [suggestions,setSuggestions]=ceS({});
  const [q,setQ]=ceS('');
  const [onlyUnmapped,setOnlyUnmapped]=ceS(false);
  const [selId,setSelId]=ceS('');
  const [detail,setDetail]=ceS(null);        // {connect_id,name,brands,universe}
  const [sel,setSel]=ceS(new Set());         // marcas seleccionadas (edición local)
  const [savedSel,setSavedSel]=ceS(new Set());
  const [bq,setBq]=ceS('');                  // búsqueda en universo de marcas
  const [keyVal,setKeyVal]=ceS(OA.adminKey());
  const [refreshing,setRefreshing]=ceS(false);
  const [saving,setSaving]=ceS(false);
  const [msg,setMsg]=ceS(''); const [err,setErr]=ceS('');

  const wErr=(e)=> setErr(e&&e.status===401
    ? (es?'X-API-Key inválida o no configurada (candado de la derecha).':'Invalid or missing X-API-Key (padlock on the right).')
    : String((e&&e.message)||e));

  const loadRoster=(refresh)=>{
    if(refresh){ setRefreshing(true); setMsg(''); }
    setErr('');
    OA.connectClients(!!refresh).then(r=>{
      setClients(r.clients||[]); setSuggestions(r.suggestions||{});
      setRefreshing(false);
      if(refresh) setMsg(r.refresh_error
        ? (es?'Connect no respondió ('+r.refresh_error+'); mostrando cache.':'Connect did not respond ('+r.refresh_error+'); showing cache.')
        : (es?'Roster releído desde Connect: '+(r.total||0)+' clientes.':'Roster re-read from Connect: '+(r.total||0)+' clients.'));
    }).catch(e=>{ setRefreshing(false); if(clients==null) setClients([]); wErr(e); });
  };
  ceE(()=>{ loadRoster(false); },[]);

  const openClient=(id)=>{
    setSelId(id); setDetail(null); setMsg(''); setErr(''); setBq('');
    OA.clientBrandsGet(id).then(d=>{
      setDetail(d);
      const s=new Set(d.brands||[]); setSel(new Set(s)); setSavedSel(s);
    }).catch(e=>wErr(e));
  };

  const dirty = detail && (sel.size!==savedSel.size || [...sel].some(x=>!savedSel.has(x)));
  const doSave=()=>{
    if(!detail||!dirty) return;
    setSaving(true); setErr(''); setMsg('');
    OA.clientBrandsPut(detail.connect_id,[...sel]).then(r=>{
      setSaving(false);
      const s=new Set(r.brands||[]); setSel(new Set(s)); setSavedSel(s);
      setMsg(es?'Guardado: el embed de este cliente arrancará con '+(r.brands||[]).length+' marca(s).'
               :'Saved: this client’s embed will start with '+(r.brands||[]).length+' brand(s).');
      setClients(cs=>(cs||[]).map(c=>c.connect_id===detail.connect_id?{...c,mapped:(r.brands||[]).length,brands:(r.brands||[])}:c));
    }).catch(e=>{ setSaving(false); wErr(e); });
  };
  const saveKey=(v)=>{ setKeyVal(v); try{ localStorage.setItem('oa_admin_key',v); }catch(e){} };

  const sug = selId ? suggestions[selId] : null;
  const applySug=()=>{ if(sug&&sug.brands) setSel(new Set(sug.brands)); };

  const list=(clients||[]).filter(c=>{
    if(onlyUnmapped && c.mapped>0) return false;
    if(q && !(c.name||'').toLowerCase().includes(q.toLowerCase())) return false;
    return true;
  });
  const uni=(detail&&detail.universe)||[];
  const uniShown=uni.filter(b=>!bq || b.name.toLowerCase().includes(bq.toLowerCase()));

  return React.createElement('div',null,
    /* ---- barra superior: búsqueda + refresh + key ---- */
    React.createElement('div',{style:{display:'flex',gap:10,alignItems:'center',marginBottom:14,flexWrap:'wrap'}},
      React.createElement('input',{style:{...inp,width:240},placeholder:es?'Buscar cliente…':'Search client…',
        value:q,onChange:e=>setQ(e.target.value)}),
      React.createElement('label',{style:{display:'flex',alignItems:'center',gap:6,fontSize:13,cursor:'pointer'}},
        React.createElement('input',{type:'checkbox',checked:onlyUnmapped,onChange:e=>setOnlyUnmapped(e.target.checked)}),
        es?'Solo sin asociar':'Only unmapped'),
      React.createElement('button',{style:{...btn,opacity:refreshing?0.6:1},disabled:refreshing,onClick:()=>loadRoster(true),
        title:es?'Vuelve a leer los clientes desde Connect (requiere X-API-Key)':'Re-reads clients from Connect (requires X-API-Key)'},
        refreshing?(es?'Leyendo…':'Reading…'):('↻ '+(es?'Leer de Connect':'Read from Connect'))),
      React.createElement('span',{style:{marginLeft:'auto',display:'flex',alignItems:'center',gap:6}},
        React.createElement('span',{title:'X-API-Key',style:{fontSize:15}},'🔒'),
        React.createElement('input',{style:{...inp,width:170},type:'password',placeholder:'X-API-Key',
          value:keyVal,onChange:e=>saveKey(e.target.value)}))),
    err&&React.createElement('div',{style:{background:'#FEF2F2',border:'1px solid #FECACA',color:'#B91C1C',
      padding:'8px 12px',borderRadius:8,fontSize:13,marginBottom:12}},err),
    msg&&React.createElement('div',{style:{background:'#F0FDF4',border:'1px solid #BBF7D0',color:'#166534',
      padding:'8px 12px',borderRadius:8,fontSize:13,marginBottom:12}},msg),

    React.createElement('div',{style:{display:'grid',gridTemplateColumns:'340px 1fr',gap:16,alignItems:'start'}},
      /* ---- izquierda: clientes de Connect ---- */
      React.createElement('div',{className:'card',style:{padding:0,overflow:'hidden'}},
        React.createElement('div',{style:{padding:'12px 16px',borderBottom:'1px solid #F0F0F0',fontWeight:600,fontSize:13}},
          (es?'Clientes en Connect':'Clients in Connect')+(clients?' ('+list.length+')':'')),
        clients==null
          ? React.createElement('div',{style:{padding:16,color:'#888',fontSize:13}},es?'Cargando…':'Loading…')
          : list.length===0
            ? React.createElement('div',{style:{padding:16,color:'#888',fontSize:13}},
                es?'Sin clientes. Usa «Leer de Connect» para traer el roster.':'No clients. Use “Read from Connect” to pull the roster.')
            : list.map(c=>React.createElement('button',{key:c.connect_id,
                onClick:()=>openClient(c.connect_id),
                style:{display:'block',width:'100%',textAlign:'left',padding:'10px 16px',border:'none',cursor:'pointer',
                  borderBottom:'1px solid #F6F6F6',
                  background:selId===c.connect_id?'#F4F3FB':'transparent'}},
                React.createElement('div',{style:{display:'flex',alignItems:'center',gap:8}},
                  React.createElement('span',{style:{fontWeight:600,fontSize:13}},c.name||c.connect_id),
                  c.status===0&&React.createElement('span',{style:{fontSize:11,color:'#B45309'}},es?'inactivo':'inactive'),
                  React.createElement('span',{style:{marginLeft:'auto',fontSize:11,padding:'2px 8px',borderRadius:10,
                    background:c.mapped>0?'#EEF6EE':'#FDF3E7',color:c.mapped>0?'#166534':'#B45309'}},
                    c.mapped>0?(c.mapped+(es?' marca(s)':' brand(s)')):(es?'sin asociar':'unmapped'))),
                React.createElement('div',{style:{fontSize:11,color:'#999',marginTop:2}},
                  c.connect_id,
                  suggestions[c.connect_id]&&c.mapped===0
                    ? React.createElement('span',{style:{color:'#4D4A9D',marginLeft:8}},'✨ '+(es?'sugerencia disponible':'suggestion available'))
                    : null)))),

      /* ---- derecha: detalle del cliente ---- */
      !selId
        ? React.createElement('div',{className:'card',style:{padding:24,color:'#888',fontSize:13}},
            es?'Selecciona un cliente para asociar sus marcas de analytics. Con la asociación guardada, el embed de ese cliente (token con claim client) arranca filtrado a esas marcas; sin asociación no ve datos (fail-closed).'
              :'Select a client to associate its analytics brands. Once saved, that client’s embed (token with the client claim) starts filtered to those brands; with no mapping it sees no data (fail-closed).')
        : !detail
          ? React.createElement('div',{className:'card',style:{padding:24,color:'#888',fontSize:13}},es?'Cargando…':'Loading…')
          : React.createElement('div',{className:'card',style:{padding:20}},
              React.createElement('div',{style:{display:'flex',alignItems:'center',gap:10,marginBottom:4}},
                React.createElement('div',{style:{fontWeight:700,fontSize:16}},detail.name||detail.connect_id),
                React.createElement('span',{style:{fontSize:11,color:'#999'}},detail.connect_id)),
              React.createElement('div',{style:{fontSize:12,color:'#777',marginBottom:14}},
                es?'Marca las marcas de analytics a las que este cliente tendrá acceso en el embed.'
                  :'Check the analytics brands this client will access in the embed.'),
              sug&&sug.brands&&sug.brands.length>0&&React.createElement('div',{style:{background:'#F4F3FB',
                border:'1px solid #DDDAF2',borderRadius:8,padding:'10px 12px',fontSize:13,marginBottom:14,
                display:'flex',alignItems:'center',gap:10,flexWrap:'wrap'}},
                React.createElement('span',null,'✨ '+(es?'Sugerencia por ':'Suggestion via ')+sug.via+': ',
                  React.createElement('b',null,sug.brands.join(', '))),
                React.createElement('button',{style:{...btn,marginLeft:'auto'},onClick:applySug},
                  es?'Aplicar sugerencia':'Apply suggestion')),
              React.createElement('input',{style:{...inp,width:260,marginBottom:10},
                placeholder:es?'Filtrar marcas…':'Filter brands…',value:bq,onChange:e=>setBq(e.target.value)}),
              React.createElement('div',{style:{maxHeight:340,overflowY:'auto',border:'1px solid #F0F0F0',
                borderRadius:8,padding:'6px 0',marginBottom:14}},
                uniShown.map(b=>React.createElement('label',{key:b.name,
                  style:{display:'flex',alignItems:'center',gap:8,padding:'6px 14px',fontSize:13,cursor:'pointer'}},
                  React.createElement('input',{type:'checkbox',checked:sel.has(b.name),
                    onChange:e=>{ const s=new Set(sel); if(e.target.checked) s.add(b.name); else s.delete(b.name); setSel(s); }}),
                  React.createElement('span',null,b.name),
                  React.createElement('span',{style:{marginLeft:'auto',fontSize:11,color:'#AAA'}},
                    OA.fmt(b.events)+(es?' eventos':' events')))),
                uniShown.length===0&&React.createElement('div',{style:{padding:'8px 14px',fontSize:13,color:'#999'}},
                  es?'Sin marcas que coincidan.':'No matching brands.')),
              React.createElement('div',{style:{display:'flex',alignItems:'center',gap:10}},
                React.createElement('button',{style:{...btnP,opacity:(!dirty||saving)?0.5:1},disabled:!dirty||saving,onClick:doSave},
                  saving?(es?'Guardando…':'Saving…'):(es?'Guardar asociación':'Save mapping')),
                dirty&&React.createElement('span',{style:{fontSize:12,color:'#B45309'}},
                  es?'Cambios sin guardar':'Unsaved changes')),
              /* ---- así arrancará el embed ---- */
              React.createElement('div',{style:{marginTop:18,borderTop:'1px solid #F0F0F0',paddingTop:14}},
                React.createElement('div',{style:{fontWeight:600,fontSize:13,marginBottom:6}},
                  es?'Así arrancará el embed':'How the embed will start'),
                savedSel.size===0
                  ? React.createElement('div',{style:{fontSize:13,color:'#B91C1C'}},
                      es?'Sin marcas asociadas: el embed de este cliente no mostrará datos (fail-closed).'
                        :'No brands mapped: this client’s embed will show no data (fail-closed).')
                  : React.createElement('div',{style:{display:'flex',gap:6,flexWrap:'wrap'}},
                      [...savedSel].sort().map(b=>React.createElement('span',{key:b,
                        style:{fontSize:12,padding:'3px 10px',borderRadius:10,background:'#EEF6EE',color:'#166534'}},b))),
                React.createElement('div',{style:{fontSize:12,color:'#999',marginTop:8}},
                  es?'Requiere que el token oa-embed emitido por Connect traiga el claim client = id del cliente ('+detail.connect_id+').'
                    :'Requires the oa-embed token issued by Connect to carry the claim client = client id ('+detail.connect_id+').')))));
}
