(function($){
  'use strict';

  if (typeof window.WPSNAudit === 'undefined') {
    return;
  }

  var cfg = window.WPSNAudit;
  var sqlOnly = !!(cfg && cfg.sqlOnly);

  var i18n = (cfg && cfg.i18n) ? cfg.i18n : {};
  var LABEL_CANCEL = i18n.cancel || 'Cancel scan';
  var LABEL_CANCELLING = i18n.cancelling || 'Cancelling…';
  var MSG_CONFIRM_CANCEL = i18n.confirm_cancel || 'Cancel this audit scan?';
  var LABEL_CANCELLED = i18n.cancelled || 'cancelled';
  var TEXT_PENDING_REMOVED = i18n.pending_jobs_removed || 'Cancelled. Pending jobs removed:';
  var MSG_SELECT_NONE = i18n.select_none || 'Select at least one row first.';

  var state = {
    scanId: parseInt(cfg.currentScanId || 0, 10) || 0,
    running: false,
    timer: null,
    backoffMs: 0,
    startMode: 'normal',
    lastDoneCount: -1,
    lastProgressTs: 0,
    pumpMode: false
  };

  function resetBackoff() {
    state.backoffMs = 0;
  }

  function nextBackoff() {
    var base = 4000;
    if (!state.backoffMs || state.backoffMs < base) {
      state.backoffMs = base;
    } else {
      // Be extra gentle on shared hosting / incidents.
      state.backoffMs = Math.min(state.backoffMs * 2, 120000);
    }
    return state.backoffMs;
  }


  function errorFromData(data, fallback) {
    var msg = fallback || 'Request failed';
    if (data && typeof data.message !== 'undefined' && data.message) {
      msg = data.message.toString();
    }
    if (data && typeof data.debug_output !== 'undefined' && data.debug_output) {
      msg += ' — ' + data.debug_output.toString();
    } else if (data && typeof data.hint !== 'undefined' && data.hint) {
      msg += ' — ' + data.hint.toString();
    }
    return msg;
  }

  function xhrErrorMessage(xhr, fallback) {
    var msg = fallback || 'Request failed';

    if (xhr && xhr.responseJSON && xhr.responseJSON.data) {
      return errorFromData(xhr.responseJSON.data, msg);
    }

    if (xhr && typeof xhr.responseText === 'string' && xhr.responseText) {
      var t = xhr.responseText;
      // Strip HTML tags (best-effort) + collapse whitespace.
      t = t.replace(/<[^>]*>/g, ' ');
      t = t.replace(/\s+/g, ' ').trim();
      if (t) {
        msg = t.substring(0, 200);
      }
    }

    if (xhr && xhr.status) {
      msg += ' (HTTP ' + xhr.status + ')';
    }
    return msg;
  }

  function qsUpdate(url, params) {
    try {
      var u = new URL(url, window.location.origin);
      Object.keys(params || {}).forEach(function(k){
        if (params[k] === null || typeof params[k] === 'undefined' || params[k] === '') {
          u.searchParams.delete(k);
        } else {
          u.searchParams.set(k, params[k]);
        }
      });
      return u.toString();
    } catch (e) {
      return url;
    }
  }

  function setProgress(pct) {
    $('#wpsn-audit-scan-progress-bar').css('width', (pct || 0) + '%');
  }

  function showProgress() {
    $('#wpsn-audit-scan-progress').show();
  }

  function hideError() {
    $('#wpsn-audit-scan-progress-error').hide().text('');
  }

  function showError(msg) {
    if (!msg) return;
    $('#wpsn-audit-scan-progress-error').show().text(msg);
  }

  function setText(meta, text) {
    $('#wpsn-audit-scan-progress-meta').text(meta || '');
    $('#wpsn-audit-scan-progress-text').text(text || '');
  }

  function enableUI(isBusy) {
    if (isBusy) {
      $('#wpsn-audit-scan-spinner').addClass('is-active');
      $('#wpsn-audit-scan-submit').prop('disabled', true);
      $('#wpsn-audit-scan-submit-light').prop('disabled', true);
      $('#wpsn-audit-scan-submit-fast').prop('disabled', true);
      $('#wpsn-audit-scan-submit-sql').prop('disabled', true);
    } else {
      $('#wpsn-audit-scan-spinner').removeClass('is-active');
      $('#wpsn-audit-scan-submit').prop('disabled', false);
      $('#wpsn-audit-scan-submit-light').prop('disabled', false);
      $('#wpsn-audit-scan-submit-fast').prop('disabled', false);
      $('#wpsn-audit-scan-submit-sql').prop('disabled', false);
    }
  }

  function stopLoop() {
    state.running = false;
    if (state.timer) {
      clearTimeout(state.timer);
      state.timer = null;
    }

    $('#wpsn-audit-scan-cancel').hide().removeClass('disabled').text(LABEL_CANCEL);
  }

  function scheduleNext(delayMs) {
    stopLoop();
    state.running = true;
    state.timer = setTimeout(pollOnce, delayMs || 15000);

    if (state.scanId) {
      $('#wpsn-audit-scan-cancel').show().removeClass('disabled');
    }
  }

  function ajaxPost(action, data) {
    return $.ajax({
      url: cfg.ajaxUrl,
      method: 'POST',
      dataType: 'json',
      data: $.extend({
        action: action,
        nonce: cfg.nonce
      }, data || {})
    });
  }

  function formatStatus(res) {
    var status = (res.status || '').toString();
    var phase = (res.phase || '').toString();
    var scannedPosts = parseInt(res.scanned_posts || 0, 10) || 0;
    var scannedTerms = parseInt(res.scanned_terms || 0, 10) || 0;
    var totalPosts = parseInt(res.total_posts || 0, 10) || 0;
    var totalTerms = parseInt(res.total_terms || 0, 10) || 0;
    var issues = typeof res.issues_found !== 'undefined' ? (parseInt(res.issues_found || 0, 10) || 0) : null;
    var pct = parseInt(res.pct || 0, 10) || 0;

    var queuePaused = !!(res.queue_paused);
    var nextTickUtc = (res.queue_next_tick_utc || '').toString();

    var meta = 'Scan #' + state.scanId;
    if (status) meta += ' · ' + status;
    if (phase && phase !== status) meta += ' (' + phase + ')';
    meta += ' · ' + pct + '%';

    var text = 'Posts: ' + scannedPosts + '/' + totalPosts + ' · Terms: ' + scannedTerms + '/' + totalTerms;
    if (issues !== null) {
      text += ' · Issues found: ' + issues;
    }
    if (res.processed_jobs) {
      text += ' · Worker: +' + res.processed_jobs + ' jobs';
    }

    if (queuePaused) {
      text += ' · Queue: paused';
    } else if (nextTickUtc) {
      // Display only HH:MM UTC to keep the UI compact.
      var m = nextTickUtc.match(/T(\d\d):(\d\d):\d\d/);
      if (m && m[1] && m[2]) {
        text += ' · Next tick: ' + m[1] + ':' + m[2] + ' UTC';
      }
    }

    return { meta: meta, text: text, pct: pct };
  }

  function pollOnce() {
    if (!state.scanId) return;

    // If we see no progress for a while, enable “pump mode”: ask the server
    // to do a tiny amount of work AFTER the response is sent.
    var now = Date.now();
    if (!state.lastProgressTs) {
      state.lastProgressTs = now;
    }
    if (!state.pumpMode && state.lastDoneCount >= 0 && (now - state.lastProgressTs) > 45000) {
      state.pumpMode = true;
    }

    ajaxPost('wpsn_audit_scan_status', { scan_id: state.scanId, pump: state.pumpMode ? 1 : 0 })
      .done(function(resp){
        if (!resp || !resp.success || !resp.data) {
          showError(errorFromData((resp && resp.data) ? resp.data : null, 'Unknown error'));
          enableUI(false);
          stopLoop();
          return;
        }

        hideError();
        resetBackoff();
        showProgress();

        var fmt = formatStatus(resp.data);
        setProgress(fmt.pct);
        setText(fmt.meta, fmt.text);

        var doneCount = (parseInt(resp.data.scanned_posts || 0, 10) || 0) + (parseInt(resp.data.scanned_terms || 0, 10) || 0);
        if (state.lastDoneCount < 0) {
          state.lastDoneCount = doneCount;
          state.lastProgressTs = Date.now();
        } else if (doneCount > state.lastDoneCount) {
          state.lastDoneCount = doneCount;
          state.lastProgressTs = Date.now();
          state.pumpMode = false; // progress resumed
        }

        if (resp.data.queue_paused) {
          showError('Queue is paused — resume it in Queue Center to continue.');
        } else if (resp.data.error_message) {
          showError(resp.data.error_message);
        }

        if (resp.data.done) {
          enableUI(false);
          stopLoop();
          $('#wpsn-audit-scan-refresh').show();
          if (resp.data.status === 'completed') {
            setProgress(100);
          }
          return;
        }

        // Status polling interval (gentle). If pumpMode is enabled, keep it modest.
        scheduleNext(state.pumpMode ? 20000 : 15000);
      })
      .fail(function(xhr){
        enableUI(false);
        var msg = xhrErrorMessage(xhr);

        // Transient server busy / rate limit errors are common on shared hosting.
        // Instead of stopping, back off and retry.
        if (xhr && (xhr.status === 503 || xhr.status === 429)) {
          var delay = nextBackoff();
          showError(msg + ' — retry in ' + Math.round(delay / 1000) + 's');
          scheduleNext(delay);
          return;
        }

        stopLoop();
        showError(msg);
      });
  }

  function startScan(includeTerms, checkSocial, mode) {
    hideError();
    enableUI(true);
    showProgress();
    setProgress(0);
    var m = (mode || 'normal').toString();
    var suffix = '';
    if (m === 'light') suffix = ' (light mode)';
    if (m === 'fast') suffix = ' (fast mode)';
    setText('Starting…', 'Scheduling scan jobs…' + suffix);

    ajaxPost('wpsn_audit_scan_start', {
      include_terms: includeTerms ? 1 : 0,
      check_social: checkSocial ? 1 : 0,
      scan_mode: m
    }).done(function(resp){
      if (!resp || !resp.success || !resp.data) {
        enableUI(false);
        showError(errorFromData((resp && resp.data) ? resp.data : null, 'Failed to start scan'));
        return;
      }

      state.scanId = parseInt(resp.data.scan_id || 0, 10) || 0;
      if (!state.scanId) {
        enableUI(false);
        showError('Missing scan_id');
        return;
      }

      // Update URL so export/history works right.
      try {
        var newUrl = qsUpdate(window.location.href, { scan_id: state.scanId });
        window.history.replaceState({}, '', newUrl);
      } catch (e) {}

      $('#wpsn-audit-scan-refresh').hide();
      enableUI(false);

      // Start gentle polling loop.
      state.lastDoneCount = -1;
      state.lastProgressTs = 0;
      state.pumpMode = false;
      scheduleNext(1200);
    }).fail(function(xhr){
      enableUI(false);
      var msg = xhrErrorMessage(xhr);
      showError(msg);
    });
  }

  function maybeResume(scanId) {
    if (!scanId) return;
    ajaxPost('wpsn_audit_scan_status', { scan_id: scanId })
      .done(function(resp){
        if (!resp || !resp.success || !resp.data) {
          return;
        }
        if (resp.data.status === 'running') {
          state.scanId = scanId;
          showProgress();
          var fmt = formatStatus(resp.data);
          setProgress(fmt.pct);
          setText(fmt.meta, fmt.text);
          $('#wpsn-audit-scan-refresh').hide();
          state.lastDoneCount = -1;
          state.lastProgressTs = 0;
          state.pumpMode = false;
          scheduleNext(1500);
        }
      });
  }

  $(function(){
    if (!sqlOnly) {
    // Which mode button was pressed.
    $('#wpsn-audit-scan-submit').on('click', function(){
      state.startMode = 'normal';
    });
    $('#wpsn-audit-scan-submit-light').on('click', function(){
      state.startMode = 'light';
    });
    $('#wpsn-audit-scan-submit-fast').on('click', function(){
      state.startMode = 'fast';
    });
    $('#wpsn-audit-scan-submit-sql').on('click', function(){
      state.startMode = 'sql';
    });

    // Bind scan form.
    $('#wpsn-audit-scan-form').on('submit', function(e){
      var includeTerms = $('#wpsn-audit-include-terms').is(':checked');
      var checkSocial = $('#wpsn-audit-check-social').is(':checked');
      var mode = (state.startMode || 'normal');

      // SQL mode is a synchronous admin-post request (no AJAX).
      if (mode === 'sql') {
        enableUI(true);
        return;
      }

      e.preventDefault();
      startScan(includeTerms, checkSocial, mode);
    });

    $('#wpsn-audit-scan-refresh').on('click', function(e){
      e.preventDefault();
      window.location.reload();
    });

    $('#wpsn-audit-scan-cancel').on('click', function(e){
      e.preventDefault();
      if (!state.scanId) return;

      if (!window.confirm(MSG_CONFIRM_CANCEL)) {
        return;
      }

      var $btn = $(this);
      $btn.addClass('disabled').text(LABEL_CANCELLING);

      ajaxPost('wpsn_audit_scan_cancel', { scan_id: state.scanId })
        .done(function(resp){
          if (!resp || !resp.success || !resp.data) {
            $btn.removeClass('disabled').text(LABEL_CANCEL);
            showError(errorFromData((resp && resp.data) ? resp.data : null, 'Failed to cancel'));
            return;
          }

          enableUI(false);
          stopLoop();
          showProgress();
          hideError();

          var deleted = parseInt(resp.data.deleted_jobs || 0, 10) || 0;
          setText('Scan #' + state.scanId + ' · ' + LABEL_CANCELLED, TEXT_PENDING_REMOVED + ' ' + deleted);
          $('#wpsn-audit-scan-refresh').show();
        })
        .fail(function(xhr){
          $btn.removeClass('disabled').text(LABEL_CANCEL);
          var msg = xhrErrorMessage(xhr);
          showError(msg);
        });
    });


    } else {
      // SQL-only mode: submit scan form normally (admin-post). Show spinner while request runs.
      $('#wpsn-audit-scan-form').on('submit', function(){
        enableUI(true);
        return true;
      });
    }

    // Bulk selection (selected rows).
    var $selectAll = $('#wpsn-audit-select-all');
    var $rows = $('.wpsn-audit-row-check');
    var $count = $('#wpsn-audit-selected-count');

    function updateSelectedCount() {
      if (!$count.length) return;
      var n = $rows.filter(':checked').length;
      $count.text(n ? n.toString() : '0');
    }

    if ($selectAll.length && $rows.length) {
      $selectAll.on('change', function(){
        var checked = $(this).is(':checked');
        $rows.prop('checked', checked);
        updateSelectedCount();
      });

      $rows.on('change', function(){
        var checkedCount = $rows.filter(':checked').length;
        $selectAll.prop('checked', checkedCount === $rows.length);
        updateSelectedCount();
      });

      updateSelectedCount();
    }

    $('#wpsn-audit-selected-form').on('submit', function(e){
      if ($rows.filter(':checked').length < 1) {
        e.preventDefault();
        window.alert(MSG_SELECT_NONE);
        return false;
      }
      return true;
    });

        // If page opened for a running scan, resume.
    if (!sqlOnly && state.scanId > 0) {
      maybeResume(state.scanId);
    }
  });

})(jQuery);
