jQuery(function ($) {
  const openBtn = $('#sbc-open');
  const openBadge = $('#sbc-open-badge');
  const panel = $('#sbc-panel');
  const bannerEl = $('#sbc-banner');
  const walletEl = $('#sbc-wallet');
  const walletTextEl = $('#sbc-wallet-text');
  const walletNoteEl = $('#sbc-wallet-note');
  const withdrawBtn = $('#sbc-withdraw');
  const timerEl = $('#sbc-timer');
  const statusEl = $('#sbc-status');
  const messagesEl = $('#sbc-messages');
  const jumpBtn = $('#sbc-jump-bottom');
  const actionsEl = $('#sbc-actions');
  const inputWrap = $('#sbc-input-wrap');
  const soundToggleBtn = $('#sbc-sound-toggle');
  const minimizeBtn = $('#sbc-minimize');

  let poller = null;
  let bgPoller = null;
  let countdown = null;
  let typingPingAt = 0;
  let typingBubbleShown = false;
  let audioCtx = null;
  let bonusCheckTriggered = false;

  let currentResetVersion = parseInt(SBC_CHAT.resetVersion, 10) || 1;
  let storageKey = 'sbc_state_v9_' + currentResetVersion;
  let soundEnabled = localStorage.getItem('sbc_sound_enabled') !== '0';

  function defaultState() {
    return {
      step: 'ask_email',
      email: '',
      fullName: '',
      userId: 0,
      service: '',
      transactionId: 0,
      chatId: null,
      chatToken: null,
      chatStatus: 'none',
      expiresTs: 0,
      eligible: false,
      bonusAmount: 0,
      cooldownMessage: '',
      lastSeenAgentMsgKey: '',
      unreadBadge: 0,
      rated: false,
      messages: [],
      wallet: null
    };
  }

  function sanitizeSavedState(saved) {
    saved = saved || {};
    if (saved.step === 'opening_chat') saved.step = 'ask_email';
    if (saved.chatStatus === 'closed' && saved.step !== 'closed') saved.step = 'closed';
    return saved;
  }

  function loadState() {
    try {
      const raw = localStorage.getItem(storageKey);
      const saved = raw ? JSON.parse(raw) : {};
      return Object.assign(defaultState(), sanitizeSavedState(saved));
    } catch (e) {
      return defaultState();
    }
  }

  function saveState() {
    localStorage.setItem(storageKey, JSON.stringify(state));
  }

  function esc(s) {
    return String(s || '').replace(/[&<>"']/g, function (m) {
      return ({
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
      })[m];
    });
  }

  function formatTime(tsString) {
    if (!tsString) return '';
    const d = new Date(tsString.replace(' ', 'T'));
    if (isNaN(d.getTime())) return '';
    let h = d.getHours();
    const m = String(d.getMinutes()).padStart(2, '0');
    const ampm = h >= 12 ? 'PM' : 'AM';
    h = h % 12 || 12;
    return `${h}:${m} ${ampm}`;
  }

  function beep() {
    if (!soundEnabled) return;
    try {
      audioCtx = audioCtx || new (window.AudioContext || window.webkitAudioContext)();
      const osc = audioCtx.createOscillator();
      const gain = audioCtx.createGain();
      osc.type = 'sine';
      osc.frequency.value = 880;
      gain.gain.setValueAtTime(0.08, audioCtx.currentTime);
      gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.35);
      osc.connect(gain);
      gain.connect(audioCtx.destination);
      osc.start();
      osc.stop(audioCtx.currentTime + 0.35);
    } catch (e) { /* audio not available, ignore */ }
  }

  function updateOpenBadge() {
    if (state.unreadBadge > 0 && !panel.is(':visible')) {
      openBadge.text(state.unreadBadge > 9 ? '9+' : state.unreadBadge).css('display', 'flex');
    } else {
      openBadge.hide();
    }
  }

  let state = loadState();

  soundToggleBtn.text(soundEnabled ? '🔔' : '🔕');
  soundToggleBtn.toggleClass('sbc-muted', !soundEnabled);
  updateOpenBadge();

  function clearTimers() {
    clearInterval(poller);
    clearInterval(countdown);
    poller = null;
    countdown = null;
  }

  function hardResetFrontend(newVersion) {
    const oldKey = storageKey;
    currentResetVersion = parseInt(newVersion, 10) || (currentResetVersion + 1);
    storageKey = 'sbc_state_v9_' + currentResetVersion;
    localStorage.removeItem(oldKey);

    state = defaultState();
    saveState();
    clearTimers();
    renderMessages();
    loadSupportContext();
  }

  function messageExists(key) {
    return state.messages.some(m => m.key === key);
  }

  function pushMessage(sender, text, key, createdAt, senderLabel, senderDepartment) {
    const msgKey = key || ('msg-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8));
    if (messageExists(msgKey)) return;

    state.messages.push({
      key: msgKey,
      sender: sender,
      message: text,
      createdAt: createdAt || '',
      senderLabel: senderLabel || '',
      senderDepartment: senderDepartment || ''
    });

    saveState();
    renderMessages();
  }

  function appendServerMessages(list) {
    let newAgentMessage = false;

    (list || []).forEach(function (m) {
      const key = 'srv-' + m.id;
      if (messageExists(key)) return;

      const sender = m.sender_type === 'agent'
        ? 'agent'
        : m.sender_type === 'customer'
          ? 'user'
          : m.sender_type === 'warning'
            ? 'warning'
            : 'system';

      if (sender === 'agent') newAgentMessage = true;

      pushMessage(sender, m.message, key, m.created_at, m.sender_label, m.sender_department);
    });

    if (newAgentMessage) {
      beep();
      if (!panel.is(':visible')) {
        state.unreadBadge = (state.unreadBadge || 0) + 1;
        saveState();
        updateOpenBadge();
      }
    }
  }

  function isNearBottom() {
    const el = messagesEl[0];
    if (!el) return true;
    return (el.scrollHeight - el.scrollTop - el.clientHeight) < 60;
  }

  function renderMessages() {
    const wasNearBottom = isNearBottom();
    messagesEl.children('.sbc-msg-row, .sbc-day-divider').remove();

    state.messages.forEach(function (m) {
      const label = m.sender === 'agent'
        ? (m.senderLabel || 'Agent') + (m.senderDepartment ? ' · ' + m.senderDepartment : '')
        : m.sender === 'user'
          ? 'You'
          : m.sender === 'warning'
            ? ''
            : 'Support';

      const time = m.createdAt ? `<span class="sbc-msg-time">${esc(formatTime(m.createdAt))}</span>` : '';

      messagesEl.append(
        `<div class="sbc-msg-row ${m.sender}">
          ${m.sender !== 'user' && m.sender !== 'warning' ? '<span class="sbc-message-avatar">S</span>' : ''}
          <div class="sbc-msg ${m.sender}">
            ${label ? `<strong>${esc(label)}</strong>` : ''}
            <div>${esc(m.message).replace(/\n/g, '<br>')}</div>
            ${time}${m.sender === 'user' ? '<span class="sbc-delivered">✓✓</span>' : ''}
          </div>
        </div>`
      );
    });

    if (messagesEl[0]) {
      if (wasNearBottom) {
        scrollToBottom();
      } else {
        jumpBtn.show();
      }
    }
  }

  function scrollToBottom() {
    if (messagesEl[0]) {
      messagesEl.scrollTop(messagesEl[0].scrollHeight);
    }
    jumpBtn.hide();
  }

  function showTypingBubble(show) {
    if (show === typingBubbleShown) return;
    typingBubbleShown = show;

    $('#sbc-typing-indicator').remove();
    if (show) {
      messagesEl.append(`
        <div class="sbc-typing-row" id="sbc-typing-indicator">
          <div class="sbc-typing-bubble"><span></span><span></span><span></span></div>
        </div>
      `);
      if (isNearBottom()) scrollToBottom();
    }
  }

  function setActions(html) {
    actionsEl.html(html || '');
  }

  function clearActions() {
    actionsEl.html('');
  }

  function setInput(mode, placeholder, buttonText, showEnd) {
    inputWrap.show();

    if (mode === 'hidden') {
      inputWrap.hide();
      return;
    }

    const inputHtml = mode === 'email'
      ? `<input type="email" id="sbc-input-field" placeholder="${esc(placeholder || '')}">`
      : `<textarea id="sbc-input-field" class="sbc-textarea" placeholder="${esc(placeholder || '')}"></textarea>`;

    const endButton = showEnd
      ? `<button type="button" id="sbc-end-chat" class="sbc-btn sbc-btn-danger">End Chat</button>`
      : `<button type="button" id="sbc-end-chat" class="sbc-btn sbc-btn-danger" style="display:none;">End Chat</button>`;

    inputWrap.html(`
      ${inputHtml}
      <button type="button" id="sbc-send" class="sbc-btn">${esc(buttonText || 'Send')}</button>
      ${endButton}
    `);
  }

  function getInputField() {
    return $('#sbc-input-field');
  }

  function showGreetingIfNeeded() {
    if (!state.messages.length) {
      pushMessage('system', 'Hello 👋 What is your email?');
    }
  }

  function showEmailStep() {
    state.step = 'ask_email';
    saveState();

    showGreetingIfNeeded();
    clearActions();
    setInput('email', 'Enter your email', 'Continue', false);
    statusEl.text('');
    walletEl.hide();
    bannerEl.hide().text('');
    timerEl.text('');
  }

  function showConfirmStep(fullName) {
    state.step = 'confirm_name';
    saveState();

    pushMessage('system', `I found: ${fullName}. Is this you?`);
    setActions(`
      <button type="button" class="sbc-option-btn" data-action="confirm" data-value="yes">Yes</button>
      <button type="button" class="sbc-option-btn" data-action="confirm" data-value="no">No</button>
    `);
    setInput('hidden');
  }

  function showServiceStep() {
    state.step = 'choose_service';
    saveState();

    pushMessage('system', 'Thanks. Please choose the service you have an issue with:', 'service-prompt-' + (state.userId || 'customer'));
    const configuredServices = Array.isArray(SBC_CHAT.complaintServices) ? SBC_CHAT.complaintServices : [];
    const serviceButtons = configuredServices.map(item => `<button type="button" class="sbc-option-btn" data-action="service" data-value="${esc(item.key)}">◉ ${esc(item.label)}</button>`).join('');
    setActions(`
      <span class="sbc-category-label">Choose a category</span>
      ${serviceButtons}
      <button type="button" class="sbc-option-btn" data-action="service" data-value="other">☏ Talk to an Agent</button>
      <button type="button" class="sbc-option-btn sbc-option-muted" data-action="cancel">Cancel</button>
    `);
    setInput('hidden');
  }

  let recentTransactions = [];
  let transactionPage = 1;

  function showRecentTransactions(service, page) {
    transactionPage = Math.max(1, Number(page) || 1);
    state.step = 'choose_transaction';
    saveState();
    setInput('hidden');
    setActions('<span class="sbc-category-label">Loading your recent transactions...</span>');

    $.post(SBC_CHAT.ajaxUrl, {
      action: 'sbc_get_recent_transactions', nonce: SBC_CHAT.nonce, service: service, page: transactionPage
    }, function (res) {
      if (!res || !res.success) {
        pushMessage('system', (res && res.data && res.data.message) ? res.data.message : 'Could not load transactions.');
        setActions('<button type="button" class="sbc-option-btn" data-action="service" data-value="other">Talk to an Agent</button><button type="button" class="sbc-option-btn sbc-option-muted" data-action="restart">Restart</button>');
        return;
      }
      recentTransactions = res.data.transactions || [];
      if (!recentTransactions.length) {
        pushMessage('system', 'No recent transactions were found for this service. You can talk directly to an agent.');
        const back = transactionPage > 1 ? '<button type="button" class="sbc-option-btn" data-action="transaction_page" data-value="' + (transactionPage - 1) + '">← Previous</button>' : '';
        setActions(`${back}<button type="button" class="sbc-option-btn" data-action="service" data-value="other">Talk to an Agent</button><button type="button" class="sbc-option-btn sbc-option-muted" data-action="restart">Restart</button>`);
        return;
      }
      const cards = recentTransactions.map(function (tx) {
        const title = tx.plan || tx.network || (tx.service.charAt(0).toUpperCase() + tx.service.slice(1));
        return `<button type="button" class="sbc-transaction-option" data-action="transaction" data-value="${Number(tx.id)}"><strong>${esc(title)} • ${SBC_CHAT.currency}${Number(tx.amount).toFixed(2)}</strong><span>${esc(tx.recipient)} • ${esc(formatTime(tx.created_at))} • ${esc(tx.status)}</span></button>`;
      }).join('');
      const previous = res.data.has_previous ? `<button type="button" class="sbc-option-btn" data-action="transaction_page" data-value="${transactionPage - 1}">← Previous</button>` : '';
      const next = res.data.has_more ? `<button type="button" class="sbc-option-btn" data-action="transaction_page" data-value="${transactionPage + 1}">Next 4 →</button>` : '';
      setActions(`<span class="sbc-category-label">Select the transaction with the issue</span><div class="sbc-transaction-pager">${previous}${next}<button type="button" class="sbc-option-btn sbc-option-muted" data-action="restart">Cancel / Restart</button></div>${cards}`);
    });
  }

  function loadSupportContext() {
    if (!SBC_CHAT.loggedIn) {
      state = defaultState();
      state.messages = [];
      pushMessage('system', 'Please log in to access customer support.');
      setActions(`<a class="sbc-option-btn sbc-login-link" href="${esc(SBC_CHAT.loginUrl)}">Log In</a>`);
      setInput('hidden');
      walletEl.hide();
      return;
    }

    $.post(SBC_CHAT.ajaxUrl, { action: 'sbc_get_support_context', nonce: SBC_CHAT.nonce }, function (res) {
      if (!res || !res.success) return;
      const data = res.data;
      state.email = data.email;
      state.fullName = data.full_name;
      state.userId = data.user_id;
      state.wallet = data.wallet;
      state.cooldownMessage = data.bonus_cooldown_message || '';
      updateWallet(data.wallet);
      if (state.cooldownMessage) bannerEl.show().text(state.cooldownMessage);
      if (data.existing_chat && data.existing_chat.status !== 'closed') {
        enterChatActive(data.existing_chat, data.wallet);
        return;
      }
      state = Object.assign(defaultState(), {
        step: 'choose_service', email: data.email, fullName: data.full_name,
        userId: data.user_id, wallet: data.wallet, cooldownMessage: data.bonus_cooldown_message || '',
        messages: [{ key: 'welcome-' + data.user_id, sender: 'system', message: `Hello ${data.full_name}. What do you need help with?`, createdAt: '' }]
      });
      saveState();
      renderMessages();
      updateWallet(data.wallet);
      if (state.cooldownMessage) bannerEl.show().text(state.cooldownMessage);
      showServiceStep();
    });
  }

  function showDetailsStep() {
    state.step = 'ask_details';
    saveState();

    pushMessage('system', state.service === 'other' ? 'Briefly describe what you need help with, then click Contact Agent.' : 'Briefly describe the issue.');
    setActions('<button type="button" class="sbc-option-btn sbc-option-muted" data-action="restart">Cancel / Restart</button>');
    setInput('textarea', 'Describe your issue', 'Contact Agent', false);
  }

  function showChatActiveStep() {
    state.step = 'chat_active';
    saveState();

    clearActions();
    setInput('textarea', 'Type your message', 'Send', true);
  }

  function showClosedStep() {
    state.step = 'closed';
    state.chatStatus = 'closed';
    saveState();

    clearActions();
    setInput('hidden');
    statusEl.text('Chat ended.');
    timerEl.text('');
    bannerEl.hide();
    showTypingBubble(false);

    if (!state.rated) {
      renderRatingPrompt();
    } else {
      setActions(`<button type="button" class="sbc-option-btn" id="sbc-new-chat">Start New Chat</button>`);
    }
  }

  function renderRatingPrompt() {
    setActions(`
      <div style="width:100%;text-align:center;">
        <div style="font-size:13px;color:#4b5563;margin-bottom:4px;">How was your support experience?</div>
        <div class="sbc-rating" id="sbc-rating-stars">
          ${[1, 2, 3, 4, 5].map(n => `<span class="sbc-star" data-star="${n}">★</span>`).join('')}
        </div>
        <button type="button" class="sbc-option-btn" id="sbc-new-chat" style="margin-top:6px;">Skip / Start New Chat</button>
      </div>
    `);
  }

  function submitRating(stars) {
    if (!state.chatId || !state.chatToken) return;

    $.post(SBC_CHAT.ajaxUrl, {
      action: 'sbc_submit_rating',
      nonce: SBC_CHAT.nonce,
      chat_id: state.chatId,
      chat_token: state.chatToken,
      rating: stars
    }, function (res) {
      if (res && res.success) {
        state.rated = true;
        saveState();
        pushMessage('system', `Thanks for rating us ${stars}/5! ⭐`);
        setActions(`<button type="button" class="sbc-option-btn" id="sbc-new-chat">Start New Chat</button>`);
      }
    });
  }

  function updateWallet(data) {
    if (!data) { walletEl.hide(); return; }

    const balance = parseFloat(data.balance !== undefined ? data.balance : (data.bonus_balance || 0));
    const threshold = parseFloat(data.threshold !== undefined ? data.threshold : (data.withdrawal_threshold || SBC_CHAT.withdrawalThreshold || 500));
    const pending = !!(data.pending_withdrawal !== undefined ? data.pending_withdrawal : data.withdrawal_pending);

    if (!state.userId) {
      walletEl.hide();
      return;
    }

    walletEl.css('display', 'grid');
    walletTextEl.text(`${SBC_CHAT.currency}${balance.toFixed(2)}`);

    if (pending) {
      walletNoteEl.text('Withdrawal request pending review.');
      withdrawBtn.hide();
    } else if (balance >= threshold) {
      walletNoteEl.text(`You can request withdrawal now. Threshold: ${SBC_CHAT.currency}${threshold.toFixed(2)}`);
      withdrawBtn.show();
    } else {
      walletNoteEl.text(`Withdrawal available from ${SBC_CHAT.currency}${threshold.toFixed(2)}.`);
      withdrawBtn.hide();
    }
  }

  function isRecentTimestamp(tsString, seconds = 4) {
    if (!tsString) return false;
    const ts = new Date(tsString.replace(' ', 'T')).getTime();
    return (Date.now() - ts) < (seconds * 1000);
  }

  function startCountdown() {
    clearInterval(countdown);

    countdown = setInterval(function () {
      if (!state.expiresTs) return;

      const diff = (state.expiresTs * 1000) - Date.now();

      if (diff <= 0) {
        timerEl.text('00:00');
        clearInterval(countdown);
        if (!bonusCheckTriggered) {
          bonusCheckTriggered = true;
          refreshStatus();
        }
        return;
      }

      const seconds = Math.max(0, Math.ceil(diff / 1000));
      const minutesPart = Math.floor(seconds / 60);
      const secondsPart = String(seconds % 60).padStart(2, '0');
      timerEl.text(`Bonus in ${minutesPart}:${secondsPart}`);
    }, 1000);

    const diff = (state.expiresTs * 1000) - Date.now();
    if (diff > 0) {
      bonusCheckTriggered = false;
      const seconds = Math.ceil(diff / 1000);
      timerEl.text(`Bonus in ${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, '0')}`);
    } else {
      timerEl.text('00:00');
      if (!bonusCheckTriggered) {
        bonusCheckTriggered = true;
        refreshStatus();
      }
    }
  }

  function startPolling() {
    clearInterval(poller);
    poller = setInterval(refreshStatus, 3000);
  }

  function stopPollingOnly() {
    clearInterval(poller);
    poller = null;
  }

  // Light background poll so the unread badge/sound still work while the
  // panel is closed, without hammering the server as hard as the in-chat poll.
  function startBackgroundPolling() {
    clearInterval(bgPoller);
    bgPoller = setInterval(function () {
      if (!panel.is(':visible') && state.chatId && state.chatToken && state.chatStatus !== 'closed') {
        refreshStatus();
      }
    }, 10000);
  }

  function refreshStatus() {
    if (!state.chatId || !state.chatToken) return;

    $.post(SBC_CHAT.ajaxUrl, {
      action: 'sbc_get_status',
      nonce: SBC_CHAT.nonce,
      chat_id: state.chatId,
      chat_token: state.chatToken
    }, function (res) {
      if (!res || !res.success) return;

      const data = res.data || {};

      if (data.reset_version && parseInt(data.reset_version, 10) !== currentResetVersion) {
        hardResetFrontend(data.reset_version);
        return;
      }

      state.expiresTs = parseInt(data.expires_ts, 10) || 0;
      state.chatStatus = data.status;
      if (data.bonus_cooldown_message) state.cooldownMessage = data.bonus_cooldown_message;
      if (data.rating !== null && data.rating !== undefined) state.rated = true;
      saveState();

      appendServerMessages(data.messages || []);
      updateWallet(data);

      if (data.status === 'closed') {
        bannerEl.hide();
        timerEl.text('Chat ended.');
        statusEl.text('Chat ended.');
        clearInterval(countdown);
        stopPollingOnly();
        showClosedStep();
        return;
      }

      if (data.compensation_awarded) {
        bannerEl.show().text('Bonus awarded.');
        statusEl.text('Waiting for agent...');
        timerEl.text('Bonus time completed.');
        clearInterval(countdown);
      } else if (isRecentTimestamp(data.agent_typing_at, 4)) {
        statusEl.text('Agent is typing...');
      } else if (data.agent_replied_at || data.status === 'active') {
        bannerEl.show().text('Agent connected. Bonus cancelled.');
        statusEl.text('Agent connected.');
        timerEl.text('Agent connected.');
        clearInterval(countdown);
      } else if (data.bonus_cooldown_message || state.cooldownMessage) {
        const cooldownText = data.bonus_cooldown_message || state.cooldownMessage;
        bannerEl.show().text(cooldownText);
        statusEl.text('Waiting for agent...');
        timerEl.text('Bonus cooldown active');
        clearInterval(countdown);
      } else if (state.step === 'chat_active') {
        statusEl.text('Waiting for agent...');
        if (state.expiresTs > 0) {
          bannerEl.show().text(
            state.eligible && state.bonusAmount > 0
              ? `If no agent responds in ${SBC_CHAT.timeout} seconds, you get ${SBC_CHAT.currency}${state.bonusAmount} bonus.`
              : 'Waiting for agent...'
          );
          startCountdown();
        }
      }

      if (panel.is(':visible')) {
        showTypingBubble(isRecentTimestamp(data.agent_typing_at, 4) && data.status !== 'closed');
      }
    });
  }

  function enterChatActive(payload, wallet) {
    state.chatId = payload.chat_id;
    state.chatToken = payload.chat_token;
    state.chatStatus = payload.status || 'waiting';
    state.expiresTs = parseInt(payload.expires_ts, 10) || 0;
    bonusCheckTriggered = false;
    state.eligible = !!payload.eligible;
    state.bonusAmount = parseFloat(payload.bonus_amount) || 0;
    state.cooldownMessage = payload.bonus_cooldown_message || '';
    state.step = 'chat_active';
    saveState();

    appendServerMessages(payload.messages || []);
    if (wallet) updateWallet(wallet);

    if (payload.status === 'closed') {
      showClosedStep();
      return;
    }

    if (payload.compensation_awarded) {
      bannerEl.show().text('Bonus awarded.');
      statusEl.text('Waiting for agent...');
    } else if (payload.agent_replied_at || payload.status === 'active') {
      bannerEl.show().text('Agent connected. Bonus cancelled.');
      statusEl.text('Agent connected.');
    } else if (state.eligible && state.bonusAmount > 0) {
      bannerEl.show().text(`If no agent responds in ${SBC_CHAT.timeout} seconds, you get ${SBC_CHAT.currency}${state.bonusAmount} bonus.`);
      statusEl.text('Waiting for agent...');
    } else if (state.cooldownMessage) {
      bannerEl.show().text(state.cooldownMessage);
      timerEl.text('Bonus cooldown active');
      statusEl.text('Waiting for agent...');
    } else {
      bannerEl.show().text('Waiting for agent...');
      statusEl.text('Waiting for agent...');
    }

    showChatActiveStep();
    if (state.eligible && state.expiresTs > 0) startCountdown();
    startPolling();
    startBackgroundPolling();
  }

  function startChatFromDetails(detailsText, attempt) {
    attempt = Number(attempt) || 0;
    const sendBtn = $('#sbc-send');
    const inputField = getInputField();

    sendBtn.prop('disabled', true).text('Starting...');
    $('.sbc-transaction-option').prop('disabled', true);

    const request = $.post(SBC_CHAT.ajaxUrl, {
      action: 'sbc_start_chat',
      nonce: SBC_CHAT.nonce,
      chat_id: state.chatId,
      chat_token: state.chatToken,
      email: state.email,
      service: state.service,
      initial_message: detailsText
      ,transaction_id: state.transactionId || 0
      ,complaint_reason: state.transactionId ? 'Selected transaction complaint' : 'Direct agent request'
    }, function (res) {
      sendBtn.prop('disabled', false).text('Start Chat');

      if (!res || !res.success) {
        const message = (res && res.data && res.data.message) ? res.data.message : 'Could not send this complaint to support.';
        pushMessage('system', message + ' Please try again.');
        $('.sbc-transaction-option').prop('disabled', false);
        return;
      }

      inputField.val('');
      enterChatActive(res.data, res.data.wallet);
    });

    request.fail(function (xhr) {
      const statusCode = Number(xhr && xhr.status) || 0;
      const raw = String((xhr && xhr.responseText) || '').replace(/^\uFEFF/, '').trim();
      const jsonStart = raw.indexOf('{"success"');
      const jsonEnd = raw.lastIndexOf('}');
      if (jsonStart >= 0 && jsonEnd > jsonStart) {
        try {
          const recovered = JSON.parse(raw.slice(jsonStart, jsonEnd + 1));
          if (recovered && recovered.success && recovered.data) {
            sendBtn.prop('disabled', false).text('Start Chat');
            inputField.val('');
            enterChatActive(recovered.data, recovered.data.wallet);
            return;
          }
          if (recovered && recovered.data && recovered.data.message) {
            sendBtn.prop('disabled', false).text('Start Chat');
            $('.sbc-transaction-option').prop('disabled', false);
            pushMessage('system', recovered.data.message + ' Please try again.');
            return;
          }
        } catch (ignored) {}
      }
      if (attempt < 1 && (statusCode === 0 || statusCode === 200 || statusCode >= 500)) {
        setTimeout(function () { startChatFromDetails(detailsText, attempt + 1); }, 900);
        return;
      }
      sendBtn.prop('disabled', false).text('Start Chat');
      $('.sbc-transaction-option').prop('disabled', false);
      const response = xhr && xhr.responseJSON;
      let message = response && response.data && response.data.message ? response.data.message : '';
      if (!message && statusCode === 403) {
        message = 'Your support security session expired. Refresh this page and try again.';
      } else if (!message && statusCode >= 500) {
        message = `The support server returned error ${statusCode}. Please inform the administrator.`;
      } else if (!message && statusCode === 200) {
        message = 'The support server returned an invalid response. Please inform the administrator.';
      } else if (!message) {
        message = 'The complaint could not reach support because the connection was interrupted.';
      }
      pushMessage('system', message + ' Please try again.');
    });
  }

  function sendCustomerMessage(msg) {
    const sendBtn = $('#sbc-send');
    const inputField = getInputField();

    sendBtn.prop('disabled', true).text('Sending...');

    $.post(SBC_CHAT.ajaxUrl, {
      action: 'sbc_send_message',
      nonce: SBC_CHAT.nonce,
      chat_id: state.chatId,
      chat_token: state.chatToken,
      message: msg
    }, function (res) {
      sendBtn.prop('disabled', false).text('Send');

      if (!res || !res.success) {
        alert((res && res.data && res.data.message) ? res.data.message : 'Could not send message.');
        return;
      }

      inputField.val('');
      inputField.focus();
      appendServerMessages(res.data.messages || []);
    });
  }

  function endChat() {
    if (!state.chatId || !state.chatToken) return;

    $.post(SBC_CHAT.ajaxUrl, {
      action: 'sbc_end_chat',
      nonce: SBC_CHAT.nonce,
      chat_id: state.chatId,
      chat_token: state.chatToken
    }, function (res) {
      if (!res || !res.success) {
        alert((res && res.data && res.data.message) ? res.data.message : 'Could not end chat.');
        return;
      }

      appendServerMessages(res.data.messages || []);
      clearInterval(countdown);
      clearInterval(poller);
      showClosedStep();
    });
  }

  function resetConversation() {
    clearTimers();
    clearInterval(bgPoller);
    localStorage.removeItem(storageKey);
    state = defaultState();
    saveState();
    renderMessages();
    loadSupportContext();
  }

  function sendTypingPing() {
    if (!state.chatId || !state.chatToken || state.step !== 'chat_active') return;

    const now = Date.now();
    if (now - typingPingAt < 2000) return;
    typingPingAt = now;

    $.post(SBC_CHAT.ajaxUrl, {
      action: 'sbc_customer_typing',
      nonce: SBC_CHAT.nonce,
      chat_id: state.chatId,
      chat_token: state.chatToken
    });
  }

  function requestWithdrawal() {
    if (!state.chatId || !state.chatToken) return;

    $.post(SBC_CHAT.ajaxUrl, {
      action: 'sbc_request_withdrawal',
      nonce: SBC_CHAT.nonce,
      chat_id: state.chatId,
      chat_token: state.chatToken
    }, function (res) {
      if (!res || !res.success) {
        alert((res && res.data && res.data.message) ? res.data.message : 'Could not request withdrawal.');
        return;
      }

      updateWallet(res.data.wallet);
      walletNoteEl.text('Withdrawal request submitted.');
    });
  }

  function initConversationIfNeeded() {
    renderMessages();
    state.unreadBadge = 0;
    saveState();
    updateOpenBadge();

    if (SBC_CHAT.loggedIn && state.wallet) updateWallet(state.wallet);
    if (state.cooldownMessage) bannerEl.show().text(state.cooldownMessage);

    if (state.step === 'closed' || state.chatStatus === 'closed') {
      showClosedStep();
      return;
    }

    if (!SBC_CHAT.loggedIn || state.step === 'ask_email') {
      loadSupportContext();
      return;
    }

    if (state.step === 'confirm_name') {
      setActions(`
        <button type="button" class="sbc-option-btn" data-action="confirm" data-value="yes">Yes</button>
        <button type="button" class="sbc-option-btn" data-action="confirm" data-value="no">No</button>
      `);
      setInput('hidden');
      return;
    }

    if (state.step === 'choose_service') {
      showServiceStep();
      return;
    }

    if (state.step === 'choose_transaction') {
      showRecentTransactions(state.service);
      return;
    }

    if (state.step === 'ask_details') {
      showDetailsStep();
      return;
    }

    if (state.step === 'chat_active') {
      showChatActiveStep();
      updateWallet(state.wallet);
      if (state.chatId && state.chatToken) {
        refreshStatus();
        startPolling();
        startBackgroundPolling();
      }
      return;
    }
  }

  openBtn.on('click', function () {
    panel.toggle();

    if (panel.is(':visible')) {
      panel.addClass('sbc-open-anim');
      initConversationIfNeeded();
    } else {
      stopPollingOnly();
      clearInterval(countdown);
    }
  });

  minimizeBtn.on('click', function () {
    panel.hide();
    stopPollingOnly();
    clearInterval(countdown);
  });

  soundToggleBtn.on('click', function () {
    soundEnabled = !soundEnabled;
    localStorage.setItem('sbc_sound_enabled', soundEnabled ? '1' : '0');
    soundToggleBtn.text(soundEnabled ? '🔔' : '🔕');
    soundToggleBtn.toggleClass('sbc-muted', !soundEnabled);
  });

  jumpBtn.on('click', function () {
    scrollToBottom();
  });

  messagesEl.on('scroll', function () {
    if (isNearBottom()) jumpBtn.hide();
  });

  actionsEl.on('click', 'button', function () {
    const action = $(this).data('action');
    const value = $(this).data('value');

    if (action === 'restart') {
      resetConversation();
      return;
    }

    if (action === 'cancel') {
      panel.hide();
      stopPollingOnly();
      clearInterval(countdown);
      return;
    }

    if (action === 'transaction_page') {
      showRecentTransactions(state.service, Number(value));
      return;
    }

    if (action === 'confirm') {
      if (value === 'yes') {
        pushMessage('user', 'Yes');
        state.step = 'choose_service';
        saveState();
        showServiceStep();
      } else {
        pushMessage('user', 'No');
        state = defaultState();
        saveState();
        pushMessage('system', 'Okay, please provide the correct email used to register.');
        showEmailStep();
      }
      return;
    }

    if (action === 'service') {
      const labelMap = { other: 'Talk to an Agent' };
      (SBC_CHAT.complaintServices || []).forEach(item => { labelMap[item.key] = item.label; });

      state.service = value;
      transactionPage = 1;
      saveState();

      pushMessage('user', labelMap[value] || value);
      if (value === 'other') {
        state.transactionId = 0;
        showDetailsStep();
      } else {
        showRecentTransactions(value);
      }
      return;
    }

    if (action === 'transaction') {
      const tx = recentTransactions.find(item => Number(item.id) === Number(value));
      if (!tx) return;
      state.transactionId = Number(tx.id);
      saveState();
      $(this).prop('disabled', true);
      const title = tx.plan || tx.network || tx.service;
      pushMessage('user', `${title} • ${SBC_CHAT.currency}${Number(tx.amount).toFixed(2)} • ${tx.recipient}`);
      pushMessage('system', 'Your transaction has been attached. We are connecting you to an agent now.');
      startChatFromDetails(`Support request for selected ${tx.service} transaction #${tx.id}`);
    }
  });

  actionsEl.on('click', '#sbc-new-chat', function () {
    resetConversation();
  });

  actionsEl.on('click', '.sbc-star', function () {
    const val = Number($(this).data('star'));
    $('#sbc-rating-stars .sbc-star').each(function () {
      $(this).toggleClass('active', Number($(this).data('star')) <= val);
    });
  });

  actionsEl.on('mouseenter', '.sbc-star', function () {
    const val = Number($(this).data('star'));
    $('#sbc-rating-stars .sbc-star').each(function () {
      $(this).toggleClass('hover', Number($(this).data('star')) <= val);
    });
  });

  actionsEl.on('mouseleave', '#sbc-rating-stars', function () {
    $('#sbc-rating-stars .sbc-star').removeClass('hover');
  });

  actionsEl.on('click', '.sbc-star', function () {
    submitRating(Number($(this).data('star')));
  });

  $(document).on('click', '#sbc-send', function () {
    const inputField = getInputField();
    const val = inputField.val().trim();
    if (!val) return;

    if (state.step === 'ask_email') {
      const sendBtn = $('#sbc-send');
      sendBtn.prop('disabled', true).text('Checking...');

      $.post(SBC_CHAT.ajaxUrl, {
        action: 'sbc_lookup_email',
        nonce: SBC_CHAT.nonce,
        email: val
      }, function (res) {
        sendBtn.prop('disabled', false).text('Continue');

        if (!res || !res.success) {
          pushMessage('system', (res && res.data && res.data.message) ? res.data.message : 'Email not found. Please try again.');
          setInput('email', 'Enter your email', 'Continue', false);
          return;
        }

        state.email = res.data.email;
        state.fullName = res.data.full_name;
        state.userId = res.data.user_id;
        state.wallet = res.data.wallet;
        saveState();

        pushMessage('user', val);

        // If this person already has a chat waiting for or being handled by
        // an agent, jump straight back into it instead of re-running the
        // whole intake flow again.
        if (res.data.existing_chat && res.data.existing_chat.status !== 'closed') {
          pushMessage('system', 'Welcome back — reconnecting you to your existing chat.');
          enterChatActive(res.data.existing_chat, res.data.wallet);
          return;
        }

        updateWallet(res.data.wallet);
        showConfirmStep(res.data.full_name);
      });

      return;
    }

    if (state.step === 'ask_details') {
      if (!state.email || !state.service) {
        alert('Please complete the earlier steps.');
        return;
      }
      startChatFromDetails(val);
      return;
    }

    if (state.step === 'chat_active') {
      if (!state.chatId || !state.chatToken) return;
      sendCustomerMessage(val);
    }
  });

  $(document).on('click', '#sbc-end-chat', function () {
    endChat();
  });

  $(document).on('click', '#sbc-withdraw', function () {
    requestWithdrawal();
  });

  $(document).on('input', '#sbc-input-field', function () {
    if (state.step === 'chat_active' && $(this).val().trim().length) {
      sendTypingPing();
    }
  });

  $(document).on('keydown', '#sbc-input-field', function (e) {
    const tag = $(this).prop('tagName').toLowerCase();
    if (tag !== 'textarea' && e.key === 'Enter') {
      e.preventDefault();
      $('#sbc-send').click();
    }
  });

  setInterval(function () {
    if (SBC_CHAT.resetVersion && parseInt(SBC_CHAT.resetVersion, 10) !== currentResetVersion) {
      hardResetFrontend(SBC_CHAT.resetVersion);
    }
  }, 4000);

  renderMessages();
  initConversationIfNeeded();
  saveState();
});
