(function(){ const cfg = window.AI_CHATBOT_CONFIG || {}; if (!cfg.enabled || !cfg.floatingEnabled) return; const csrf = document.body?.dataset?.csrfToken || cfg.csrfToken || ''; let sessionId = localStorage.getItem('ai_chatbot_session_id') || (crypto.randomUUID ? crypto.randomUUID() : String(Date.now())); localStorage.setItem('ai_chatbot_session_id', sessionId); let selectedSlot = null; let selectedProfessional = null; const launcher = document.createElement('button'); launcher.className = 'ai-chatbot-launcher'; launcher.type = 'button'; launcher.title = cfg.assistantName || 'Chatbot IA'; launcher.innerHTML = ''; const panel = document.createElement('div'); panel.className = 'ai-chatbot-panel'; panel.innerHTML = `
${escapeHtml(cfg.assistantName || 'Asistente Virtual')}
Especialidades · precios · turnos
`; document.body.appendChild(panel); document.body.appendChild(launcher); const body = panel.querySelector('#aiChatbotBody'); const form = panel.querySelector('#aiChatbotForm'); const input = panel.querySelector('#aiChatbotInput'); function escapeHtml(s){ return String(s || '').replace(/[&<>'"]/g, c => ({'&':'&','<':'<','>':'>',"'":''','"':'"'}[c])); } function addMessage(text, who='bot'){ const wrap = document.createElement('div'); wrap.className = `ai-chatbot-message ${who}`; wrap.innerHTML = `
${escapeHtml(text)}
`; body.appendChild(wrap); body.scrollTop = body.scrollHeight; } function addActions(actions){ if(!actions || !actions.length) return; const wrap = document.createElement('div'); wrap.className = 'ai-chatbot-actions'; actions.forEach(a => { const b = document.createElement('button'); b.type='button'; b.className='ai-chatbot-action'; b.textContent=a.label || 'Abrir'; b.addEventListener('click', () => { if(a.type === 'open_booking_form') showBookingForm(); else if(a.url) { if(a.url.startsWith('#')) location.hash=a.url; else location.href=a.url; } }); wrap.appendChild(b); }); body.appendChild(wrap); body.scrollTop = body.scrollHeight; } launcher.addEventListener('click', () => { panel.classList.toggle('open'); if(panel.classList.contains('open') && !body.dataset.started){ body.dataset.started='1'; addMessage(cfg.welcomeMessage || 'Hola, soy el asistente virtual.'); addActions([{type:'open_booking_form', label:'Solicitar turno'}, {type:'link', label:'Ver precios', url:'#services'}, {type:'link', label:'Contacto', url:'#contact'}]); input.focus(); } }); panel.querySelector('.ai-chatbot-close').addEventListener('click', () => panel.classList.remove('open')); form.addEventListener('submit', async (e) => { e.preventDefault(); const msg = input.value.trim(); if(!msg) return; input.value=''; addMessage(msg, 'user'); await sendMessage(msg); }); async function sendMessage(message){ addMessage('Estoy consultando la información disponible...', 'bot'); const last = body.lastElementChild; try{ const resp = await fetch(cfg.messageUrl, {method:'POST', headers:{'Content-Type':'application/json','X-CSRF-Token':csrf}, body:JSON.stringify({message, session_id: sessionId})}); const data = await resp.json(); if(last) last.remove(); if(!data.ok) { addMessage(data.error || 'No pude procesar la consulta.'); return; } sessionId = data.session_id || sessionId; localStorage.setItem('ai_chatbot_session_id', sessionId); addMessage(data.reply || 'Sin respuesta.'); addActions(data.actions || []); }catch(err){ if(last) last.remove(); addMessage('No pude conectarme con el asistente. Probá nuevamente.'); } } async function showBookingForm(){ const card = document.createElement('div'); card.className='ai-booking-card'; card.innerHTML = `
Turno

Solicitud guiada de turno

Te voy a guiar paso a paso.

`; body.appendChild(card); body.scrollTop = body.scrollHeight; if(window.BookingWizard && window.BookingWizard.create){ window.BookingWizard.create(card, { csrfToken: csrf, optionsUrl: cfg.bookingWizardOptionsUrl || cfg.bookingOptionsUrl, slotsUrl: cfg.bookingWizardSlotsUrl || cfg.bookingSlotsUrl, createUrl: cfg.bookingWizardCreateUrl || cfg.bookingCreateUrl, linkedPatient: null, }, { source: 'ai_chatbot', defaultMode: 'unknown', onSuccess: (data) => { addMessage(`Turno confirmado con ${data.professional}, el ${data.date} a las ${data.time}.`); if(data.branch) addMessage(`Sede seleccionada: ${data.branch}.`); addActions([{type:'link', label:'Ver comprobante', url:data.success_url}]); } }); } else { addMessage('No pude cargar el asistente de turnos. Podés usar el botón Reservar turno del sitio.'); addActions([{type:'link', label:'Abrir turnos', url:'/booking'}]); } } })();