/* ── ELE WIDGET — PIA Chat v3 ──────────────────────────────────── */
/* State machine. Vanilla JS. No frameworks.                       */

// Base URL: detecta desde dónde se carga el script para auto-inyectar CSS.
// Con `defer`, document.currentScript puede ser null → buscamos en todos los scripts.
var _ELE_SCRIPT_SRC = (function () {
  if (document.currentScript && document.currentScript.src) return document.currentScript.src;
  var scripts = document.getElementsByTagName('script');
  for (var i = 0; i < scripts.length; i++) {
    if (scripts[i].src && scripts[i].src.indexOf('index.js') > -1) return scripts[i].src;
  }
  return '';
}());
var _ELE_BASE = _ELE_SCRIPT_SRC
  ? _ELE_SCRIPT_SRC.replace(/\/index\.js(\?.*)?$/, '/')
  : 'https://widget.soypia.com/';

// ============================================
// SECCIÓN 1: CONFIGURACIÓN
// ============================================

const CONFIG = {
  API_URL:               'https://wkklgodtwlzxclpzubfr.supabase.co/functions/v1/web-chat',
  PROACTIVE_DELAY:       13000,
  GREETED_KEY:           'ele_greeted',
  SESSION_KEY:           'ele_session_id',
  MESSAGES_KEY:          'ele_messages',
  DELAY_BASE:            800,
  DELAY_PER_CHAR:        30,
  DELAY_MAX:             4000,
  STREAMING_SPEED:       25,
  BOOKING_URL:           'https://outlook.office.com/book/SoportePia@soypia.com/',
  BOOKING_TIMEOUT:       3000,
};

const GREETINGS = {
  hero: 'Hola, soy Ele de PIA. Si no encontrás lo que buscás acá, contame y te ayudo.',
  tp:   'Esa capacidad que se gasta en perseguir y reconstruir. Cuántas personas dedicás a eso hoy?',
  s3:   'Querés ver cómo esto aplica en tu tipo de operación?',
  faq:  'Si no encontrás lo que buscás acá, contame y te ayudo.',
  cta:  '20 minutos y te mostramos cómo aplica en tu operación. Qué días te funcionan?',
};

const BUTTONS = {
  hero: [
    { text: 'Tengo una pregunta',        icon: 'chat',     action: 'chat' },
    { text: 'Aplica para mi operación?', icon: 'search',   action: 'chat' },
    { text: 'Agendar llamada',           icon: 'calendar', action: 'booking' },
  ],
  tp: [
    { text: 'Cómo se activa?',           icon: 'chat',     action: 'chat' },
    { text: 'Qué incluye la entrada?',   icon: 'chat',     action: 'chat' },
    { text: 'Agendar llamada',           icon: 'calendar', action: 'booking' },
  ],
  s3: [
    { text: 'Equipo en campo',            icon: 'chat',     action: 'chat' },
    { text: 'Cumplimiento/auditoría',     icon: 'chat',     action: 'chat' },
    { text: 'Agendar llamada',            icon: 'calendar', action: 'booking' },
  ],
  faq: [
    { text: 'Tengo otra pregunta',        icon: 'chat',     action: 'chat' },
    { text: 'Hablar con alguien',         icon: 'chat',     action: 'chat' },
    { text: 'Agendar llamada',            icon: 'calendar', action: 'booking' },
  ],
  cta: [
    { text: 'Agendar llamada',            icon: 'calendar', action: 'booking' },
    { text: 'WhatsApp directo',           icon: 'wa',       action: 'whatsapp' },
  ],
};

// ============================================
// SECCIÓN 1b: TEXTOS UI (multi-tenant ready)
// ============================================
// Fuente única de todos los strings visibles al usuario.
// En el futuro estos textos vendrán de la DB por organización.

const TEXTS = {
  mic_no_support:    'Tu navegador no soporta grabación de audio',
  mic_permission:    'Permite el micrófono para grabar',
  audio_processing:  'Procesando audio…',
  audio_fail:        'No pude entender el audio. Podés intentar de nuevo o escribirme por texto?',
  audio_send_error:  'No se pudo enviar. Tocá para reintentar.',
  audio_limit_warning: 'Máximo 2 minutos',
};

const WA_URL = 'https://wa.me/50664837800?text=Hola%2C+vi+el+sitio+de+PIA+y+quiero+entender+si+aplica+para+mi+operaci%C3%B3n.';

const ICON = {
  chat:     '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',
  calendar: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>',
  search:   '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>',
  wa:       '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z"/></svg>',
};

// ============================================
// SECCIÓN 2: STATE MACHINE
// ============================================

const STATE = {
  view:           'closed',   // 'closed' | 'home' | 'chat' | 'booking'
  messages:       [],
  section:        'hero',
  greetingShown:  false,
  greetingFrozen: false,
  isTyping:       false,
  sessionId:      sessionStorage.getItem('ele_session_id') || null,
  shareOpen:      false,
  // Booking calendar state
  bookingDate:    null,   // { year, month } currently displayed
  bookingDay:     null,   // selected day number
  bookingSlot:    null,   // '9-12' | '14-17'
  // Audio state
  audioMode:      null,   // null | 'recording'
  audioBlob:      null,
  audioURL:       null,
  audioSeconds:   0,
  _audioTimer:    null,
  _mediaRecorder: null,
  _audioChunks:   [],
  _audioStream:   null,
  _audioCtx:      null,
  _waveAnimId:    null,
  _mimeType:      'audio/webm',
  // UI
  typingText:     null,   // override typing indicator with text (e.g. audio_processing)
};

(function () {
  try {
    var saved = sessionStorage.getItem('ele_messages');
    if (saved) STATE.messages = JSON.parse(saved);
  } catch (e) {}
})();

var _renderTimer = null;
function setState(changes) {
  Object.assign(STATE, changes);
  clearTimeout(_renderTimer);
  _renderTimer = setTimeout(render, 16);
}

function saveMessages() {
  try {
    sessionStorage.setItem(CONFIG.MESSAGES_KEY, JSON.stringify(STATE.messages));
    if (STATE.sessionId) sessionStorage.setItem(CONFIG.SESSION_KEY, STATE.sessionId);
  } catch (e) {}
}

// ============================================
// SECCIÓN 3: RENDER
// ============================================

function render() {
  var root = document.getElementById('ele-widget-root');
  if (!root) return;

  var fab = root.querySelector('.ele-fab');
  if (fab) fab.style.display = STATE.view === 'closed' ? 'flex' : 'none';

  var backBtn = root.querySelector('.ele-back');
  if (backBtn) backBtn.style.display = (STATE.view === 'chat' || STATE.view === 'booking') ? 'flex' : 'none';

  // Share button: only in chat view
  var shareBtn = root.querySelector('.ele-share-btn');
  if (shareBtn) shareBtn.style.display = STATE.view === 'chat' ? 'flex' : 'none';

  var panel = root.querySelector('.ele-panel');
  if (panel) {
    if (STATE.view === 'closed') {
      panel.classList.remove('is-open');
    } else {
      panel.classList.add('is-open');
      renderPanelContent(panel);
    }
  }

  var popup = root.querySelector('.ele-greeting-popup');
  if (popup) {
    popup.style.display = (STATE.greetingShown && STATE.view === 'closed') ? 'block' : 'none';
  }
}

function renderPanelContent(panel) {
  var content = panel.querySelector('.ele-content');
  if (!content) return;
  if (STATE.view === 'home')         renderHome(content);
  else if (STATE.view === 'booking') renderBooking(content);
  else if (STATE.view === 'chat') {
    // Don't destroy recording/preview UI on intermediate setState calls
    if (content.querySelector('.ele-chat') && STATE.audioMode !== null) {
      renderMessages();
      return;
    }
    renderChat(content);
  }
}

// ============================================
// SECCIÓN 4: HOME SPACE
// ============================================

function renderHome(container) {
  var greeting = GREETINGS[STATE.section] || GREETINGS.hero;
  var buttons  = BUTTONS[STATE.section]   || BUTTONS.hero;
  var isMobile = window.matchMedia('(max-width: 768px)').matches;

  var buttonsHtml = buttons.map(function (btn, i) {
    var iconSvg = ICON[btn.icon] || ICON.chat;
    if (isMobile && i >= 2) {
      if (btn.action === 'booking') {
        return '<a href="#" class="ele-home-link" data-action="booking">' + ICON.calendar + ' ' + escapeHtml(btn.text) + ' →</a>';
      }
      return '';
    }
    return '<button type="button" class="ele-home-btn" data-action="' + escapeAttr(btn.action) + '" data-text="' + escapeAttr(btn.text) + '">' +
      '<span class="ele-home-btn-icon">' + iconSvg + '</span>' +
      escapeHtml(btn.text) +
    '</button>';
  }).join('');

  container.innerHTML =
    '<div class="ele-home">' +
      '<p class="ele-home-greeting">' + escapeHtml(greeting) + '</p>' +
      '<div class="ele-home-input-wrap">' +
        '<textarea class="ele-home-input" placeholder="Escribí tu mensaje…" rows="1" enterkeyhint="send"></textarea>' +
        '<button type="button" class="ele-home-send" aria-label="Enviar">' +
          '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg>' +
        '</button>' +
      '</div>' +
      '<div class="ele-home-buttons">' + buttonsHtml + '</div>' +
      '<p class="ele-home-footer">Powered by PIA · soypia.com</p>' +
    '</div>';

  var input   = container.querySelector('.ele-home-input');
  var sendBtn = container.querySelector('.ele-home-send');

  input.addEventListener('keydown', function (e) {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      var text = input.value.trim();
      if (text) sendFromHome(text);
    }
  });
  input.addEventListener('input', function () { autoResize(input); });

  sendBtn.addEventListener('click', function (e) {
    e.preventDefault();
    var text = input.value.trim();
    if (text) sendFromHome(text);
  });

  container.querySelectorAll('.ele-home-btn').forEach(function (btn) {
    btn.addEventListener('click', function (e) {
      e.preventDefault();
      var action = btn.dataset.action;
      var text   = btn.dataset.text;
      if (action === 'chat')          sendFromHome(text);
      else if (action === 'booking')  openBooking();
      else if (action === 'whatsapp') window.open(WA_URL, '_blank');
    });
  });

  container.querySelectorAll('.ele-home-link').forEach(function (link) {
    link.addEventListener('click', function (e) {
      e.preventDefault();
      openBooking();
    });
  });
}

function sendFromHome(text) {
  STATE.messages.push({ role: 'user', content: text });
  saveMessages();
  setState({ view: 'chat' });
  sendToBackend(text);
}

// ============================================
// SECCIÓN 5: CHAT
// ============================================

var _hasMic = !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia && window.MediaRecorder);

function renderChat(container) {
  var micBtn =
    '<button type="button" class="ele-mic-btn" aria-label="Grabar audio" style="display:flex;align-items:center;justify-content:center;width:36px;height:36px;flex-shrink:0;border-radius:50%;background:none;border:1px solid #E3E5EC;color:#7A7D8A;cursor:pointer;padding:0;box-sizing:border-box;">' +
      '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg>' +
    '</button>';

  container.innerHTML =
    '<div class="ele-chat">' +
      '<div class="ele-booking-bar">' +
        '<a class="ele-booking-bar-btn" href="' + escapeAttr(CONFIG.BOOKING_URL) + '" target="_blank" rel="noopener noreferrer">Agendar llamada →</a>' +
      '</div>' +
      '<div class="ele-messages" id="ele-messages"></div>' +
      '<div class="ele-composer" id="ele-composer">' +
        micBtn +
        '<button type="button" class="ele-clip-btn" style="display:none;" aria-hidden="true" tabindex="-1" disabled></button>' +
        '<textarea class="ele-composer-input" placeholder="Escribí tu mensaje…" rows="1" enterkeyhint="send"></textarea>' +
        '<button type="button" class="ele-composer-send" aria-label="Enviar">' +
          '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg>' +
        '</button>' +
      '</div>' +
    '</div>';

  renderMessages();
  setupComposerHandlers(container);
  setupMicButton(container);
}

function renderMessages() {
  var messagesDiv = document.getElementById('ele-messages');
  if (!messagesDiv) return;

  var domMsgs   = messagesDiv.querySelectorAll('.ele-msg:not(.ele-typing-row)');
  var domCount  = domMsgs.length;
  var stateCount = STATE.messages.length;

  if (domCount > stateCount) {
    messagesDiv.innerHTML = '';
    domCount = 0;
    domMsgs  = [];
  }

  var lastRole = '';
  if (domCount > 0) {
    lastRole = domMsgs[domCount - 1].classList.contains('ele-msg-user') ? 'user' : 'assistant';
  }

  for (var i = domCount; i < stateCount; i++) {
    var msg = STATE.messages[i];
    var showAvatar = msg.role !== lastRole && msg.role === 'assistant';
    lastRole = msg.role;

    var el = document.createElement('div');
    el.className = 'ele-msg ' +
      (msg.role === 'user' ? 'ele-msg-user' : 'ele-msg-ele') +
      (i === stateCount - 1 ? ' ele-msg-new' : '');

    if (msg.role === 'user') {
      if (msg.isAudio) {
        el.innerHTML = '<div class="ele-bubble ele-bubble-user ele-bubble-audio">' + renderAudioBubble(msg.audioURL, msg.audioDuration) + '</div>';
      } else {
        el.innerHTML = '<div class="ele-bubble ele-bubble-user">' + escapeHtml(msg.content) + '</div>';
      }
    } else {
      var richHtml = '';
      if (msg.rich && Array.isArray(msg.rich)) {
        richHtml = renderRich(msg.rich);
      }
      el.innerHTML =
        (showAvatar
          ? '<div class="ele-avatar-small"><img src="https://widget.soypia.com/assets/ele-avatar.webp" alt="Ele"></div>'
          : '<div class="ele-avatar-spacer"></div>') +
        '<div class="ele-bubble ele-bubble-ele">' + linkify(escapeHtml(msg.content)) + richHtml + '</div>';
    }

    messagesDiv.appendChild(el);

    // Bind audio play buttons if any
    el.querySelectorAll('.ele-audio-play').forEach(function (btn) {
      bindAudioPlayButton(btn);
    });
    // Bind rich buttons
    el.querySelectorAll('.ele-rich-btn').forEach(function (btn) {
      btn.addEventListener('click', function () {
        var act = btn.dataset.action;
        var val = btn.dataset.value;
        if (act === 'booking') {
          openBooking();
        } else if (act === 'url' && val) {
          window.open(val, '_blank');
        } else if (act === 'chat' && val) {
          // sendMessage when already in chat to avoid re-render overhead
          if (STATE.view === 'chat') sendMessage(val);
          else sendFromHome(val);
        }
      });
    });
    // Bind rich media modal
    el.querySelectorAll('.ele-rich-media-thumb').forEach(function (thumb) {
      thumb.addEventListener('click', function () {
        openMediaModal(thumb.dataset.type, thumb.dataset.url, thumb.dataset.title || '');
      });
    });
  }

  // In-place update during streaming
  if (stateCount > 0 && domCount === stateCount) {
    var lastMsg = STATE.messages[stateCount - 1];
    if (lastMsg.role === 'assistant') {
      var lastEl = messagesDiv.querySelectorAll('.ele-msg:not(.ele-typing-row)')[stateCount - 1];
      if (lastEl) {
        var bubble = lastEl.querySelector('.ele-bubble-ele');
        if (bubble && bubble.textContent !== lastMsg.content) {
          var richHtml2 = '';
          if (lastMsg.rich && Array.isArray(lastMsg.rich)) richHtml2 = renderRich(lastMsg.rich);
          bubble.innerHTML = linkify(escapeHtml(lastMsg.content)) + richHtml2;
        }
      }
    }
  }

  // Typing indicator
  var typingRow = messagesDiv.querySelector('.ele-typing-row');
  if (STATE.isTyping) {
    var wantText = STATE.typingText || null;
    if (!typingRow) {
      var typEl = document.createElement('div');
      typEl.className = 'ele-msg ele-msg-ele ele-typing-row';
      typEl.innerHTML =
        '<div class="ele-avatar-spacer"></div>' +
        (wantText
          ? '<div class="ele-bubble ele-bubble-ele ele-typing-text">' + escapeHtml(wantText) + '</div>'
          : '<div class="ele-bubble ele-bubble-ele ele-typing"><span class="ele-dot"></span><span class="ele-dot"></span><span class="ele-dot"></span></div>');
      messagesDiv.appendChild(typEl);
    } else {
      // Update in place if mode changed (dots ↔ text)
      var bubble = typingRow.querySelector('.ele-bubble');
      var hasText = bubble && bubble.classList.contains('ele-typing-text');
      if (wantText && !hasText) {
        bubble.className = 'ele-bubble ele-bubble-ele ele-typing-text';
        bubble.innerHTML = escapeHtml(wantText);
      } else if (!wantText && hasText) {
        bubble.className = 'ele-bubble ele-bubble-ele ele-typing';
        bubble.innerHTML = '<span class="ele-dot"></span><span class="ele-dot"></span><span class="ele-dot"></span>';
      }
    }
  } else if (!STATE.isTyping && typingRow) {
    typingRow.remove();
  }

  scrollToBottom();
}

function setupComposerHandlers(container) {
  var input   = container.querySelector('.ele-composer-input');
  var sendBtn = container.querySelector('.ele-composer-send');
  if (!input || !sendBtn) return;

  function doSend() {
    var text = input.value.trim();
    if (!text || STATE.isTyping) return;
    input.value = '';
    autoResize(input);
    sendMessage(text);
  }

  input.addEventListener('keydown', function (e) {
    if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); doSend(); }
  });
  input.addEventListener('input', function () { autoResize(input); });
  sendBtn.addEventListener('click', function (e) { e.preventDefault(); doSend(); });
  setTimeout(function () { input.focus(); }, 50);
}

function sendMessage(text) {
  STATE.messages.push({ role: 'user', content: text });
  saveMessages();
  renderMessages();
  sendToBackend(text);
}

// ============================================
// SECCIÓN 6: BOOKING CON CALENDARIO
// ============================================

function openBookingIframe(url) {
  var content = document.querySelector('.ele-content');
  if (!content) { window.open(url, '_blank'); return; }

  // Show iframe view inside .ele-content
  content.innerHTML =
    '<div class="ele-iframe-wrap">' +
      '<div class="ele-iframe-header">' +
        '<button class="ele-iframe-back" aria-label="Volver al chat">' +
          '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="15 18 9 12 15 6"/></svg>' +
          ' Volver al chat' +
        '</button>' +
      '</div>' +
      '<iframe class="ele-booking-iframe" src="' + escapeAttr(url) + '" allow="payment" title="Calendario de reservas"></iframe>' +
      '<div class="ele-iframe-fallback" style="display:none;">' +
        '<p>No pude abrir el calendario acá.</p>' +
        '<a class="ele-iframe-open-btn" href="' + escapeAttr(url) + '" target="_blank" rel="noopener">Abrir en nueva pestaña →</a>' +
      '</div>' +
    '</div>';

  var iframe   = content.querySelector('.ele-booking-iframe');
  var fallback = content.querySelector('.ele-iframe-fallback');
  var backBtn  = content.querySelector('.ele-iframe-back');

  // Detect X-Frame-Options block: if load fires we're fine;
  // if it never fires within 3s, show fallback.
  var loaded = false;
  var timer = setTimeout(function () {
    if (!loaded) {
      iframe.style.display = 'none';
      fallback.style.display = 'flex';
    }
  }, 3000);

  iframe.addEventListener('load', function () {
    loaded = true;
    clearTimeout(timer);
  });

  backBtn.addEventListener('click', function () {
    clearTimeout(timer);
    // Return to chat view
    setState({ view: 'chat' });
  });
}

function openBooking() {
  window.open(CONFIG.BOOKING_URL, '_blank', 'noopener,noreferrer');
}

function renderBooking(container) {
  container.innerHTML =
    '<div class="ele-booking-wrap">' +
      '<div class="ele-booking-header">' +
        '<button class="ele-booking-iframe-try ele-btn-link" id="ele-try-iframe">Abrir en nueva pestaña →</button>' +
        '<p class="ele-booking-subtitle">O elegí un horario acá:</p>' +
      '</div>' +
      '<div id="ele-calendar-wrap"></div>' +
      '<div class="ele-slot-wrap">' +
        '<button class="ele-slot-btn' + (STATE.bookingSlot === '9-12' ? ' is-selected' : '') + '" data-slot="9-12">9:00 – 12:00</button>' +
        '<button class="ele-slot-btn' + (STATE.bookingSlot === '14-17' ? ' is-selected' : '') + '" data-slot="14-17">14:00 – 17:00</button>' +
      '</div>' +
      '<button class="ele-booking-confirm" id="ele-booking-confirm"' + (STATE.bookingDay && STATE.bookingSlot ? '' : ' disabled') + '>Confirmar</button>' +
      '<p class="ele-booking-footer">Powered by PIA · soypia.com</p>' +
    '</div>';

  renderCalendar(container.querySelector('#ele-calendar-wrap'));

  // Nav prev/next
  container.addEventListener('click', function (e) {
    if (e.target.closest('#ele-cal-prev')) { navigateMonth(-1); return; }
    if (e.target.closest('#ele-cal-next')) { navigateMonth(1);  return; }

    // Day selection
    var dayEl = e.target.closest('.ele-cal-day:not(.ele-cal-day--disabled)');
    if (dayEl && dayEl.dataset.day) {
      STATE.bookingDay = parseInt(dayEl.dataset.day, 10);
      updateBookingUI(container);
      return;
    }

    // Slot selection
    var slotBtn = e.target.closest('.ele-slot-btn');
    if (slotBtn) {
      STATE.bookingSlot = slotBtn.dataset.slot;
      container.querySelectorAll('.ele-slot-btn').forEach(function (b) {
        b.classList.toggle('is-selected', b.dataset.slot === STATE.bookingSlot);
      });
      updateBookingConfirmBtn(container);
      return;
    }

    // Confirm
    if (e.target.closest('#ele-booking-confirm') && STATE.bookingDay && STATE.bookingSlot) {
      confirmBooking();
      return;
    }

    // Iframe link
    if (e.target.closest('#ele-try-iframe')) {
      window.open(CONFIG.BOOKING_URL, '_blank');
      return;
    }
  });
}

function renderCalendar(wrap) {
  if (!wrap) return;
  var d    = STATE.bookingDate;
  var year = d.year, month = d.month;

  var now  = new Date();
  var today = { y: now.getFullYear(), m: now.getMonth(), d: now.getDate() };

  var DAYS = ['Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sá', 'Do'];
  var MONTHS = ['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'];

  var firstDay = new Date(year, month, 1).getDay(); // 0=Sun
  // Adjust so Monday is first
  firstDay = (firstDay + 6) % 7;

  var daysInMonth = new Date(year, month + 1, 0).getDate();

  var isPrevDisabled = (year < today.y) || (year === today.y && month <= today.m);

  var headerHtml =
    '<div class="ele-cal-nav">' +
      '<button class="ele-cal-arrow' + (isPrevDisabled ? ' ele-cal-arrow--disabled' : '') + '" id="ele-cal-prev">' +
        '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="15 18 9 12 15 6"/></svg>' +
      '</button>' +
      '<span class="ele-cal-title">' + MONTHS[month] + ' ' + year + '</span>' +
      '<button class="ele-cal-arrow" id="ele-cal-next">' +
        '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="9 18 15 12 9 6"/></svg>' +
      '</button>' +
    '</div>';

  var daysHeaderHtml = '<div class="ele-cal-grid">' + DAYS.map(function (d) {
    return '<div class="ele-cal-header-day">' + d + '</div>';
  }).join('') + '';

  // Empty cells
  for (var e = 0; e < firstDay; e++) {
    daysHeaderHtml += '<div class="ele-cal-day ele-cal-day--empty"></div>';
  }

  for (var day = 1; day <= daysInMonth; day++) {
    var dow = (firstDay + day - 1) % 7; // 0=Mon, 5=Sat, 6=Sun
    var isWeekend = dow >= 5;
    var isPast = (year === today.y && month === today.m && day < today.d) ||
                 (year < today.y) || (year === today.y && month < today.m);
    var isToday = year === today.y && month === today.m && day === today.d;
    var isSelected = STATE.bookingDay === day;
    var isDisabled = isWeekend || isPast;

    var cls = 'ele-cal-day' +
      (isDisabled ? ' ele-cal-day--disabled' : '') +
      (isToday && !isDisabled ? ' ele-cal-day--today' : '') +
      (isSelected && !isDisabled ? ' ele-cal-day--selected' : '');

    daysHeaderHtml += '<div class="' + cls + '"' + (!isDisabled ? ' data-day="' + day + '"' : '') + '>' + day + '</div>';
  }

  daysHeaderHtml += '</div>';

  wrap.innerHTML = headerHtml + daysHeaderHtml;
}

function navigateMonth(delta) {
  var d = STATE.bookingDate;
  var m = d.month + delta;
  var y = d.year;
  if (m < 0)  { m = 11; y--; }
  if (m > 11) { m = 0;  y++; }
  STATE.bookingDate = { year: y, month: m };
  STATE.bookingDay  = null;
  var wrap = document.querySelector('#ele-calendar-wrap');
  if (wrap) renderCalendar(wrap);
  var confirm = document.getElementById('ele-booking-confirm');
  if (confirm) confirm.disabled = true;
}

function updateBookingUI(container) {
  renderCalendar(container.querySelector('#ele-calendar-wrap'));
  updateBookingConfirmBtn(container);
}

function updateBookingConfirmBtn(container) {
  var btn = container.querySelector('#ele-booking-confirm');
  if (btn) btn.disabled = !(STATE.bookingDay && STATE.bookingSlot);
}

function confirmBooking() {
  var d     = STATE.bookingDate;
  var MONTHS_FULL = ['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre'];
  var slotText = STATE.bookingSlot === '9-12' ? '9:00 a 12:00' : '14:00 a 17:00';
  var text  = 'Quiero agendar una llamada para el ' + STATE.bookingDay + ' de ' + MONTHS_FULL[d.month] + ' de ' + d.year + ', en el horario de ' + slotText + '.';
  STATE.messages.push({ role: 'user', content: text });
  saveMessages();
  setState({ view: 'chat', bookingDay: null, bookingSlot: null });
  sendToBackend(text);
}

// ============================================
// SECCIÓN 7: AUDIO INPUT
// ============================================

function setupMicButton(container) {
  var micBtn = container.querySelector('.ele-mic-btn');
  if (!micBtn) return;
  micBtn.addEventListener('click', function () {
    var hasMic = !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia && window.MediaRecorder);
    if (!hasMic) { showMicTooltip(container, TEXTS.mic_no_support); return; }
    if (STATE.audioMode === null) startRecording(container);
  });
}

function startRecording(container) {
  navigator.mediaDevices.getUserMedia({ audio: true }).then(function (stream) {
    STATE._audioStream = stream;

    // Detect best supported mimeType
    var mimeType = '';
    if (MediaRecorder.isTypeSupported('audio/webm'))  mimeType = 'audio/webm';
    else if (MediaRecorder.isTypeSupported('audio/mp4'))  mimeType = 'audio/mp4';
    else if (MediaRecorder.isTypeSupported('audio/ogg'))  mimeType = 'audio/ogg';
    var recOpts = mimeType ? { mimeType: mimeType } : {};
    var recorder = new MediaRecorder(stream, recOpts);
    if (!mimeType) mimeType = recorder.mimeType || 'audio/webm';

    STATE._audioChunks   = [];
    STATE._mediaRecorder = recorder;
    STATE._mimeType      = mimeType;
    STATE.audioSeconds   = 0;

    recorder.ondataavailable = function (e) {
      if (e.data.size > 0) STATE._audioChunks.push(e.data);
    };

    recorder.onstop = function () {
      stream.getTracks().forEach(function (t) { t.stop(); });
      clearInterval(STATE._audioTimer);
      stopWaveform();
      if (STATE._audioCtx) { try { STATE._audioCtx.close(); } catch (e) {} STATE._audioCtx = null; }
      // Only send if not cancelled (onstop = null when cancelled)
      var blob = new Blob(STATE._audioChunks, { type: mimeType });
      var url  = URL.createObjectURL(blob);
      STATE.audioMode = null;
      sendAudio(blob, url, STATE.audioSeconds, mimeType, container);
    };

    recorder.start(100);

    STATE._audioTimer = setInterval(function () {
      STATE.audioSeconds++;
      updateRecordingTimer();
      if (STATE.audioSeconds >= 120) stopAndSend(container);
    }, 1000);

    setState({ audioMode: 'recording' });
    showRecordingUI(container);

  }).catch(function () {
    showMicTooltip(container, TEXTS.mic_permission);
  });
}

function stopRecording() {
  if (STATE._mediaRecorder && STATE._mediaRecorder.state !== 'inactive') {
    STATE._mediaRecorder.stop();
  }
  clearInterval(STATE._audioTimer);
}

function cancelRecording(container) {
  // Detach onstop so it doesn't call sendAudio
  if (STATE._mediaRecorder) STATE._mediaRecorder.onstop = null;
  stopRecording();
  if (STATE._audioStream) {
    STATE._audioStream.getTracks().forEach(function (t) { t.stop(); });
    STATE._audioStream = null;
  }
  stopWaveform();
  if (STATE._audioCtx) { try { STATE._audioCtx.close(); } catch (e) {} STATE._audioCtx = null; }
  STATE.audioMode     = null;
  STATE.audioBlob     = null;
  STATE.audioURL      = null;
  STATE.audioSeconds  = 0;
  STATE._mediaRecorder = null;
  STATE._audioChunks   = [];
  // Restore normal composer
  var content = container ? container.closest('.ele-content') : document.querySelector('.ele-content');
  if (content) renderChat(content);
}

function stopAndSend(container) {
  stopWaveform();
  stopRecording(); // triggers recorder.onstop → sendAudio
  // container reference passed via closure in onstop? No — we pass container to sendAudio via a module-level var
  STATE._sendContainer = container;
}

function showRecordingUI(container) {
  var composer = container.querySelector('#ele-composer');
  if (!composer) return;
  composer.style.transition = 'all 0.2s ease-out';
  composer.innerHTML =
    '<div class="ele-rec-mode" id="ele-rec-mode">' +
      '<button class="ele-rec-cancel" aria-label="Cancelar grabación">' +
        '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>' +
      '</button>' +
      '<div class="ele-rec-wave" id="ele-rec-wave">' +
        '<span class="ele-rec-bar"></span>' +
        '<span class="ele-rec-bar"></span>' +
        '<span class="ele-rec-bar"></span>' +
        '<span class="ele-rec-bar"></span>' +
        '<span class="ele-rec-bar"></span>' +
      '</div>' +
      '<span class="ele-rec-timer" id="ele-rec-timer">0:00</span>' +
      '<button class="ele-rec-send" aria-label="Enviar audio">' +
        '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg>' +
      '</button>' +
    '</div>';

  composer.querySelector('.ele-rec-cancel').addEventListener('click', function () {
    cancelRecording(container);
  });
  composer.querySelector('.ele-rec-send').addEventListener('click', function () {
    stopAndSend(container);
  });

  startWaveform();
}

function startWaveform() {
  var waveEl = document.getElementById('ele-rec-wave');
  if (!waveEl) return;
  var bars = waveEl.querySelectorAll('.ele-rec-bar');
  if (!bars.length) return;

  // Try AnalyserNode for real volume
  if (STATE._audioStream && (window.AudioContext || window.webkitAudioContext)) {
    try {
      var AudioCtx = window.AudioContext || window.webkitAudioContext;
      var ctx = new AudioCtx();
      var src = ctx.createMediaStreamSource(STATE._audioStream);
      var analyser = ctx.createAnalyser();
      analyser.fftSize = 32;
      src.connect(analyser);
      STATE._audioCtx = ctx;
      var dataArray = new Uint8Array(analyser.frequencyBinCount);

      function drawFrame() {
        if (STATE.audioMode !== 'recording') return;
        analyser.getByteFrequencyData(dataArray);
        for (var i = 0; i < bars.length; i++) {
          var idx   = Math.floor((i / bars.length) * dataArray.length);
          var value = dataArray[idx] / 255;
          bars[i].style.height = Math.max(4, Math.round(value * 20)) + 'px';
        }
        STATE._waveAnimId = requestAnimationFrame(drawFrame);
      }
      drawFrame();
      return;
    } catch (e) { /* fall through to CSS fallback */ }
  }

  // CSS fallback: random heights every 150ms
  function animateBars() {
    if (STATE.audioMode !== 'recording') return;
    for (var j = 0; j < bars.length; j++) {
      bars[j].style.height = (4 + Math.random() * 16).toFixed(0) + 'px';
    }
    STATE._waveAnimId = setTimeout(animateBars, 150);
  }
  animateBars();
}

function stopWaveform() {
  if (STATE._waveAnimId) {
    cancelAnimationFrame(STATE._waveAnimId);
    clearTimeout(STATE._waveAnimId);
    STATE._waveAnimId = null;
  }
}

function updateRecordingTimer() {
  var el = document.getElementById('ele-rec-timer');
  if (!el) return;
  var s = STATE.audioSeconds;
  el.textContent = Math.floor(s / 60) + ':' + (s % 60 < 10 ? '0' : '') + (s % 60);
  if (s >= 110) el.classList.add('ele-rec-timer--warning');
}

function showMicTooltip(container, message) {
  var micBtn = container.querySelector('.ele-mic-btn');
  if (!micBtn) return;
  var tip = document.createElement('div');
  tip.className = 'ele-mic-tooltip';
  tip.textContent = message || TEXTS.mic_permission;
  // Force visible (don't rely on :hover — works on mobile too)
  tip.style.opacity   = '1';
  tip.style.transform = 'translateY(0)';
  micBtn.style.position = 'relative';
  micBtn.appendChild(tip);
  setTimeout(function () { tip.remove(); }, 3000);
}

function sendAudio(blob, url, duration, mimeType, container) {
  // Resolve container: passed directly or stored from stopAndSend
  var cnt = container || STATE._sendContainer || null;
  STATE._sendContainer = null;

  // Restore normal composer immediately
  if (cnt) {
    var content = cnt.closest('.ele-content');
    if (content) renderChat(content);
  }

  var durText = Math.floor(duration / 60) + ':' + (duration % 60 < 10 ? '0' : '') + (duration % 60);
  STATE.messages.push({ role: 'user', content: '[Audio]', isAudio: true, audioURL: url, audioDuration: durText });
  saveMessages();
  setState({ view: 'chat' });
  renderMessages();

  STATE.isTyping   = true;
  STATE.typingText = TEXTS.audio_processing;
  renderMessages();

  var ext = mimeType && mimeType.indexOf('mp4') > -1 ? 'audio.mp4'
          : mimeType && mimeType.indexOf('ogg') > -1 ? 'audio.ogg'
          : 'audio.webm';

  function attempt(retry) {
    var formData = new FormData();
    formData.append('audio', blob, ext);
    if (STATE.sessionId) formData.append('session_id', STATE.sessionId);
    formData.append('channel', 'web');

    fetch(CONFIG.API_URL, { method: 'POST', body: formData })
      .then(function (res) { return res.json(); })
      .then(function (data) {
        STATE.isTyping   = false;
        STATE.typingText = null;
        if (data.session_id && !STATE.sessionId) {
          STATE.sessionId = data.session_id;
          sessionStorage.setItem(CONFIG.SESSION_KEY, data.session_id);
        }
        var reply = data.reply || data.message || TEXTS.audio_fail;
        STATE.messages.push({ role: 'assistant', content: '', rich: Array.isArray(data.rich) ? data.rich : null });
        saveMessages();
        renderMessages();
        simulateStreaming(reply);
        playReceiveSound();
      })
      .catch(function () {
        if (retry < 2) {
          setTimeout(function () { attempt(retry + 1); }, 2000);
          return;
        }
        STATE.isTyping   = false;
        STATE.typingText = null;
        renderMessages();
        // Show inline retry on the audio bubble
        var bubbles = document.querySelectorAll('.ele-msg-user .ele-audio-bubble');
        var lastBubble = bubbles.length ? bubbles[bubbles.length - 1] : null;
        if (lastBubble && !lastBubble.querySelector('.ele-audio-error')) {
          var errEl = document.createElement('div');
          errEl.className = 'ele-audio-error';
          errEl.textContent = TEXTS.audio_send_error;
          lastBubble.appendChild(errEl);
          errEl.addEventListener('click', function () {
            errEl.remove();
            STATE.isTyping   = true;
            STATE.typingText = TEXTS.audio_processing;
            renderMessages();
            attempt(0);
          });
        }
      });
  }
  attempt(0);
}

function renderAudioBubble(url, durText) {
  return '<div class="ele-audio-bubble">' +
    '<button class="ele-audio-play" data-url="' + escapeAttr(url || '') + '" aria-label="Reproducir">' +
      '<svg class="ico-play" width="10" height="10" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>' +
      '<svg class="ico-pause" width="10" height="10" viewBox="0 0 24 24" fill="currentColor" style="display:none"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg>' +
    '</button>' +
    '<div class="ele-audio-progress-wrap">' +
      '<div class="ele-audio-progress-bar"><div class="ele-audio-progress-fill"></div></div>' +
      '<span class="ele-audio-time">' + (durText || '0:00') + '</span>' +
    '</div>' +
  '</div>';
}

function bindAudioPlayButton(btn) {
  if (!btn || btn.dataset.bound) return;
  btn.dataset.bound = '1';
  var url = btn.dataset.url;
  if (!url) return;
  var audio     = new Audio(url);
  var bubble    = btn.closest('.ele-audio-bubble');
  var fill      = bubble ? bubble.querySelector('.ele-audio-progress-fill') : null;
  var timeEl    = bubble ? bubble.querySelector('.ele-audio-time') : null;
  var iconPlay  = btn.querySelector('.ico-play');
  var iconPause = btn.querySelector('.ico-pause');
  var totalDur  = timeEl ? timeEl.textContent : '0:00';

  function fmt(s) {
    s = Math.floor(s || 0);
    return Math.floor(s / 60) + ':' + (s % 60 < 10 ? '0' : '') + (s % 60);
  }

  audio.addEventListener('timeupdate', function () {
    var pct = audio.duration ? (audio.currentTime / audio.duration) * 100 : 0;
    if (fill)   fill.style.width = pct + '%';
    if (timeEl) timeEl.textContent = fmt(audio.currentTime) + ' / ' + totalDur;
  });

  audio.addEventListener('ended', function () {
    if (iconPlay)  iconPlay.style.display  = '';
    if (iconPause) iconPause.style.display = 'none';
    if (fill)   fill.style.width = '0%';
    if (timeEl) timeEl.textContent = totalDur;
  });

  btn.addEventListener('click', function () {
    if (audio.paused) {
      audio.play();
      if (iconPlay)  iconPlay.style.display  = 'none';
      if (iconPause) iconPause.style.display = '';
    } else {
      audio.pause();
      if (iconPlay)  iconPlay.style.display  = '';
      if (iconPause) iconPause.style.display = 'none';
    }
  });
}

// ============================================
// SECCIÓN 8: RICH MEDIA
// ============================================

function renderRich(items) {
  if (!items || !items.length) return '';
  return items.map(function (item) {
    if (item.type === 'video') {
      return '<div class="ele-rich-media ele-rich-video ele-rich-media-thumb" data-type="video" data-url="' + escapeAttr(item.url) + '" data-title="' + escapeAttr(item.title || '') + '">' +
        (item.thumbnail ? '<img src="' + escapeAttr(item.thumbnail) + '" alt="' + escapeAttr(item.title || 'Video') + '">' : '') +
        '<div class="ele-rich-play-overlay"><svg width="28" height="28" viewBox="0 0 24 24" fill="white"><polygon points="5 3 19 12 5 21 5 3"/></svg></div>' +
        (item.title ? '<p class="ele-rich-caption">' + escapeHtml(item.title) + '</p>' : '') +
      '</div>';
    }
    if (item.type === 'image') {
      return '<div class="ele-rich-media ele-rich-media-thumb" data-type="image" data-url="' + escapeAttr(item.url) + '">' +
        '<img src="' + escapeAttr(item.url) + '" alt="' + escapeAttr(item.alt || 'Imagen') + '">' +
      '</div>';
    }
    if (item.type === 'buttons') {
      var MAX_SLOTS = 4;
      var allItems  = item.items || [];
      var visible   = allItems.slice(0, MAX_SLOTS);
      var hasMore   = allItems.length > MAX_SLOTS;
      var btns = visible.map(function (b) {
        if (b.action === 'url' && (b.url || b.value)) {
          return '<a class="ele-rich-btn" href="' + escapeAttr(b.url || b.value) + '" target="_blank" rel="noopener noreferrer" style="text-align:center;text-decoration:none;display:block;">' + escapeHtml(b.text) + '</a>';
        }
        return '<button class="ele-rich-btn" data-action="' + escapeAttr(b.action) + '" data-value="' + escapeAttr(b.url || b.text || '') + '">' + escapeHtml(b.text) + '</button>';
      }).join('');
      if (hasMore) {
        btns += '<button class="ele-rich-btn ele-rich-btn--more" data-action="chat" data-value="Ver más horarios">Ver más horarios →</button>';
      }
      return '<div class="ele-rich-btns">' + btns + '</div>';
    }
    if (item.type === 'card') {
      return '<div class="ele-rich-card">' +
        '<p class="ele-rich-card-title">' + escapeHtml(item.title || '') + '</p>' +
        (item.description ? '<p class="ele-rich-card-desc">' + escapeHtml(item.description) + '</p>' : '') +
        (item.action ? '<a href="' + escapeAttr(item.action.url) + '" target="_blank" rel="noopener" class="ele-rich-card-link">' + escapeHtml(item.action.text) + ' →</a>' : '') +
      '</div>';
    }
    return '';
  }).join('');
}

function openMediaModal(type, url, title) {
  var existing = document.getElementById('ele-media-modal');
  if (existing) existing.remove();

  var modal = document.createElement('div');
  modal.id = 'ele-media-modal';
  modal.className = 'ele-media-modal';

  var inner = '';
  if (type === 'video') {
    // Convert YouTube URL to embed if needed
    var embedUrl = url.replace('watch?v=', 'embed/').replace('youtu.be/', 'www.youtube.com/embed/');
    inner = '<iframe src="' + escapeAttr(embedUrl) + '" allowfullscreen class="ele-media-iframe"></iframe>';
  } else {
    inner = '<img src="' + escapeAttr(url) + '" alt="' + escapeAttr(title) + '" class="ele-media-img">';
  }

  modal.innerHTML =
    '<div class="ele-media-overlay"></div>' +
    '<div class="ele-media-box">' +
      inner +
      '<button class="ele-media-close" aria-label="Cerrar">' +
        '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>' +
      '</button>' +
    '</div>';

  document.body.appendChild(modal);
  requestAnimationFrame(function () { modal.classList.add('is-open'); });

  function closeModal() { modal.classList.remove('is-open'); setTimeout(function () { modal.remove(); }, 300); }
  modal.querySelector('.ele-media-overlay').addEventListener('click', closeModal);
  modal.querySelector('.ele-media-close').addEventListener('click', closeModal);
}

// ============================================
// SECCIÓN 9: COMPARTIR
// ============================================

function toggleShareDropdown(btn) {
  var dd = document.getElementById('ele-share-dropdown');
  if (dd) { dd.remove(); STATE.shareOpen = false; return; }

  STATE.shareOpen = true;
  var drop = document.createElement('div');
  drop.id = 'ele-share-dropdown';
  drop.className = 'ele-share-dropdown';
  drop.innerHTML =
    '<button class="ele-share-opt" id="ele-share-copy">Copiar como texto</button>' +
    '<button class="ele-share-opt" id="ele-share-download">Descargar conversación</button>';

  // Append to body with fixed position to escape overflow:hidden of .ele-panel
  var rect = btn.getBoundingClientRect();
  drop.style.position = 'fixed';
  drop.style.top      = (rect.bottom + 8) + 'px';
  drop.style.right    = (window.innerWidth - rect.right) + 'px';
  drop.style.zIndex   = '10001';
  document.body.appendChild(drop);

  document.getElementById('ele-share-copy').addEventListener('click', function (e) {
    e.stopPropagation();
    copyConversation(btn);
    drop.remove(); STATE.shareOpen = false;
  });
  document.getElementById('ele-share-download').addEventListener('click', function (e) {
    e.stopPropagation();
    downloadConversation();
    drop.remove(); STATE.shareOpen = false;
  });

  setTimeout(function () {
    document.addEventListener('click', function handler() {
      var d = document.getElementById('ele-share-dropdown');
      if (d) d.remove();
      STATE.shareOpen = false;
      document.removeEventListener('click', handler);
    }, { once: true });
  }, 10);
}

function buildConversationText() {
  var now = new Date();
  var dateStr = now.toLocaleDateString('es', { day: 'numeric', month: 'long', year: 'numeric' });
  var lines = ['Conversación con Ele · PIA', dateStr, '', ''];
  STATE.messages.forEach(function (msg) {
    if (msg.isAudio) { lines.push('Yo: [Audio]'); return; }
    if (msg.role === 'user') lines.push('Yo: ' + msg.content);
    else lines.push('Ele: ' + msg.content);
    lines.push('');
  });
  lines.push('---', 'soypia.com');
  return lines.join('\n');
}

function copyConversation(btn) {
  var text = buildConversationText();
  if (navigator.clipboard && navigator.clipboard.writeText) {
    navigator.clipboard.writeText(text).then(function () {
      showShareFeedback(btn, 'Copiado ✓');
    }).catch(function () { fallbackCopy(text); });
  } else {
    fallbackCopy(text);
  }
}

function fallbackCopy(text) {
  var ta = document.createElement('textarea');
  ta.value = text;
  ta.style.position = 'fixed'; ta.style.opacity = '0';
  document.body.appendChild(ta);
  ta.select();
  try { document.execCommand('copy'); } catch (e) {}
  document.body.removeChild(ta);
}

function showShareFeedback(btn, msg) {
  var orig = btn.innerHTML;
  btn.innerHTML = '<span style="font-size:11px;color:#00D6C5;white-space:nowrap;">' + msg + '</span>';
  setTimeout(function () { btn.innerHTML = orig; }, 2000);
}

function downloadConversation() {
  var text = buildConversationText();
  var blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
  var url  = URL.createObjectURL(blob);
  var a    = document.createElement('a');
  var now  = new Date();
  var dateSlug = now.getFullYear() + '-' + (now.getMonth()+1) + '-' + now.getDate();
  a.href     = url;
  a.download = 'conversacion-pia-' + dateSlug + '.txt';
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(url);
}

// ============================================
// SECCIÓN 10: SONIDO
// ============================================

function playReceiveSound() {
  if (STATE.view !== 'chat') return;
  try {
    var ctx  = new (window.AudioContext || window.webkitAudioContext)();
    var osc  = ctx.createOscillator();
    var gain = ctx.createGain();
    osc.connect(gain);
    gain.connect(ctx.destination);
    osc.frequency.value = 600;
    osc.type = 'sine';
    gain.gain.setValueAtTime(0, ctx.currentTime);
    gain.gain.linearRampToValueAtTime(0.06, ctx.currentTime + 0.02);
    gain.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.1);
    osc.start(ctx.currentTime);
    osc.stop(ctx.currentTime + 0.12);
  } catch (e) {}
}

// ============================================
// SECCIÓN 11: API
// ============================================

async function sendToBackend(text) {
  STATE.isTyping = true;
  renderMessages();

  const TIMEOUT_MS = 25000;
  var waitingMsgIdx = -1; // index of interim "Dame un momento" message

  async function attempt(tryNum) {
    const controller = new AbortController();
    const timeoutId  = setTimeout(function () { controller.abort(); }, TIMEOUT_MS);
    try {
      const res = await fetch(CONFIG.API_URL, {
        method:  'POST',
        signal:  controller.signal,
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          message:       text,
          session_id:    STATE.sessionId || undefined,
          retry_attempt: tryNum,
        }),
      });
      clearTimeout(timeoutId);

      const data = await res.json();

      if (data.session_id && !STATE.sessionId) {
        STATE.sessionId = data.session_id;
        sessionStorage.setItem(CONFIG.SESSION_KEY, data.session_id);
      }

      // Remove interim waiting message if present
      if (waitingMsgIdx > -1) {
        STATE.messages.splice(waitingMsgIdx, 1);
        waitingMsgIdx = -1;
      }

      const reply = data.reply || data.message || 'Disculpá, no pude procesar eso. Podés intentar de nuevo?';
      const rich  = Array.isArray(data.rich) ? data.rich : null;
      const delay = calculateDelay(reply);
      await wait(delay);

      STATE.isTyping = false;
      STATE.messages.push({ role: 'assistant', content: '', rich: rich });
      saveMessages();
      renderMessages();
      await simulateStreaming(reply);
      playReceiveSound();

    } catch (err) {
      clearTimeout(timeoutId);
      console.warn('[Ele] intento ' + tryNum + ' fallido:', err.name);

      if (tryNum === 1) {
        // Intento 1 falló: esperar 2s y reintentar silenciosamente
        await wait(2000);
        await attempt(2);

      } else if (tryNum === 2) {
        // Intento 2 falló: mostrar mensaje interim y reintentar
        waitingMsgIdx = STATE.messages.length;
        STATE.messages.push({ role: 'assistant', content: 'Dame un momento, estoy procesando.' });
        saveMessages();
        renderMessages();
        await wait(3000);
        // Remove interim message before attempt 3
        if (waitingMsgIdx > -1) {
          STATE.messages.splice(waitingMsgIdx, 1);
          waitingMsgIdx = -1;
        }
        await attempt(3);

      } else {
        // Intento 3 falló: error final
        STATE.isTyping = false;
        STATE.messages.push({
          role: 'assistant',
          content: 'Estoy teniendo dificultades. Podés intentar de nuevo en unos segundos o escribir directo a Walter: wa.me/50664837800',
        });
        saveMessages();
        renderMessages();
      }
    }
  }

  await attempt(1);
}

async function simulateStreaming(text) {
  const words   = text.split(/\s+/).filter(Boolean);
  const lastMsg = STATE.messages[STATE.messages.length - 1];
  for (let i = 0; i < words.length; i++) {
    lastMsg.content += (i > 0 ? ' ' : '') + words[i];
    renderMessages();
    await wait(CONFIG.STREAMING_SPEED);
  }
  saveMessages();
  scrollToBottom(); // scroll final al terminar el streaming completo
}

// ============================================
// SECCIÓN 12: UTILIDADES
// ============================================

function calculateDelay(text) {
  var calculated = CONFIG.DELAY_BASE + (text.length * CONFIG.DELAY_PER_CHAR);
  var capped     = Math.min(calculated, CONFIG.DELAY_MAX);
  return Math.round(capped * (0.8 + Math.random() * 0.4));
}

function wait(ms) {
  return new Promise(function (resolve) { setTimeout(resolve, ms); });
}

function scrollToBottom() {
  var msgs = document.getElementById('ele-messages');
  if (!msgs) return;
  // Doble rAF: primer frame pinta, segundo tiene height final del contenido nuevo.
  requestAnimationFrame(function () {
    requestAnimationFrame(function () {
      msgs.scrollTop = msgs.scrollHeight;
    });
  });
}

function autoResize(ta) {
  ta.style.height = 'auto';
  ta.style.height = Math.min(ta.scrollHeight, 72) + 'px';
}

function escapeHtml(str) {
  if (str == null) return '';
  var div = document.createElement('div');
  div.textContent = String(str);
  return div.innerHTML;
}

function escapeAttr(str) {
  if (str == null) return '';
  return String(str).replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}

function linkify(html) {
  return html.replace(/(https?:\/\/[^\s<>"']+|wa\.me\/[^\s<>"']+)/g, function (url) {
    return '<a href="' + url + '" target="_blank" rel="noopener noreferrer">' + url + '</a>';
  });
}

// ============================================
// SECCIÓN 13: SECTION OBSERVER
// ============================================

function setupSectionObserver() {
  if (!('IntersectionObserver' in window)) return;
  var sectionSelectors = {
    hero: '.hero, #hero, [data-section="hero"]',
    tp:   '.tp-section, #triple-payment, [data-section="tp"]',
    s3:   '.s3-section, #como-opera, [data-section="s3"]',
    faq:  '.faq-section, #faq, [data-section="faq"]',
    cta:  '.cta-section, #s6-cta, #cta-final, [data-section="cta"]',
  };
  var sectionEls = {};
  Object.keys(sectionSelectors).forEach(function (key) {
    var el = document.querySelector(sectionSelectors[key]);
    if (el) sectionEls[key] = el;
  });
  var obs = new IntersectionObserver(function (entries) {
    entries.forEach(function (entry) {
      if (!entry.isIntersecting || STATE.greetingFrozen) return;
      var sectionKey = Object.keys(sectionEls).find(function (k) { return sectionEls[k] === entry.target; });
      if (sectionKey && sectionKey !== STATE.section) {
        STATE.section = sectionKey;
        if (STATE.view === 'closed') updateGreetingPopup();
      }
    });
  }, { threshold: 0.3 });
  Object.values(sectionEls).forEach(function (el) { obs.observe(el); });
}

// ============================================
// SECCIÓN 14: GREETING PROACTIVO
// ============================================

function scheduleGreeting() {
  if (sessionStorage.getItem(CONFIG.GREETED_KEY)) return;
  setTimeout(function () {
    if (STATE.view !== 'closed') return;
    if (sessionStorage.getItem(CONFIG.GREETED_KEY)) return;
    sessionStorage.setItem(CONFIG.GREETED_KEY, 'true');
    setState({ greetingShown: true });
  }, CONFIG.PROACTIVE_DELAY);
}

function updateGreetingPopup() {
  var popup = document.querySelector('.ele-greeting-popup');
  if (!popup) return;
  var textEl = popup.querySelector('.ele-greeting-text');
  if (textEl) textEl.textContent = GREETINGS[STATE.section] || GREETINGS.hero;
}

// ============================================
// SECCIÓN 15: KEYBOARD MOBILE
// ============================================

function setupKeyboard() {
  if (!window.visualViewport) return;
  function onViewportChange() {
    var panel = document.querySelector('.ele-panel.is-open');
    if (!panel || STATE.view === 'closed') return;
    panel.style.height = window.visualViewport.height + 'px';
    panel.style.top    = window.visualViewport.offsetTop + 'px';
    scrollToBottom();
  }
  window.visualViewport.addEventListener('resize', onViewportChange);
  window.visualViewport.addEventListener('scroll', onViewportChange);
}

// ============================================
// SECCIÓN 16: INICIALIZACIÓN
// ============================================

function initWidget() {
  // Auto-inyectar widget.css si el sitio padre no lo cargó.
  // Esto hace el widget auto-contenido: solo se necesita el <script> tag.
  var _hasCss = document.getElementById('ele-widget-css') ||
                document.querySelector('link[href*="widget.soypia.com/widget.css"]') ||
                document.querySelector('link[href*="widget.css"]');
  if (!_hasCss) {
    // Carga no bloqueante: preload → stylesheet swap.
    // El browser descarga el CSS en paralelo sin bloquear el render inicial.
    var cssLink = document.createElement('link');
    cssLink.id   = 'ele-widget-css';
    cssLink.rel  = 'preload';
    cssLink.as   = 'style';
    cssLink.href = _ELE_BASE + 'widget.css';
    cssLink.onload = function () {
      this.rel    = 'stylesheet';
      this.as     = '';
      this.onload = null;
    };
    // Fallback para browsers sin soporte de preload
    cssLink.onerror = function () {
      this.rel     = 'stylesheet';
      this.as      = '';
      this.onload  = null;
      this.onerror = null;
    };
    document.head.appendChild(cssLink);
  }

  console.info('[Ele] Widget cargado desde', _ELE_BASE);

  var root = document.createElement('div');
  root.id  = 'ele-widget-root';

  root.innerHTML =
    '<div class="ele-greeting-popup" style="display:none;">' +
      '<div class="ele-greeting-content">' +
        '<img src="https://widget.soypia.com/assets/ele-avatar.webp" alt="Ele" class="ele-greeting-avatar">' +
        '<div style="flex:1;min-width:0">' +
          '<p class="ele-greeting-name">Ele <span class="ele-greeting-badge">PIA</span></p>' +
          '<p class="ele-greeting-text">' + escapeHtml(GREETINGS.hero) + '</p>' +
        '</div>' +
        '<button type="button" class="ele-greeting-close" aria-label="Cerrar">&times;</button>' +
      '</div>' +
    '</div>' +

    '<button type="button" class="ele-fab" aria-label="Abrir chat con Ele" aria-expanded="false">' +
      '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>' +
      '<span class="ele-fab-badge" style="display:none;">1</span>' +
    '</button>' +

    '<div class="ele-panel" role="dialog" aria-label="Chat con Ele">' +
      '<div class="ele-header">' +
        '<button type="button" class="ele-back" style="display:none;" aria-label="Volver al inicio">' +
          '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>' +
        '</button>' +
        '<img src="https://widget.soypia.com/assets/ele-avatar.webp" alt="Ele" class="ele-header-avatar">' +
        '<div class="ele-header-info">' +
          '<span class="ele-header-name">Ele</span>' +
          '<span class="ele-header-status"><span class="ele-status-dot"></span> En línea</span>' +
        '</div>' +
        '<div class="ele-header-actions">' +
          '<button type="button" class="ele-share-btn" title="Compartir" aria-label="Compartir conversación" style="display:none;">' +
            '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"/><polyline points="16 6 12 2 8 6"/><line x1="12" y1="2" x2="12" y2="15"/></svg>' +
          '</button>' +
          '<button type="button" class="ele-clear-btn" title="Limpiar chat" aria-label="Limpiar conversación">' +
            '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>' +
          '</button>' +
          '<button type="button" class="ele-close-btn" title="Cerrar" aria-label="Cerrar chat">' +
            '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>' +
          '</button>' +
        '</div>' +
      '</div>' +
      '<div class="ele-content"></div>' +
    '</div>';

  document.body.appendChild(root);

  root.querySelector('.ele-fab').addEventListener('click', function (e) {
    e.preventDefault(); e.stopPropagation();
    if (STATE.view === 'closed') {
      STATE.greetingFrozen = true;
      STATE.greetingShown  = false;
      history.pushState({ widget: true }, '');
      setState({ view: STATE.messages.length > 0 ? 'chat' : 'home' });
    } else {
      setState({ view: 'closed' });
    }
  });

  root.querySelector('.ele-close-btn').addEventListener('click', function (e) {
    e.preventDefault();
    setState({ view: 'closed', greetingFrozen: false });
  });

  root.querySelector('.ele-back').addEventListener('click', function (e) {
    e.preventDefault();
    if (STATE.view === 'booking') setState({ view: 'home' });
    else setState({ view: 'home' });
  });

  root.querySelector('.ele-clear-btn').addEventListener('click', function (e) {
    e.preventDefault();
    STATE.messages  = [];
    STATE.sessionId = null;
    sessionStorage.removeItem(CONFIG.MESSAGES_KEY);
    sessionStorage.removeItem(CONFIG.SESSION_KEY);
    setState({ view: 'home' });
  });

  root.querySelector('.ele-share-btn').addEventListener('click', function (e) {
    e.stopPropagation();
    toggleShareDropdown(this);
  });

  root.querySelector('.ele-greeting-popup').addEventListener('click', function (e) {
    if (e.target.classList.contains('ele-greeting-close')) {
      setState({ greetingShown: false });
      return;
    }
    STATE.greetingFrozen = true;
    STATE.greetingShown  = false;
    history.pushState({ widget: true }, '');
    setState({ view: 'home' });
  });

  setupSectionObserver();
  setupKeyboard();
  scheduleGreeting();
  render();
}

// Auto-init
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', initWidget);
} else {
  initWidget();
}
