/* ==========================================================================
   Niwa Lead Form — Card Mode Adapter
   ---------------------------------------------------------------------------
   Renders a floating question card as the last child of the chat panel
   (.niwa-morph__chat / .niwa-center__chat). The card shows the current
   question, a progress bar, and an input area that adapts to the question
   type (text / textarea / email / phone / number / choice_single /
   choice_multi). Submission advances via LeadFormEngine.

   NAMESPACE: window.Niwa.LeadFormCardMode
   ========================================================================== */

window.Niwa = window.Niwa || {};

window.Niwa.LeadFormCardMode = (function () {
  'use strict';

  var _active = false;
  var _triggerArmed = false;
  var _triggerFired = false;
  var _consumeFirstMessageOnSend = false;
  var _cardEl = null;
  var _bodyEl = null;
  var _progressFillEl = null;
  var _questionNumberEl = null;
  var _questionLabelEl = null;
  var _inputHostEl = null;
  var _errorEl = null;
  var _originalSendMessage = null;
  var _sendHookInstalled = false;
  var _restoreOnOpen = false;

  /* -- Shortcuts ---------------------------------------------------------- */

  function _engine() { return window.Niwa && window.Niwa.LeadFormEngine; }
  function _renderer() { return window.Niwa && window.Niwa.MessageRenderer; }
  function _morph() { return window.Niwa && window.Niwa.MorphController; }
  function _chat() { return window.Niwa && window.Niwa.ChatClient; }

  function _i18n(key, fallback) {
    var lf = window.NiwaLF;
    if (lf && lf.i18n && typeof lf.i18n[key] === 'string' && lf.i18n[key] !== '') {
      return lf.i18n[key];
    }
    return fallback || '';
  }

  /* -- DOM: build the card ----------------------------------------------- */

  /**
   * Returns the chat panel (flyout body wrapper) where the card is mounted.
   * The card appends as the last child of `.niwa-morph__chat` (or center
   * equivalent). Because the chat panel fades/hides with the flyout, the
   * card auto-disappears when the morph collapses — no orphaned artifacts
   * above the pill.
   */
  function _findMountTargets() {
    var morphChat = document.querySelector('.niwa-morph .niwa-morph__chat');
    if (morphChat) return { variant: 'morph', chat: morphChat };

    var centerChat = document.querySelector('.niwa-center .niwa-center__chat');
    if (centerChat) return { variant: 'center', chat: centerChat };

    // Fallback: inline shortcode layout — mount at end of body area.
    var shortcodeBody = document.querySelector('.niwa-shortcode__body');
    if (shortcodeBody && shortcodeBody.parentNode) {
      return { variant: 'shortcode', chat: shortcodeBody.parentNode };
    }
    return null;
  }

  function _buildCard() {
    if (_cardEl) return _cardEl;
    var card = document.createElement('div');
    card.className = 'niwa-lf-card';
    card.setAttribute('data-mode', 'card');
    card.setAttribute('role', 'dialog');
    card.setAttribute('aria-live', 'polite');

    var close = document.createElement('button');
    close.type = 'button';
    close.className = 'niwa-lf-card__close';
    close.setAttribute('aria-label', _i18n('close', 'Close'));
    close.textContent = '×';
    close.addEventListener('click', _dismissCard);
    card.appendChild(close);

    var prog = document.createElement('div');
    prog.className = 'niwa-lf-card__progress';
    var progFill = document.createElement('div');
    progFill.className = 'niwa-lf-card__progress-fill';
    progFill.style.width = '0%';
    prog.appendChild(progFill);
    card.appendChild(prog);

    var body = document.createElement('div');
    body.className = 'niwa-lf-card__body';

    var qWrap = document.createElement('div');
    qWrap.className = 'niwa-lf-card__question';
    var num = document.createElement('span');
    num.className = 'niwa-lf-card__number';
    var label = document.createElement('span');
    label.className = 'niwa-lf-card__label';
    qWrap.appendChild(num);
    qWrap.appendChild(label);
    body.appendChild(qWrap);

    var host = document.createElement('div');
    host.className = 'niwa-lf-card__input-host';
    body.appendChild(host);

    var err = document.createElement('div');
    err.className = 'niwa-lf-card__error';
    err.setAttribute('aria-live', 'polite');
    body.appendChild(err);

    card.appendChild(body);

    _cardEl = card;
    _bodyEl = body;
    _progressFillEl = progFill;
    _questionNumberEl = num;
    _questionLabelEl = label;
    _inputHostEl = host;
    _errorEl = err;
    return card;
  }

  function _mountCard() {
    var t = _findMountTargets();
    if (!t) return false;
    var card = _buildCard();
    // Mount card as the last child of the chat panel so it sits below the
    // message stream but above the pill (pill is outside .niwa-morph__chat).
    // Because the chat panel itself is faded/hidden when the flyout is
    // collapsed, the card inherits that behavior automatically.
    if (!card.isConnected) {
      t.chat.appendChild(card);
    }
    card.hidden = false;
    document.body.classList.add('niwa-lf-card-active');
    t.chat.classList.add('niwa-lf-host-active');
    t.chat.setAttribute('data-niwa-lf-variant', t.variant);
    return true;
  }

  function _unmountCard() {
    _restoreOnOpen = false;
    if (window.Niwa && window.Niwa.Scheduler && typeof window.Niwa.Scheduler.destroy === 'function') {
      window.Niwa.Scheduler.destroy();
    }
    if (_cardEl && _cardEl.parentNode) {
      _cardEl.parentNode.removeChild(_cardEl);
    }
    document.body.classList.remove('niwa-lf-card-active');
    var hosts = document.querySelectorAll('.niwa-lf-host-active');
    for (var i = 0; i < hosts.length; i++) {
      hosts[i].classList.remove('niwa-lf-host-active');
      hosts[i].removeAttribute('data-niwa-lf-variant');
    }
    _cardEl = null;
  }

  function _hideCardForMorph() {
    if (!_cardEl || !_cardEl.isConnected) return;
    _cardEl.hidden = true;
    document.body.classList.remove('niwa-lf-card-active');
    var hosts = document.querySelectorAll('.niwa-lf-host-active');
    for (var i = 0; i < hosts.length; i++) {
      hosts[i].classList.remove('niwa-lf-host-active');
      hosts[i].removeAttribute('data-niwa-lf-variant');
    }
  }

  function _dismissCard() {
    _active = false;
    _releaseSendHook();
    _unmountCard();
  }

  function _pauseForMorph() {
    if (!_active || !_cardEl || _cardEl.hidden) return;
    _restoreOnOpen = true;
    _hideCardForMorph();
  }

  function _restoreAfterMorph() {
    if (!_active || !_restoreOnOpen || !_cardEl) return;
    _restoreOnOpen = false;
    _mountCard();
    var field = _cardEl.querySelector('input:not([type="hidden"]), textarea');
    if (field) field.focus();
  }

  /* -- Intercept native send flow for text answers ----------------------- */

  function _clearComposer() {
    var mc = _morph();
    var ta = mc && mc.getTextarea ? mc.getTextarea() : null;
    if (ta) {
      ta.value = '';
      if (mc.syncTextareaLayout) mc.syncTextareaLayout();
      else ta.style.height = 'auto';
    }

    var sendBtn = mc && mc.getSendBtn ? mc.getSendBtn() : null;
    if (sendBtn) {
      var disabledCls = sendBtn.classList.contains('niwa-center__send')
        ? 'niwa-center__send--disabled'
        : 'niwa-morph__send--disabled';
      sendBtn.classList.add(disabledCls);
    }
  }

  function _handleFirstUserMessage(rawText) {
    var text = String(rawText == null ? '' : rawText).trim();
    if (!text) return false;

    var r = _renderer();
    if (!r || typeof r.addMessage !== 'function') return false;

    // The first message is the form trigger, not a simultaneous LLM turn.
    _consumeFirstMessageOnSend = false;
    r.addMessage(text, 'user');
    if (typeof r.saveHistory === 'function') r.saveHistory();
    if (typeof r.clearSuggestions === 'function') r.clearSuggestions();
    _clearComposer();
    _startFlow();
    return true;
  }

  function _installSendHook() {
    if (_sendHookInstalled) return;
    var chat = _chat();
    if (!chat || typeof chat.sendMessage !== 'function') return;
    _originalSendMessage = chat.sendMessage;
    chat.sendMessage = function (text) {
      if (_consumeFirstMessageOnSend && !_triggerFired && _handleFirstUserMessage(text)) {
        return true;
      }
      if (_active && _engine() && !_engine().isCompleted()) {
        return _handleUserTextAnswer(text);
      }
      return _originalSendMessage.call(chat, text);
    };
    _sendHookInstalled = true;
  }

  function _releaseSendHook() {
    if (!_sendHookInstalled) return;
    var chat = _chat();
    if (chat && _originalSendMessage) chat.sendMessage = _originalSendMessage;
    _originalSendMessage = null;
    _sendHookInstalled = false;
    _consumeFirstMessageOnSend = false;
  }

  /* -- Rendering per question -------------------------------------------- */

  function _updateProgress() {
    var eng = _engine();
    if (!eng || !_progressFillEl) return;
    var p = eng.getProgress();
    var pct = p.total > 0 ? Math.max(0, Math.min(100, Math.round((p.current / p.total) * 100))) : 0;
    _progressFillEl.style.width = pct + '%';
  }

  function _clearError() {
    if (_errorEl) {
      _errorEl.textContent = '';
      _errorEl.classList.remove('niwa-lf-card__error--visible');
    }
    if (_cardEl) _cardEl.classList.remove('niwa-lf-card--shake');
  }

  function _showError(message) {
    if (!_errorEl) return;
    _errorEl.textContent = String(message || '');
    _errorEl.classList.add('niwa-lf-card__error--visible');
    if (_cardEl) {
      _cardEl.classList.remove('niwa-lf-card--shake');
      // Force reflow to restart the animation.
      void _cardEl.offsetWidth;
      _cardEl.classList.add('niwa-lf-card--shake');
    }
  }

  function _renderQuestion(question) {
    if (!question || !_cardEl) return;
    _clearError();
    _updateProgress();

    var eng = _engine();
    var prog = eng ? eng.getProgress() : { current: 0, total: 0 };
    var current = (prog.current || 0) + 1;
    _questionNumberEl.textContent = prog.total > 0
      ? String(current) + ' / ' + String(prog.total)
      : String(current) + '.';
    _questionLabelEl.textContent = String(question.label || '');

    // Fade/slide transition.
    _bodyEl.classList.remove('niwa-lf-card__body--enter');
    void _bodyEl.offsetWidth;
    _bodyEl.classList.add('niwa-lf-card__body--enter');

    if (window.Niwa && window.Niwa.Scheduler && typeof window.Niwa.Scheduler.destroy === 'function') {
      window.Niwa.Scheduler.destroy();
    }
    _inputHostEl.innerHTML = '';
    var type = String(question.type || 'text');

    if (type === 'appointment') {
      _renderAppointmentInput(question);
    } else if (type === 'choice_single' || type === 'choice_multi') {
      _renderChoiceInput(question, type === 'choice_multi');
    } else if (type === 'textarea') {
      _renderTextareaInput(question);
    } else {
      _renderInlineTextInput(question, type);
    }
  }

  function _renderAppointmentInput(question) {
    var scheduler = window.Niwa && window.Niwa.Scheduler;
    if (!scheduler || typeof scheduler.activate !== 'function') {
      _showError(_i18n('schedulerUnavailable', 'Online booking is not available right now.'));
      return;
    }
    scheduler.activate({
      host: _inputHostEl,
      dismissible: false,
      question: question,
      onBooked: function (result) { _submit(question, result.answer); }
    }).catch(function (error) {
      _showError(error && error.message ? error.message : _i18n('schedulerUnavailable', 'Online booking is not available right now.'));
    });
  }

  /**
   * Build a button that visually matches the native composer's round send
   * (dark 32px circle with up-arrow SVG). Reuses `.niwa-morph__send` so it
   * inherits all shield styling — identical to the pill's send button.
   */
  function _buildNativeSendButton(onClick) {
    var btn = document.createElement('button');
    btn.type = 'button';
    btn.className = 'niwa-morph__send niwa-morph__send--disabled';
    btn.setAttribute('aria-label', _i18n('send', 'Send'));
    btn.innerHTML =
      '<svg width="32" height="32" viewBox="0 0 32 32" fill="none" aria-hidden="true">' +
      '<path d="M16 22L16 10M16 10L11 15M16 10L21 15" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/>' +
      '</svg>';
    btn.addEventListener('click', onClick);
    return btn;
  }

  function _syncSendDisabled(btn, field) {
    if (!btn || !field) return;
    var empty = String(field.value == null ? '' : field.value).trim() === '';
    btn.classList.toggle('niwa-morph__send--disabled', empty);
  }

  /**
   * Inline single-line input (text / email / phone / number). Renders the
   * same markup the native pill composer uses (`.niwa-morph__input` wrapper
   * with `.niwa-morph__textarea` + `.niwa-morph__send`) so the frontend
   * shield CSS styles it identically to the native input — there is no
   * separate lead-form input skin to maintain.
   */
  function _renderInlineTextInput(question, type) {
    var wrap = document.createElement('div');
    wrap.className = 'niwa-lf-card__native-input';

    var input = document.createElement('input');
    input.className = 'niwa-morph__textarea';
    input.type = (type === 'email') ? 'email'
      : (type === 'phone') ? 'tel'
      : (type === 'number') ? 'number'
      : 'text';
    if (type === 'email') input.setAttribute('inputmode', 'email');
    else if (type === 'phone') input.setAttribute('inputmode', 'tel');
    else if (type === 'number') input.setAttribute('inputmode', 'decimal');
    input.autocomplete = (type === 'email') ? 'email' : (type === 'phone') ? 'tel' : 'off';
    if (question.placeholder) input.placeholder = String(question.placeholder);

    var btn = _buildNativeSendButton(function () {
      _submit(question, input.value);
    });

    input.addEventListener('keydown', function (ev) {
      if (ev.key === 'Enter') {
        ev.preventDefault();
        _submit(question, input.value);
      }
    });
    input.addEventListener('input', function () {
      _clearError();
      _syncSendDisabled(btn, input);
    });

    wrap.appendChild(input);
    wrap.appendChild(btn);
    _inputHostEl.appendChild(wrap);
    _syncSendDisabled(btn, input);
    setTimeout(function () { input.focus(); }, 60);
  }

  function _renderTextareaInput(question) {
    var wrap = document.createElement('div');
    wrap.className = 'niwa-lf-card__native-input niwa-lf-card__native-input--multiline';

    var ta = document.createElement('textarea');
    ta.className = 'niwa-morph__textarea';
    ta.rows = 3;
    if (question.placeholder) ta.placeholder = String(question.placeholder);

    var btn = _buildNativeSendButton(function () {
      _submit(question, ta.value);
    });

    ta.addEventListener('keydown', function (ev) {
      if (ev.key === 'Enter' && !ev.shiftKey) {
        ev.preventDefault();
        _submit(question, ta.value);
      }
    });
    ta.addEventListener('input', function () {
      _clearError();
      _syncSendDisabled(btn, ta);
    });

    wrap.appendChild(ta);
    wrap.appendChild(btn);
    _inputHostEl.appendChild(wrap);
    _syncSendDisabled(btn, ta);
    setTimeout(function () { ta.focus(); }, 50);
  }

  function _renderChoiceInput(question, multi) {
    var options = Array.isArray(question.options) ? question.options : [];
    var selections = {};

    var list = document.createElement('div');
    list.className = 'niwa-lf-card__choices' + (multi ? ' niwa-lf-card__choices--multi' : '');

    options.forEach(function (opt) {
      var btn = document.createElement('button');
      btn.type = 'button';
      btn.className = 'niwa-lf-card__choice';
      btn.setAttribute('data-value', String(opt.value));
      btn.setAttribute('aria-pressed', 'false');
      btn.textContent = String(opt.label || opt.value);

      btn.addEventListener('click', function () {
        if (multi) {
          var val = String(opt.value);
          if (selections[val]) {
            delete selections[val];
            btn.classList.remove('niwa-lf-card__choice--active');
            btn.setAttribute('aria-pressed', 'false');
          } else {
            selections[val] = true;
            btn.classList.add('niwa-lf-card__choice--active');
            btn.setAttribute('aria-pressed', 'true');
          }
          _clearError();
        } else {
          btn.setAttribute('aria-pressed', 'true');
          _submit(question, String(opt.value));
        }
      });
      list.appendChild(btn);
    });
    _inputHostEl.appendChild(list);

    if (multi) {
      var continueBtn = document.createElement('button');
      continueBtn.type = 'button';
      continueBtn.className = 'niwa-lf-card__continue';
      continueBtn.textContent = _i18n('continue', 'Continue');
      continueBtn.addEventListener('click', function () {
        var values = Object.keys(selections);
        _submit(question, values);
      });
      _inputHostEl.appendChild(continueBtn);
    }
  }

  /* -- Submit helpers ----------------------------------------------------- */

  function _handleUserTextAnswer(rawText) {
    var eng = _engine();
    if (!eng) return;
    var q = eng.getCurrentQuestion();
    if (!q) return;
    _submit(q, String(rawText == null ? '' : rawText));
  }

  function _submit(question, answer) {
    var eng = _engine();
    if (!eng || !question) return;

    var local = eng.validateAnswer(question, answer);
    if (!local.valid) {
      _showError(local.error || _i18n('required', 'This field is required.'));
      return;
    }

    // Clear native textarea if we were reusing it.
    var mc = _morph();
    var ta = mc && mc.getTextarea ? mc.getTextarea() : null;
    if (ta) {
      ta.value = '';
      if (mc.syncTextareaLayout) mc.syncTextareaLayout();
      else ta.style.height = 'auto';
    }

    _bodyEl.classList.add('niwa-lf-card__body--leaving');

    eng.submitAnswer(question.id, answer).then(function (res) {
      _bodyEl.classList.remove('niwa-lf-card__body--leaving');
      if (!res || !res.ok) {
        _showError(res && res.error ? String(res.error) : _i18n('required', 'This field is required.'));
      }
      // Advanced/completed events handle rendering.
    }).catch(function () {
      _bodyEl.classList.remove('niwa-lf-card__body--leaving');
      _showError(_i18n('required', 'Something went wrong.'));
    });
  }

  /* -- Completion UI ------------------------------------------------------ */

  /**
   * Finalize the flow by handing off to the normal chat surface: render a
   * bot bubble with the configured media + text into the chat body, then
   * unmount the card and drop the `niwa-lf-card-active` body class so the
   * native pill composer reappears and the visitor can continue chatting.
   */
  function _renderCompletion() {
    var completion = _engine() ? _engine().getCompletionConfig() : { text: '', mediaUrl: '', mediaType: '' };
    var text = completion.text || '';
    var mediaUrl = completion.mediaUrl || '';
    var mediaType = completion.mediaType || '';

    var bodyEl = document.querySelector('.niwa-morph__body') || document.querySelector('.niwa-center__body');

    if (bodyEl && (mediaUrl || text)) {
      var msgDiv = document.createElement('div');
      msgDiv.className = 'niwa-message niwa-message--bot';
      msgDiv.setAttribute('data-source', 'lf');

      var avatarDiv = document.createElement('div');
      avatarDiv.className = 'niwa-message__avatar';
      var avatarUrl = (window.NiwaAI && window.NiwaAI.avatar_url) ? window.NiwaAI.avatar_url : '';
      if (avatarUrl) {
        var avatarImg = document.createElement('img');
        avatarImg.src = avatarUrl;
        avatarImg.alt = 'Niwa';
        avatarImg.width = 28;
        avatarImg.height = 28;
        avatarDiv.appendChild(avatarImg);
      }
      msgDiv.appendChild(avatarDiv);

      var contentWrapper = document.createElement('div');
      contentWrapper.className = 'niwa-message__content';

      var bubbleDiv = document.createElement('div');
      bubbleDiv.className = 'niwa-message__bubble niwa-lf-completion-bubble';

      if (mediaUrl) {
        if (mediaType === 'video') {
          var video = document.createElement('video');
          video.autoplay = true;
          video.muted = true;
          video.loop = true;
          video.setAttribute('playsinline', '');
          video.className = 'niwa-lf-completion-media';
          var source = document.createElement('source');
          source.src = mediaUrl;
          source.type = 'video/mp4';
          video.appendChild(source);
          bubbleDiv.appendChild(video);
        } else {
          var img = document.createElement('img');
          img.src = mediaUrl;
          img.alt = '';
          img.className = 'niwa-lf-completion-media';
          bubbleDiv.appendChild(img);
        }
      }

      if (text) {
        var p = document.createElement('p');
        p.className = 'niwa-message__text';
        p.textContent = text;
        bubbleDiv.appendChild(p);
      }

      contentWrapper.appendChild(bubbleDiv);
      msgDiv.appendChild(contentWrapper);
      bodyEl.appendChild(msgDiv);

      if (window.Niwa && window.Niwa.ScrollBehavior && window.Niwa.ScrollBehavior.scrollToBottom) {
        window.Niwa.ScrollBehavior.scrollToBottom(bodyEl);
      } else {
        bodyEl.scrollTop = bodyEl.scrollHeight;
      }
    }

    _active = false;
    _releaseSendHook();
    _unmountCard();
  }

  /* -- Engine events ------------------------------------------------------ */

  function _onStarted(e) {
    if (!_active) return;
    var detail = (e && e.detail) || {};
    if (!_cardEl) _mountCard();
    if (detail.completed) {
      _renderCompletion();
      return;
    }
    if (detail.question) {
      _renderQuestion(detail.question);
    }
  }

  function _onAdvanced(e) {
    if (!_active) return;
    var detail = (e && e.detail) || {};
    if (detail.completed) {
      _renderCompletion();
      return;
    }
    if (detail.question) {
      _renderQuestion(detail.question);
    }
  }

  function _onValidationError(e) {
    if (!_active) return;
    var detail = (e && e.detail) || {};
    _showError(detail.error || _i18n('required', 'This field is required.'));
  }

  /* -- Trigger dispatcher ------------------------------------------------ */

  function _startFlow() {
    if (_triggerFired) return;
    _triggerFired = true;
    _active = true;
    _installSendHook();
    _mountCard();
    _engine().start().catch(function () {
      _active = false;
      _releaseSendHook();
      _unmountCard();
    });
  }

  if (window.addEventListener) {
    window.addEventListener('niwa:morph:before-close', _pauseForMorph);
    window.addEventListener('niwa:morph:opened', _restoreAfterMorph);
  }

  function _armImmediate() {
    if (_triggerArmed) return;
    _triggerArmed = true;
    var mc = _morph();
    if (mc && mc.isOpen && mc.isOpen()) {
      _startFlow();
      return;
    }
    var morphEl = document.getElementById('niwaMorph');
    if (!morphEl) { _startFlow(); return; }
    var observer = new MutationObserver(function () {
      if (morphEl.classList.contains('niwa-morph--open')) {
        observer.disconnect();
        _startFlow();
      }
    });
    observer.observe(morphEl, { attributes: true, attributeFilter: ['class'] });
  }

  function _armAfterDelay(delay) {
    if (_triggerArmed) return;
    _triggerArmed = true;
    setTimeout(function () {
      var mc = _morph();
      if (mc && mc.isOpen && mc.isOpen()) { _startFlow(); return; }
      var morphEl = document.getElementById('niwaMorph');
      if (!morphEl) { _startFlow(); return; }
      var observer = new MutationObserver(function () {
        if (morphEl.classList.contains('niwa-morph--open')) {
          observer.disconnect();
          _startFlow();
        }
      });
      observer.observe(morphEl, { attributes: true, attributeFilter: ['class'] });
    }, Math.max(0, parseInt(delay || 0, 10)));
  }

  function _armAfterFirstUserMsg() {
    if (_triggerArmed) return;
    _triggerArmed = true;
    _consumeFirstMessageOnSend = true;
    _installSendHook();
  }

  /* -- init --------------------------------------------------------------- */

  function init() {
    var lf = window.NiwaLF;
    if (!lf || !lf.config || !lf.config.enabled) return;
    if (lf.config.mode !== 'card') return;
    // Visitor already finished (or partial-submitted) the form on an earlier
    // page load — backend ships `completed:true` via NiwaLF.config. Bail
    // before arming any trigger so the completion screen doesn't pop up on
    // every subsequent page render.
    if (lf.config.completed === true) return;

    document.addEventListener('niwa:lf:started', _onStarted);
    document.addEventListener('niwa:lf:advanced', _onAdvanced);
    document.addEventListener('niwa:lf:validation-error', _onValidationError);

    var trigger = lf.config.trigger || 'after_first_user_msg';
    if (trigger === 'ai_only') {
      // No JS auto-arm — the flow starts only when the frontend agent
      // calls `activate_lead_form` (routes through
      // `window.Niwa.LeadForm.activate()` → `activate()` below).
      return;
    }
    if (trigger === 'immediate') {
      _armImmediate();
    } else if (trigger === 'after_delay') {
      _armAfterDelay(lf.config.trigger_delay_ms);
    } else {
      _armAfterFirstUserMsg();
    }
  }

  /**
   * Externally triggered activation (AI agent tool, programmatic start).
   * Idempotent: if the flow already fired in this page session the call
   * is a no-op.
   */
  function activate() {
    if (_triggerFired) return;
    var lf = window.NiwaLF;
    if (!lf || !lf.config || !lf.config.enabled) return;
    if (lf.config.mode !== 'card') return;
    // Defense-in-depth: even though Niwa.LeadForm.activate() already checks
    // engine.isCompleted(), guard here too so a stray direct call cannot
    // revive a finished flow.
    if (lf.config.completed === true) return;

    // Ensure engine listeners exist even if init() was short-circuited
    // by the `ai_only` branch above.
    document.removeEventListener('niwa:lf:started', _onStarted);
    document.removeEventListener('niwa:lf:advanced', _onAdvanced);
    document.removeEventListener('niwa:lf:validation-error', _onValidationError);
    document.addEventListener('niwa:lf:started', _onStarted);
    document.addEventListener('niwa:lf:advanced', _onAdvanced);
    document.addEventListener('niwa:lf:validation-error', _onValidationError);

    _triggerArmed = true;
    _startFlow();
  }

  /* -- Public API --------------------------------------------------------- */

  return {
    init: init,
    activate: activate
  };
})();

/* -- Auto-init on DOMContentLoaded ---------------------------------------- */
(function () {
  'use strict';

  function boot() {
    if (!window.NiwaLF || !window.NiwaLF.config || !window.NiwaLF.config.enabled) return;
    if (window.NiwaLF.config.mode !== 'card') return;
    // Dependency order guarantees the engine and ChatClient are ready here.
    // Arm now so the first send cannot race the trigger hook.
    window.Niwa.LeadFormCardMode.init();
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', boot, { once: true });
  } else {
    boot();
  }
})();
