import {createProductUi,el,button,field,card,alert,empty,skeleton,dataTable,kpis,badge} from './m12/index.mjs'; const root=document.getElementById('app');let csrf='',me=null,tenants=[],selected='',ui; const messages={authentication_required:'Iniciá sesión para continuar.',invalid_credentials:'El email o la contraseña no son correctos.',csrf_denied:'Actualizá la página y volvé a intentar.',rate_limited:'Esperá un minuto antes de volver a intentar.',PROVIDER_CONFIG:'Configurá la clave y el modelo del proveedor.',woo_connection_failed:'No se pudo conectar con WooCommerce. Revisá URL y credenciales.',source_host_not_approved:'La dirección debe pertenecer al sitio o a una fuente autorizada de este cliente.',security_denied:'La solicitud no pasó los controles de seguridad.',incomplete_or_expired_snapshot:'El catálogo está incompleto o vencido. Revisá el lote.',report_unavailable:'El reporte venció o fue revocado.'}; async function api(path,body,method=body===undefined?'GET':'POST'){ const headers={};if(body!==undefined)headers['X-CSRF-Token']=csrf;if(!(body instanceof FormData)&&body!==undefined)headers['Content-Type']='application/json'; const res=await fetch(path,{method,headers,body:body===undefined?undefined:body instanceof FormData?body:JSON.stringify(body),credentials:'same-origin'});const data=await res.json();if(!res.ok){throw new Error(messages[data.error]||'No pudimos completar la operación. Revisá los datos e intentá nuevamente.');}return data; } const path=(action='')=>'/admin/api/tenant/'+encodeURIComponent(selected)+(action?'/'+action:''); const tenant=()=>tenants.find(t=>t.id===selected); function control(label,type,value='',attrs={}){const f=field(label,type,attrs);if(type==='checkbox')f.control.checked=!!value;else f.control.value=typeof value==='object'?JSON.stringify(value):value??'';return f;} function options(label,value,items){const f=field(label,'select');items.forEach(([v,l])=>f.control.append(el('option',{value:v},l)));f.control.value=value;return f;} function notify(message){ui?.toast(message);} function act(label,fn,kind='primary'){return button(label,async e=>{const b=e.currentTarget;b.disabled=true;try{await fn();}catch(error){notify(error.message);}finally{b.disabled=false;}},kind);} function loading(task){const box=el('div',{},skeleton());queueMicrotask(async()=>{try{const result=await task();if(box.isConnected)box.replaceChildren(result);}catch(error){if(box.isConnected)box.replaceChildren(alert(error.message,'danger'));}});return box;} function formDialog(title,content){return ui.dialog(title,content);} async function reloadTenants(){tenants=(await api('/admin/api/tenants')).tenants;} async function login(){root.replaceChildren();root.removeAttribute('role');root.dataset.puiRoot='';root.dataset.puiExperience='clarity';const email=control('Email','email','',{autocomplete:'username',required:true});const password=control('Contraseña','password','',{autocomplete:'current-password',required:true});const status=el('div',{role:'status'});const form=el('form',{},email.wrapper,password.wrapper,el('button',{type:'submit',class:'pui-button pui-primary'},'Ingresar'),status);form.addEventListener('submit',async event=>{event.preventDefault();const b=form.querySelector('button');b.disabled=true;try{const result=await api('/admin/api/login',{email:email.control.value,password:password.control.value});csrf=result.csrf_token;password.control.value='';await boot();}catch(e){status.replaceChildren(alert(e.message,'danger'));}finally{b.disabled=false;}});root.append(el('main',{class:'login'},el('p',{class:'eyebrow'},'747MKT · AGENTES DE IA'),el('h1',{},'Tu operación, en un lugar.'),el('p',{},'Administrá clientes, conocimientos y conversaciones.'),form));} function createClientForm(){const id=control('Identificador (minúsculas y guion)','text',''),name=control('Nombre del negocio','text',''),url=control('Origen HTTPS, sin ruta','url','');let dialog;const content=el('div',{},id.wrapper,name.wrapper,url.wrapper,act('Crear cliente',async()=>{const r=await api('/admin/api/tenants',{id:id.control.value,business_name:name.control.value,site_url:url.control.value});selected=r.id;dialog?.close();ui?.destroy();ui=null;await boot();}));return {content,show(){dialog=formDialog('Nuevo cliente',content);}};} function overview(){return loading(async()=>{const data=await api(path('stats'));return el('div',{},el('div',{class:'status-line'},badge(tenant().billing_status),el('p',{},me.provider_configured?'Proveedor configurado':'Configurá el proveedor en Conexiones')),kpis([{label:'Conversaciones',value:data.conversations,change:'Sesiones con turnos en el período UTC'},{label:'Turnos',value:data.counts.turn_completed||0,change:'Turnos únicos registrados'},{label:'Clics de contacto',value:data.counts.card_clicked||0,change:'No confirman envío ni atención'},{label:'Datos registrados',value:data.counts.lead_recorded||0,change:'Con consentimiento del visitante'}]),card('Estado del cliente',el('p',{},'Los estados migrados requieren revisión antes de habilitar atención pública.'),el('div',{class:'actions'},button('Abrir configuración',()=>ui.navigate('agent'),'primary'),el('a',{class:'pui-button pui-secondary',href:'/preview?site='+selected,target:'_blank',rel:'noopener'},'Probar agente'))),card('Incorporar a la web',el('p',{},'El widget se limita a los orígenes autorizados de este cliente.'),el('pre',{class:'mono'},'')));});} function agent(){const t=tenant(),s=t.settings;const fields={business_name:control('Nombre del negocio','text',t.business_name),business_niche:control('Actividad','text',s.business_niche),agent_name:control('Nombre del asistente','text',s.agent_name),agent_role:control('Rol','text',s.agent_role),agent_tone:control('Tono','text',s.agent_tone),business_hours:control('Horarios','textarea',s.business_hours),site_url:control('Sitio web HTTPS','url',s.site_url),whatsapp_number:control('WhatsApp internacional (solo dígitos)','text',s.whatsapp_number),price_guidance:control('Orientación sobre precios','textarea',s.price_guidance),ui_color_primary:control('Color principal','color',s.ui_color_primary||'#6657e8'),trial_expires_at:control('Fin de prueba (UTC)','date',s.trial_expires_at||'')};const status=options('Estado comercial',t.billing_status,[['needs_review','Pendiente de revisión'],['active','Activo'],['trial','Prueba con vencimiento'],['suspended','Suspendido']]);const engine=options('Perfil',t.engine,[['service','Servicios'],['store','Tienda / catálogo']]);const origins=control('Orígenes autorizados (uno por línea)','textarea',(s.allowed_origins||[]).join('\n'));const required=control('Campos de captura (uno por línea)','textarea',(s.lead_required_fields||[]).join('\n'));const prices=control('Mostrar precios publicados','checkbox',s.prices_visible),voiceIn=control('Habilitar dictado cuando el navegador lo soporte','checkbox',s.voice_dictation),voiceOut=control('Habilitar lectura de respuestas','checkbox',s.voice_read_answers),zoom=control('Permitir ampliar avatar','checkbox',s.ui_avatar_click_zoom),avatarSize=options('Tamaño del avatar',s.ui_avatar_size||'medium',[['small','Pequeño'],['medium','Mediano'],['large','Grande']]);const grid=el('div',{class:'form-grid'},...Object.values(fields).map(f=>f.wrapper),status.wrapper,engine.wrapper,origins.wrapper,required.wrapper,prices.wrapper,voiceIn.wrapper,voiceOut.wrapper,zoom.wrapper,avatarSize.wrapper);const avatar=field('Avatar público PNG/JPG/WebP (hasta 2 MB, 2048 px)','file',{accept:'image/png,image/jpeg,image/webp'});avatar.control.addEventListener('change',async()=>{if(!avatar.control.files[0])return;const form=new FormData();form.append('file',avatar.control.files[0]);try{await api(path('avatar'),form);await reloadTenants();notify('Avatar actualizado.');}catch(e){notify(e.message);}});return card('Configuración del agente',grid,avatar.wrapper,el('p',{class:'caption'},'Campos admitidos: name, whatsapp, email, interest, city. Una lista vacía mantiene la captura opcional.'),el('div',{class:'actions'},act('Guardar cambios',async()=>{const b=Object.fromEntries(Object.entries(fields).map(([k,v])=>[k,v.control.value]));b.billing_status=status.control.value;b.engine=engine.control.value;b.allowed_origins=origins.control.value.split('\n').map(v=>v.trim()).filter(Boolean);b.lead_required_fields=required.control.value.split('\n').map(v=>v.trim()).filter(Boolean);b.prices_visible=prices.control.checked;b.voice_dictation=voiceIn.control.checked;b.voice_read_answers=voiceOut.control.checked;b.ui_avatar_click_zoom=zoom.control.checked;b.ui_avatar_size=avatarSize.control.value;await api(path(),b);await reloadTenants();notify('Configuración guardada.');})));} async function editDoc(id){const doc=id?await api(path('document')+'?id='+id):{filename:'documento.txt',body:'',status:'draft',type:'factual'};const filename=control('Nombre .txt','text',doc.filename);const type=options('Tipo',doc.type,[['factual','Información factual'],['reference','Referencia'],['catalog','Catálogo'],['policy_draft','Borrador de política']]);const body=control('Contenido','textarea',doc.body,{class:'pui-input editor'});const status=options('Publicación',doc.status,[['draft','Borrador'],['published','Publicado'],['archived','Archivado']]);let dialog;const node=el('div',{},filename.wrapper,type.wrapper,status.wrapper,body.wrapper,el('div',{class:'actions'},act('Guardar versión',async()=>{await api(path('document'),{...(id?{id}:{}),filename:filename.control.value,type:type.control.value,status:status.control.value,body:body.control.value});dialog.close();ui.refresh();notify('Documento guardado.');})));if(id)node.append(act('Ver versiones anteriores',async()=>{const versions=(await api(path('versions')+'?id='+id)).versions;formDialog('Restaurar una versión',el('div',{},versions.length?versions.map(v=>card(v.created_at,el('p',{},v.status),act('Restaurar',async()=>{await api(path('rollback'),{id,revision:v.revision});dialog.close();ui.refresh();notify('Versión restaurada.');}))):empty('Todavía no hay versiones anteriores.')));},'secondary'));dialog=formDialog(id?'Editar conocimiento':'Nuevo conocimiento',node);} function knowledge(){return loading(async()=>{const docs=(await api(path('knowledge'))).documents;const upload=field('Subir TXT UTF-8 (hasta 1 MB)','file',{accept:'.txt,text/plain'});upload.control.addEventListener('change',async()=>{if(!upload.control.files[0])return;const form=new FormData();form.append('file',upload.control.files[0]);try{await api(path('upload'),form);ui.refresh();notify('Archivo incorporado como borrador.');}catch(e){notify(e.message);}});const url=control('Leer una URL autorizada','url','',{placeholder:'https://sitio-del-cliente/…'});return el('div',{},el('div',{class:'actions'},act('Nuevo documento',()=>editDoc())),card('Ingreso manual y asistido',upload.wrapper,url.wrapper,act('Leer y guardar borrador',async()=>{await api(path('assist'),{url:url.control.value});ui.refresh();notify('Lectura incorporada. Revisá el borrador antes de publicarlo.');})),dataTable(['Documento','Tipo','Estado','Bytes'],docs.map(d=>[d.filename,d.type,d.status,d.bytes]),{caption:'Conocimiento por cliente',onRow:row=>editDoc(docs.find(d=>d.filename===row[0]).id)}));});} function destinations(){return loading(async()=>{const rows=(await api(path('destinations'))).destinations;function edit(d={id:'',route:'',label:'',kind:'whatsapp',href:'',keywords:[]}){const controls={id:control('ID estable (letras minúsculas, guion)','text',d.id),route:control('Ruta del motor','text',d.route),label:control('Nombre visible del área','text',d.label),href:control('URL HTTPS del destino','url',d.href),keywords:control('Temas de esta área (separados por coma)','textarea',d.keywords.join(', '))};const kind=options('Canal',d.kind,[['whatsapp','WhatsApp'],['form','Formulario'],['link','Enlace oficial'],['queue','Cola interna']]);const dialog=formDialog('Destino de contacto',el('div',{},...Object.values(controls).map(f=>f.wrapper),kind.wrapper,act('Guardar destino',async()=>{await api(path('destination'),{id:controls.id.control.value,route:controls.route.control.value,label:controls.label.control.value,href:controls.href.control.value,keywords:controls.keywords.control.value.split(',').map(v=>v.trim()).filter(Boolean),kind:kind.control.value});dialog.close();ui.refresh();})));}return el('div',{},el('div',{class:'actions'},button('Nuevo destino',()=>edit(),'primary')),dataTable(['Área','Canal','Ruta'],rows.map(d=>[d.label,d.kind,d.route]),{caption:'Destinos configurados y trazables',onRow:row=>edit(rows.find(d=>d.route===row[2]))}),alert('Un enlace preparado no confirma que el mensaje fue enviado ni que el área atendió.'));});} function connections(){return loading(async()=>{const data=await api(path('connections'));const key=control('Clave API del proveedor (vacío conserva la actual)','password','',{autocomplete:'new-password'}),model=control('Modelo OpenAI','text',me.model||''),wooURL=control('URL de la tienda WooCommerce','url',tenant().settings.wc_store_url||tenant().settings.site_url),currency=control('Moneda ISO (para REST privado, por ejemplo ARS)','text',tenant().settings.currency||''),wooKey=control('Consumer key WooCommerce (opcional)','password','',{autocomplete:'new-password'}),wooSecret=control('Consumer secret WooCommerce (opcional)','password','',{autocomplete:'new-password'});const sync=el('div',{role:'status'});return el('div',{},card('Proveedor de conversación',badge(me.provider_configured?'Clave configurada':'Pendiente de configuración'),model.wrapper,key.wrapper,act('Guardar proveedor',async()=>{await api('/admin/api/settings',{openai_model:model.control.value,...(key.control.value?{openai_api_key:key.control.value}:{})});key.control.value='';me=await api('/admin/api/me');notify('Proveedor guardado.');})),card('WooCommerce',el('p',{},data.woo_key_configured?'Credenciales privadas configuradas.':'Puede usarse la API pública Store o configurar acceso REST de solo lectura.'),wooURL.wrapper,currency.wrapper,wooKey.wrapper,wooSecret.wrapper,el('div',{class:'actions'},act('Guardar conexión',async()=>{await api(path(),{wc_store_url:wooURL.control.value,currency:currency.control.value.trim().toUpperCase()});await api(path('connections'),{woo_key:wooKey.control.value,woo_secret:wooSecret.control.value});wooKey.control.value='';wooSecret.control.value='';await reloadTenants();notify('Conexión guardada.');}),act('Sincronizar catálogo',async()=>{const r=await api(path('woo-sync'),{});notify('Catálogo actualizado: '+r.items+' productos.');},'secondary'))),card('Receptor inmobiliario',el('p',{},'Endpoint: '+location.origin+'/v1/sync. El token se muestra una sola vez y queda cifrado.'),act('Generar o rotar token de sincronización',async()=>{const r=await api(path('connections'),{rotate_sync:true});sync.replaceChildren(el('p',{},'Guardá el token en la configuración privada del emisor:'),el('pre',{class:'mono'},r.sync_token));},'secondary'),sync,el('p',{class:'caption'},'JSON: complete:true, site, batch_id, timestamp ISO, total e items. El emisor WordPress original no estaba incluido en el material recibido.')));});} function catalog(){return loading(async()=>{const items=(await api(path('catalog'))).items;const content=control('Importar contenido inmobiliario (formato original)','textarea','',{class:'pui-input editor'});return el('div',{},dataTable(['ID','Título','Operación','Tipo','Zona'],items.map(p=>[p.id,p.title,p.operation,p.type,p.zone]),{caption:'Catálogo estructurado'}),card('Importación manual de catálogo',content.wrapper,act('Validar e importar lote completo',async()=>{if(!content.control.value.trim())throw new Error('Pegá el lote completo antes de importar.');const total=Number(prompt('Cantidad total de propiedades del lote'));if(!Number.isInteger(total)||total<0)throw new Error('Indicá la cantidad total declarada por el emisor.');const r=await api(path('catalog'),{content:content.control.value,total});ui.refresh();notify('Lote publicado: '+r.items+' elementos.');})),alert('Los snapshots antiguos se identifican como datos sin vigencia confirmada. Sincronizá antes de confirmar stock o disponibilidad.'));});} function conversations(){return loading(async()=>{const data=await api(path('conversations'));const rows=data.turns.map(t=>{let r={};try{r=JSON.parse(t.response||'{}');}catch{}return [t.session_id,t.version,r.reply||'Turno pendiente',r.status||'pendiente'];});return el('div',{},dataTable(['Sesión','Versión','Respuesta','Estado'],rows,{caption:'Conversaciones internas',onRow:row=>formDialog('Detalle de conversación',el('pre',{class:'table-detail'},JSON.stringify(data.turns.filter(t=>t.session_id===row[0]).map(t=>{try{return JSON.parse(t.response);}catch{return {};}}),null,2)))}),dataTable(['Fecha','Destino','Datos confirmados'],data.leads.map(l=>[l.created_at,l.destination_id,l.payload_json]),{caption:'Datos registrados con consentimiento'}),alert('Esta información es interna. Los reportes compartidos contienen solo métricas agregadas.'));});} function stats(){return loading(async()=>{const from=control('Desde (UTC)','date',new Date().toISOString().slice(0,7)+'-01'),to=control('Hasta (UTC)','date',new Date().toISOString().slice(0,10));const result=el('div');async function refresh(){const data=await api(path('stats')+'?from='+from.control.value+'&to='+to.control.value);result.replaceChildren(kpis([{label:'Conversaciones',value:data.conversations,change:'Sesiones con turnos'},{label:'Turnos',value:data.counts.turn_completed||0,change:'Reenvíos deduplicados'},{label:'Clics',value:data.counts.card_clicked||0,change:'Eventos del widget'}]),dataTable(['Evento','Cantidad'],Object.entries(data.counts),{caption:'Embudo de atención'}),alert('Las tarjetas mostradas, los clics y los envíos confirmados son hechos diferentes. La entrega externa no está conectada. Los costos en USD no se certifican sin facturación del proveedor.'),dataTable(['Período legado','Turnos del proveedor','Tokens de entrada','Tokens de salida'],(data.legacy_separate||[]).map(r=>{const c=JSON.parse(r.payload_json);return [r.period,c.turns??'—',c.prompt_tokens??'—',c.completion_tokens??'—'];}),{caption:'Contadores legados: no representan personas ni entregas confirmadas'}));}await refresh();return el('div',{},card('Período del reporte',el('div',{class:'form-grid'},from.wrapper,to.wrapper),act('Aplicar período',refresh)),result);});} function reports(){return loading(async()=>{const reports=(await api(path('reports'))).reports;const result=el('div',{role:'status'});return el('div',{},card('Compartir resultados',el('p',{},'El enlace dura 30 días, muestra métricas agregadas y se puede revocar.'),act('Crear enlace de 30 días',async()=>{const r=await api(path('reports'),{days:30});const url=location.origin+r.url;result.replaceChildren(el('a',{href:url,target:'_blank',rel:'noopener'},url),button('Copiar enlace',async()=>{try{await navigator.clipboard.writeText(url);notify('Enlace copiado.');}catch{notify('Seleccioná y copiá el enlace visible.');}},'secondary'));}),result),...reports.map(r=>card('Reporte '+r.id,el('p',{},'Vence: '+new Date(r.expires_at*1000).toLocaleString()),r.revoked?badge('Revocado'):act('Revocar',async()=>{await api(path('reports'),{revoke:r.id});ui.refresh();},'secondary'))));});} async function boot(){me=await api('/admin/api/me');csrf=me.csrf_token;await reloadTenants();selected=selected||tenants[0]?.id;if(!selected){root.removeAttribute('role');root.dataset.puiRoot='';root.dataset.puiExperience='clarity';root.replaceChildren(el('main',{class:'login'},el('h1',{},'Creá tu primer cliente'),createClientForm().content));return;}root.removeAttribute('role');root.replaceChildren();const defs=[['overview','Resumen',overview],['agent','Cliente y agente',agent],['knowledge','Conocimientos',knowledge],['destinations','Destinos',destinations],['connections','Conexiones',connections],['catalog','Catálogo',catalog],['conversations','Conversaciones',conversations],['stats','Estadísticas',stats],['reports','Compartir reportes',reports]];const inventory=defs.map(([id,label])=>({route_id:id,url_pattern:'#'+id,route_group:'Atención',screen_name:label,screen_type:'workspace',shell_type:'application',surface_type:'full-app',authorized_test_fixture:'installed-tenant-data',legacy_styles_status:'isolated',render_adapter:'agentes-ia-http',uses_host_permissions:true,required_components:['card','button','input'],actions:[],state_scenarios:['default'],description:'Administración de '+tenant().business_name}));ui=await createProductUi({root,experience:localStorage.getItem('agentes-experience')||'clarity',brand:{name:'Agentes de IA',accent:'#5d43c9',onAccent:'#ffffff'},labels:{context:'747MKT · Atención y conocimiento'},adapter:{inventory,routes:defs.map(d=>d[0]),navigation:{sections:[{label:'Operación',items:defs.map(([id,label])=>({id,label,href:'#'+id}))}]},screens:Object.fromEntries(defs.map(([id,,render])=>[id,render])),preferences:{get:()=>localStorage.getItem('agentes-experience'),set:id=>localStorage.setItem('agentes-experience',id)}}});const picker=field('Cliente','select',{class:'pui-input tenant-picker'});tenants.forEach(t=>picker.control.append(el('option',{value:t.id},t.business_name)));picker.control.value=selected;picker.control.addEventListener('change',()=>{selected=picker.control.value;inventory.forEach(d=>d.description='Administración de '+tenant().business_name);ui.refresh();});root.querySelector('.pui-topbar').append(picker.wrapper,button('Nuevo cliente',()=>createClientForm().show(),'secondary'),act('Cerrar sesión',async()=>{await api('/admin/api/logout',{});ui.destroy();csrf='';await login();},'secondary'));} boot().catch(()=>login());