/* globals jQuery:true, ajaxurl:true, sn_unblock_ui:true, wf_sn_ms:true */
/*
 * Security Ninja - Malware Scanner add-on
 * (c) 2015. Web factory Ltd
 */

function pad(val) {
  var valString = val + "";
  if (valString.length < 2) {
    return "0" + valString;
  } else {
    return valString;
  }
}

var msminutesLabel = document.getElementById("mscounterminutes");
var mssecondsLabel = document.getElementById("mscounterseconds");
var totalSeconds = 0;
var timerInterval; // Variable to hold the timer interval

// FOR THE SECOND COUNTER ON THE OVERLAY
function updateTimeCounter() {
  ++totalSeconds;
  mssecondsLabel.innerHTML = pad(totalSeconds % 60);
  msminutesLabel.innerHTML = pad(parseInt(totalSeconds / 60));
}

var actions = [
  {msg1: 'Cleaning cache ... ', msg2: ' DONE!', action: 'clean_cache'},
  {msg1: 'Checking malware definitions', msg2: 'DONE!', action: 'update_samples'},
  {msg1: 'Checking plugins for modifications', msg2: 'DONE!', action: 'do_integrity_scan'},
  // {msg1: 'Scanning database for malicious code', msg2: 'DONE!', action: 'do_db_scan '},
  {msg1: 'Scanning website for malicious code', msg2: 'DONE!', action: 'do_mal_scan'},
  {msg1: 'Generating results ... ', msg2: 'DONE!', action: 'get_results'}
];

jQuery(document).ready(function($) {

  function updateMalwareTabBadge(count) {
    var $tab = $('#wf-sn-tabs a[href="#sn_malware"]');
    if (!$tab.length) {
      return;
    }
    $tab.find('.warn-count').remove();
    if (count && parseInt(count, 10) > 0) {
      $tab.append('<span class="warn-count">' + parseInt(count, 10) + '</span>');
    }
  }

  function getMsString(key, fallback) {
    if (wf_sn_ms.strings && wf_sn_ms.strings[key]) {
      return wf_sn_ms.strings[key];
    }
    return fallback;
  }

  function markScanFailedOnServer() {
    return jQuery.post(ajaxurl, {
      action: 'sn_ms_mark_scan_failed',
      _ajax_nonce: wf_sn_ms.nonce
    }, null, 'json');
  }

  function formatAjaxFailure(jqXHR, textStatus, step) {
    var parts = [];
    var base = getMsString('scan_ajax_failed', 'The malware scan request failed. The scan is incomplete — do not treat the site as clean. Reload and try again.');
    parts.push(base);
    if (step) {
      parts.push('Step: ' + step);
    }
    if (jqXHR && jqXHR.status) {
      parts.push('HTTP ' + jqXHR.status);
    }
    if (textStatus && textStatus !== 'error') {
      parts.push(textStatus);
    }
    if (jqXHR && typeof jqXHR.responseText === 'string' && jqXHR.responseText.length) {
      var snippet = jqXHR.responseText.replace(/\s+/g, ' ').trim().substring(0, 160);
      if (snippet) {
        parts.push(snippet);
      }
    }
    return parts.join(' — ');
  }

  // handle each individual ajax call
  function do_sn_ms_request(params) {
    var dfd = jQuery.Deferred();

    jQuery('#sn_ms_timer').slideDown(500);
    jQuery.ajax({
      type: 'POST',
      url: ajaxurl,
      data: {
        action: 'sn_ms_run_scan',
        what: params.action,
        _ajax_nonce: wf_sn_ms.nonce
      },
      dataType: 'json',
      success: function(response) {
        if (response && response.success === true) {
          jQuery('#msg_' + params.action).removeClass('pending').removeClass('current').removeClass('failed').addClass('passed');
          jQuery('.badge', '#msg_' + params.action).html(params.msg2.replace('%d', parseInt(response.data && response.data.cnt ? response.data.cnt : 0, 10)));

          if (params.action === 'get_results') {
            clearInterval(timerInterval); // Stop the timer
            jQuery('#sn_ms_timer').fadeOut(500); // Fade out the timer div

            jQuery('#sn_ms_results').append(response.data);
            sn_unblock_ui('#sn-malware-scanner');

            jQuery('.loader').show();

            // Re-enable the scan button
            jQuery('#sn_ms_run_scan').prop('disabled', false);
          }

          // Check for matched items and append results
          if (response.data && response.data.matchedItems) {
            appendScannerResults(response.data.matchedItems);
          }

          dfd.resolve(response);
          return;
        }

        var failMsg = getMsString('scan_invalid_response', 'Invalid scan response. The scan is incomplete — do not treat the site as clean. Reload and try again.');
        if (response && response.data) {
          if (typeof response.data === 'string') {
            failMsg = response.data;
          } else if (response.data.message) {
            failMsg = response.data.message;
          }
        }
        markScanFailedOnServer();
        SnDialog.alert({ message: failMsg });
        jQuery('#sn_ms_run_scan').prop('disabled', false);
        dfd.reject(response);
      },
      error: function(jqXHR, textStatus) {
        markScanFailedOnServer();
        SnDialog.alert({ message: formatAjaxFailure(jqXHR, textStatus, params.action) });
        jQuery('#sn_ms_run_scan').prop('disabled', false);
        dfd.reject(jqXHR);
      }
    });

    return dfd.promise();
  }

  // run test
  jQuery('#sn_ms_run_scan').on('click', function(e) {
    e.preventDefault();
    jQuery('#sn_ms_run_scan').prop('disabled', true);

    $('#sn_ms_results').show().html('');
    $('#scanstatus').html('');
    totalSeconds = 0;
    updateTimeCounter();
    timerInterval = setInterval(updateTimeCounter, 1000);

    let startingpoint = $.Deferred();
    startingpoint.resolve();

    $('.wrap .error').hide();

    $('.loader').hide();

    $.each(actions, function(i, action) {
      startingpoint = startingpoint.then(function() {
        var $actionRow = $('<div class="action-row" data-action="' + action.action + '" style="display: flex; align-items: center; gap: 12px; min-height: 28px;"></div>');
        var $actionMsg = $('<div id="msg_' + action.action + '" class="current" style="flex: 0 0 auto;">' + action.msg1 + ' <span class="badge">Working ...</span></div>');
        var $responseMsg = $('<div class="response-msg" style="flex: 1 1 40%; min-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"></div>');
        if (action.action === 'do_mal_scan') {
          $responseMsg.attr('id', 'sn_ms_progress').css({ maxWidth: '50%', fontFamily: 'monospace', fontSize: '12px' });
        }
        var $timer = $('<div class="action-timer" style="flex: 0 0 auto;">0s</div>');

        $actionRow.append($actionMsg).append($responseMsg).append($timer);
        $('#sn_ms_results').append($actionRow);

        var actionStartTime = Date.now();
        var actionTimerInterval = setInterval(function() {
          var elapsedSeconds = Math.floor((Date.now() - actionStartTime) / 1000);
          $timer.text(elapsedSeconds + 's');
        }, 1000);

        var progressInterval;
        if (action.action === 'do_mal_scan') {
          progressInterval = setInterval(function() {
            $.post(ajaxurl, {
              action: 'sn_ms_scan_progress',
              _ajax_nonce: wf_sn_ms.nonce
            }, function(res) {
              if (res.success && res.data) {
                var display = res.data.current_path_display || res.data.current_path || '';
                var filesScanned = res.data.files_scanned != null ? res.data.files_scanned : '';
                var dirsScanned = res.data.directories_scanned != null ? res.data.directories_scanned : '';
                if (display || filesScanned !== '' || dirsScanned !== '') {
                  var countText = '';
                  if (filesScanned !== '' && dirsScanned !== '') {
                    countText = ' (' + Number(filesScanned).toLocaleString() + ' files, ' + Number(dirsScanned).toLocaleString() + ' dirs)';
                  }
                  $('#sn_ms_progress').text('Scanning: ' + (display || '…') + countText).attr('title', res.data.current_path || display);
                }
              }
            }, 'json');
          }, 10000);
        }

        return do_sn_ms_request(action).done(function(response) {
          $actionMsg.removeClass('current').removeClass('failed').addClass('passed');
          $timer.text('Completed in ' + Math.floor((Date.now() - actionStartTime) / 1000) + 's');

          if (response.data && response.data.msg) {
            $responseMsg.html( response.data.msg );
          }
        }).fail(function() {
          $actionMsg.removeClass('current').removeClass('passed').addClass('failed');
          $timer.text('Failed after ' + Math.floor((Date.now() - actionStartTime) / 1000) + 's');
          $responseMsg.text(getMsString('scan_step_failed', 'This scan step failed. The scan is incomplete — do not treat the site as clean.'));
        }).always(function() {
          if (action.action === 'do_mal_scan' && progressInterval) {
            clearInterval(progressInterval);
            $('#sn_ms_progress').text('');
          }
          clearInterval(actionTimerInterval);
        });
      });
    });

    startingpoint.done(function() {
      clearInterval(timerInterval);
      $('#sn_ms_timer').append('<div class="total-time" style="text-align: right;">Total Time: ' + pad(parseInt(totalSeconds / 60)) + ':' + pad(totalSeconds % 60) + '</div>');
      // Re-enable scan button when full chain completes (backup if get_results success did not run)
      jQuery('#sn_ms_run_scan').prop('disabled', false);
    });

    startingpoint.fail(function() {
      clearInterval(timerInterval);
      // Re-enable scan button when any step in the chain fails
      jQuery('#sn_ms_run_scan').prop('disabled', false);
    });

    $('.wf-sn-ms-not-run').hide();
  });

  // .sn-malware-title
  $('.secnin_content_wrapper').on('click', '.toggle-slide', function(e) {
    e.preventDefault();

    let content = $(this).parents('.sn-malware-filebox').find('.sn-malware-file-code');
    $(this).toggleClass('opened');
    $(content).slideToggle(500);
  });

  // reset files whitelist
  $('#sn_malware').on('click', '#sn-ms-reset-whitelist', function(e) {
    e.preventDefault();

    SnDialog.confirm({
      message: 'Are you sure you want to reset the whitelisted files list?\nPlease rescan files after cleaning the whitelist.',
      danger: true
    }).then(function(ok) {
      if (!ok) {
        return;
      }
      $.post(ajaxurl, {
        _ajax_nonce: wf_sn_ms.nonce,
        action: 'sn_ms_reset_whitelist'
      },
      function() {
        window.location.reload();
      });
    });
  }); // reset files whitelist

  // reset scan results
  $('#sn_malware').on('click', '#sn-ms-reset-results', function(e) {
    e.preventDefault();

    SnDialog.confirm({
      message: 'Clear all scan results? You will need to run a new scan to see results again.',
      danger: true
    }).then(function(ok) {
      if (!ok) {
        return;
      }
      $.post(ajaxurl, {
        _ajax_nonce: wf_sn_ms.nonce,
        action: 'sn_ms_reset_results'
      }, function() {
        window.location.reload();
      }, 'json').fail(function() {
        SnDialog.alert({ message: 'Failed to reset results. Please reload the page and try again.' });
      });
    });
  }); // reset scan results

  // Whitelist all flagged files
  $('#sn_malware').on('click', '#sn-ms-whitelist-all', function(e) {
    e.preventDefault();

    var confirmMsg = (wf_sn_ms.strings && wf_sn_ms.strings.whitelist_all_confirm)
      ? wf_sn_ms.strings.whitelist_all_confirm
      : 'Whitelist all currently flagged files?';

    var $btn = $(this);

    SnDialog.confirm({
      message: confirmMsg
    }).then(function(ok) {
      if (!ok) {
        return;
      }

      $btn.prop('disabled', true);

      $.post(ajaxurl, {
        _ajax_nonce: wf_sn_ms.nonce,
        action: 'sn_ms_whitelist_all'
      }, function(response) {
        if (response.success) {
          if (response.data && response.data.fresh_output) {
            updateMalwareScannerUI(response);
            if (response.data.suspicious_count !== undefined) {
              updateMalwareTabBadge(response.data.suspicious_count);
            }
          } else {
            window.location.reload();
          }
        } else {
          var failMsg = (response.data && response.data.message) ? response.data.message : 'Could not whitelist all files. Please try again.';
          if (wf_sn_ms.strings && wf_sn_ms.strings.whitelist_all_failed) {
            failMsg = wf_sn_ms.strings.whitelist_all_failed;
          }
          SnDialog.alert({ message: failMsg });
          $btn.prop('disabled', false);
        }
      }, 'json').fail(function() {
        var failMsg = 'Could not whitelist all files. Please try again.';
        if (wf_sn_ms.strings && wf_sn_ms.strings.whitelist_all_failed) {
          failMsg = wf_sn_ms.strings.whitelist_all_failed;
        }
        SnDialog.alert({ message: failMsg });
        $btn.prop('disabled', false);
      });
    });
  });

  // whitelist file
  $('#sn_malware').on('click', 'button.sn_ms_whitelist', function(e) {
    e.preventDefault();

    let $btn = $(this);

    SnDialog.confirm({
      message: 'Are you sure you want to whitelist this file?\n\nPlease reload page to see all changes.'
    }).then(function(ok) {
      if (!ok) {
        return;
      }

      $.post(ajaxurl, {
        action: 'sn_ms_whitelist_file',
        hash: $btn.data('hash'),
        nonce: $btn.data('nonce'),
        filename: $btn.data('filename'),
        _ajax_nonce: wf_sn_ms.nonce
      },
      function(response) {
        if (response.success) {
          SnDialog.alert({
            message: 'The file has been successfully added to the whitelist. The list has been updated.'
          }).then(function() {
            window.location.reload();
          });
        } else {
          SnDialog.alert({
            message: 'Error: ' + (response.data && response.data.message ? response.data.message : 'Could not add the file to the whitelist.')
          });
        }
      },
      'json');
    });
  });

  // Revert whitelisting a file
  $('#sn_malware').on('click', 'button.sn_ms_revert_whitelist', function(e) {
    e.preventDefault();

    let $btn = $(this);

    SnDialog.confirm({
      message: 'Are you sure you want to no longer whitelist this file?\n\nPlease reload page to see all changes.'
    }).then(function(ok) {
      if (!ok) {
        return;
      }

      $.post(ajaxurl, {
        action: 'revert_whitelist_btn',
        hash: $btn.data('hash'),
        nonce: $btn.data('nonce'),
        filename: $btn.data('filename'),
        _ajax_nonce: wf_sn_ms.nonce
      },
      function(response) {
        if (response.success) {
          SnDialog.alert({
            message: 'The file has been successfully removed from the whitelist. The list has been updated.'
          }).then(function() {
            window.location.reload();
          });
        } else {
          SnDialog.alert({
            message: 'Error: ' + (response.data && response.data.message ? response.data.message : 'Could not remove the file from the whitelist.')
          });
        }
      },
      'json').fail(function(jqXHR, textStatus, errorThrown) {
        SnDialog.alert({ message: 'Request failed: ' + textStatus + '. ' + errorThrown });
      });
    });
  });

  // delete file
  $('#sn_ms_results').on('click', 'button.sn_ms_delete', function(e) {
    e.preventDefault();

    let button = this;
    let $btn = $(this);

    SnDialog.confirm({
      message: 'Are you sure you want to delete this file?\n\nThere is NO undo!\n\nThis can break functionality or your site from functioning.\n\n' + $btn.data('filename'),
      danger: true
    }).then(function(ok) {
      if (!ok) {
        return;
      }

      $.post(ajaxurl, {
        action: 'sn_ms_delete_file',
        filename: $btn.data('filename'),
        hash: $btn.data('hash'),
        nonce: $btn.data('nonce'),
        _ajax_nonce: wf_sn_ms.nonce
      },
      function(response) {
        if (typeof response.success == 'undefined') {
          SnDialog.alert({ message: 'Undocumented error. File was not deleted. Please reload the page.' });
        } else if (response.success == true) {
          var $row = $(button).closest('tr');
          $row.addClass('sn-ms-row-processing').slideUp(500, function() {
            $(this).remove();
          });

          updateMalwareScannerUI(response);

          SnDialog.alert({ message: 'File deleted! The list has been updated.' });
        } else {
          SnDialog.alert({ message: 'Your file access properties do not allow us to delete the file (this is not a bad thing). Please delete it manually, via FTP.' });
        }
      },
      'json');
    });
  }); // Delete a file

  // view file
  $('#sn_ms_results').on('click', '.sn_ms_view_file', function(e) {
    e.preventDefault();
    if (typeof $(this).data('href') !== 'undefined') {
      const href = $(this).data('href');
      try {
        new URL(href); // This will throw an error if the URL is invalid
        window.open(href);
      } catch (e) {
        console.error('Invalid URL:', href);
      }
      return;
    }
  });

  /**
   * Updates the malware scanner results UI with fresh data
   *
   * @param {Object} response - AJAX response containing fresh_output and suspicious_count
   */
  function updateMalwareScannerUI(response) {
    if (!response.data || !response.data.fresh_output) {
      return;
    }
    var $wrap = $('#sn_ms_scan_findings');
    if ($wrap.length) {
      $wrap.html(response.data.fresh_output);
    } else {
      // Legacy markup without wrapper: prepend only — avoid removing whitelist / integrity sections.
      $('#sn_ms_results').prepend(response.data.fresh_output);
    }
    if (response.data.suspicious_count !== undefined) {
      updateMalwareTabBadge(response.data.suspicious_count);
    }
  }

  /**
   * Generates HTML output for malware scanner results and appends it to the results list.
   *
   * @param {Array} results - Array of result objects from the malware scanner.
   * Each result object should have the following properties:
   * - scanner: The name of the scanner (e.g., 'File Scanner', 'DB Scanner').
   * - filename: The name of the file (if applicable).
   * - optionName: The name of the option (if applicable).
   * - value: A part of the value or file content.
   */
  function appendScannerResults(results) {
    results.forEach(function(result) {
      var resultDiv = jQuery('<div class="scanner-result-row"></div>');
      var scannerInfo = '<strong>Scanner:</strong> ' + result.scanner + '<br>';
      var filenameInfo = result.filename ? '<strong>Filename:</strong> ' + result.filename + '<br>' : ''; 
      var optionNameInfo = result.optionName ? '<strong>Option Name:</strong> ' + result.optionName + '<br>' : '';
      var valueInfo = result.value ? '<strong>Value:</strong> ' + result.value + '<br>' : '';

      resultDiv.html(scannerInfo + filenameInfo + optionNameInfo + valueInfo);
      jQuery('#sn_ms_results').append(resultDiv);
    });
  }



});
