import {mountCentralUI} from './instinct-central-ui.mjs'; import {GmailBridge,ActivityLog,makeRequest,sign} from './instinct-gmail.mjs'; export function mountInstinctUI(AP){ let key=null,bridge=null,timer=null,reviewTimer=null,prepared=null,originalAsk=AP.ask.bind(AP),enabled=false; const conversations=Object.fromEntries(['ALPHA','BETA','GAMMA'].map(a=>[a,{id:crypto.randomUUID().replaceAll('-',''),sequence:0,history:[]}])) let log;try{log=new ActivityLog();}catch{log=null;} const style=document.createElement('style');style.textContent='#instinct-panel{position:fixed;inset:8% 8%;max-height:84vh;overflow:auto;background:var(--bg,#0b1220);color:var(--text,#edf3ff);border:1px solid #677b91;border-radius:16px;padding:22px;z-index:99999;box-shadow:0 12px 80px #0009}#instinct-panel label{display:block;margin:10px 0}#instinct-panel input,#instinct-panel select,#instinct-panel button{font:inherit;padding:8px;border-radius:6px;max-width:100%;color:#102034;background:#e6eef6}#instinct-panel input[type=text],#instinct-panel input[type=email]{width:90%}#instinct-panel pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:32vh;overflow:auto;background:#101a2e;color:#e9f1ff;padding:12px;border-radius:8px}#instinct-panel button{margin:4px}#instinct-open{position:static;margin-top:12px;border-top:1px solid #304565;border-radius:0;min-height:42px}';document.head.append(style); const open=document.createElement('button');open.id='instinct-open';open.textContent='⚙ Instinct · Gmail';open.type='button';open.className='nav-item';const sidebar=document.getElementById('ap-sidebar');if(sidebar)sidebar.append(open);else throw Error('Menú de configuración no disponible'); const panel=document.createElement('section');panel.id='instinct-panel';panel.hidden=true;panel.setAttribute('aria-label','Conexión Instinct Gmail');panel.innerHTML=`
Prueba manual. Gmail solo funciona con esta pestaña abierta y OAuth vigente. Ningún correo se envía al autorizar.
Firma: falta CryptoKey privada de sesión. No pegues contraseñas o claves en este panel.
Pendiente de OAuth, firma y respondedor.
Los resúmenes se preparan localmente. No se envían solos ni constan como verificados por Instinct. Autoenvío y devolución firmada pendientes.
Sin mensaje preparado.`;document.body.append(panel); const el=id=>panel.querySelector('#'+id),status=t=>el('ig-status').textContent=t; function event(event,extra={}){if(!log){status('Log no disponible: revisa almacenamiento antes de usar el puente.');throw Error('Activity log unavailable');}try{return log.append({event,...extra});}catch{status('No se pudo guardar el log. Puente pausado para evitar actividad sin registro.');enabled=false;el('ig-enabled').checked=false;throw Error('Log write failed');}} function show(){panel.hidden=false;}open.onclick=show;el('ig-close').onclick=()=>panel.hidden=true; function showSummary(summary){show();el('ig-preview').textContent=JSON.stringify(summary,null,2);status('Resumen local preparado. Sin enviar ni verificar.');} async function prepare(text){if(!AP.db)throw Error('La base del ERP no está lista.');if(!bridge||(!key&&!bridge.manualUnauthenticated))throw Error('Falta autorizar Gmail o elegir prueba manual no autenticada.');const agent=el('ig-agent').value,c=conversations[agent];if([...bridge.jobs.values()].some(j=>j.request.conversation===c.id&&!['answered','expired'].includes(j.status)))throw Error('Hay un turno pendiente o incierto. No se reenvía automáticamente.');const context={...AP.context(),mode:AP.mode,suppliers:AP.rows('SELECT s.id,s.name,s.lead_days,sp.sku,sp.unit_cost_cents,sp.min_order_qty FROM suppliers s JOIN supplier_products sp ON sp.supplier_id=s.id WHERE s.active=1')};const draft=makeRequest({conversation:c.id,agent,sequence:c.sequence+1,text,context,replyTo:bridge.mailbox,history:c.history.slice(-6)});prepared=bridge.manualUnauthenticated?{...draft,authentication:'none-manual-test'}:await sign(draft,key);event('request_prepared',{agent,requestId:prepared.id,conversation:prepared.conversation,sequence:prepared.sequence,status:'prepared'});el('ig-preview').textContent='Cuenta: '+bridge.mailbox+'\nDestino: '+bridge.destination+'\n\n'+JSON.stringify(prepared,null,2);el('ig-send').disabled=false;status('Revisa cuenta, destino y contenido completo antes de pulsar Enviar.');show();} el('ig-authorize').onclick=async()=>{try{if(bridge&&[...bridge.jobs.values()].some(j=>['sent','uncertain','sending'].includes(j.status))){await bridge.authorize();status('Token renovado; pendientes conservados.');return;}if(!globalThis.google?.accounts?.oauth2)throw Error('Google Identity Services no cargó. Revisa conexión o bloqueador.');bridge=new GmailBridge({clientId:el('ig-client').value.trim(),mailbox:el('ig-mailbox').value.trim(),destination:el('ig-destination').value.trim(),key,manualUnauthenticated:el('ig-manual').checked});await bridge.authorize();event('oauth_connected',{status:'connected'});status('Gmail autorizado. '+(bridge.manualUnauthenticated?'PRUEBA NO AUTENTICADA. ': '')+(key?'Firma disponible.':'Firma aún pendiente.'));}catch(e){status(e.message);}}; el('ig-manual').onchange=()=>{if(bridge){el('ig-manual').checked=bridge.manualUnauthenticated;status('Modo fijado al autorizar. No lo cambies con turnos pendientes; desconecta y recarga para otra prueba.');}else status(el('ig-manual').checked?'Prueba manual NO AUTENTICADA seleccionada. Autoriza Gmail después.':'Modo firmado: requiere clave privada.');}; el('ig-disconnect').onclick=()=>{bridge?.disconnect();clearInterval(timer);clearInterval(reviewTimer);el('ig-poll').checked=false;prepared=null;el('ig-send').disabled=true;status('Token eliminado de memoria. Pendientes siguen solo en esta sesión. Revoca permisos en Google si quieres retirar el consentimiento.');}; el('ig-enabled').onchange=()=>{enabled=el('ig-enabled').checked;try{event('bridge_mode_changed',{status:enabled?'enabled':'disabled'});}catch{return;}if(enabled){clearInterval(AP.cycleTimer);AP.startCycle=function(){clearInterval(this.cycleTimer);};status('Chat usa Gmail manual. Ciclo simulado detenido.');}else status('Chat anterior restaurado; ciclo automático continúa detenido.');}; AP.ask=async function(text,quiet=false,...rest){if(!enabled)return originalAsk(text,quiet,...rest);try{if(quiet)return;await prepare(text);}catch(e){status(e.message);show();}}; el('ig-review').onclick=async()=>{try{if(!enabled)throw Error('Activa primero el puente de chat.');const text=document.getElementById('chatInput').value.trim();if(!text)throw Error('Escribe la consulta en el chat del ERP.');await prepare(text);}catch(e){status(e.message);}}; el('ig-send').onclick=async()=>{try{if(!prepared||!enabled)throw Error('Prepara y revisa la consulta primero.');const r=prepared;if(Date.parse(r.expires_at)