window.vsDashboardProfileHandlers = true;

jQuery(function ($) {
  // Ensure a safe runtime config even if localization is missing/cached.
  // This prevents silent JS crashes that can break category button handlers.
  const defaultVsVars = {
    ajaxurl: (typeof window.ajaxurl !== 'undefined' && window.ajaxurl) ? window.ajaxurl : '/wp-admin/admin-ajax.php',
    nonce: $('#vs-categories-security').first().val() || '',
    i18n: {},
    is_admin: false,
    can_manage_terms: false,
    is_vendor: false
  };
  window.vs_vars = Object.assign({}, defaultVsVars, window.vs_vars || {});
  const vs_vars = window.vs_vars;

  const wpI18n = window.wp && window.wp.i18n ? window.wp.i18n : null;
  const vsI18n = window.vs_vars && window.vs_vars.i18n ? window.vs_vars.i18n : {};
  const vsText = (key, fallback) => {
    if (Object.prototype.hasOwnProperty.call(vsI18n, key) && vsI18n[key]) {
      return String(vsI18n[key]);
    }
    if (wpI18n && typeof wpI18n.__ === 'function') {
      return wpI18n.__(fallback || key, 'vendor-space');
    }
    return fallback || key;
  };
  const vsSprintf = (...args) => {
    if (wpI18n && typeof wpI18n.sprintf === 'function') {
      return wpI18n.sprintf(...args);
    }
    return args[0];
  };

  // Small visual toast for debugging clicks when console isn't visible
  function vsShowDebugToast(msg) {
    try {
      const id = 'vs-debug-toast';
      let $t = $('#' + id);
      if (!$t.length) {
        $t = $('<div id="' + id + '" style="position:fixed;right:20px;bottom:20px;background:#111;color:#fff;padding:10px 14px;border-radius:8px;z-index:999999;font-size:13px;box-shadow:0 6px 18px rgba(2,6,23,0.4);opacity:0.95;"></div>');
        $('body').append($t);
      }
      $t.text(msg).fadeIn(150).stop(true,true).delay(2500).fadeOut(300);
    } catch (e) {
      // ignore
    }
  }

  // Global error capture to help identify JS issues preventing handlers
  if (!window.vs_global_error_attached) {
    window.vs_global_error_attached = true;
    window.addEventListener('error', function (ev) {
      console.error('VS global error:', ev.message, ev.filename + ':' + ev.lineno);
      try { vsShowDebugToast('JS Error: ' + ev.message); } catch (e) {}
    });
    window.addEventListener('unhandledrejection', function (ev) {
      console.error('VS unhandled rejection:', ev.reason);
      try { vsShowDebugToast('Unhandled Promise Rejection'); } catch (e) {}
    });
  }

  // ==============================
  // Tab Switching Logic
  // ==============================
  $(document).on('click', '.vs-tab-link', function (e) {
    e.preventDefault();

    const tabId = $(this).data('tab');
    if (!tabId) return;
    const $targetTab = $('#tab-' + tabId);

    // Tabs active state
    $('.vs-tab-link').removeClass('active');
    $(this).addClass('active');

    // Hide all tabs
    $('.vs-tab').hide();
    // تأكد من إخفاء تبويب الإعلانات دائماً في البداية
    $('#tab-my-ads').hide();

    if ($targetTab.length) {
      // إذا كان التبويب هو my-ads، أظهره فقط عند الضغط على زر التبويب
      if (tabId === 'my-ads') {
        $('#tab-my-ads').fadeIn(200);
        return;
      }
      $targetTab.fadeIn(200, function () {
        // Apply products pagination when My Products tab is shown
        if (tabId === 'my-products') {
          vsLoadProductsPage(1, true);
        }
        // Apply restore pagination when Restore Products tab is shown
        if (tabId === 'restore-products' && typeof window.vsApplyRestorePagination === 'function') {
          window.vsApplyRestorePagination(true);
        }
        // Reload orders via AJAX when Orders tab is shown
        if (tabId === 'my-orders' && typeof window.vsLoadOrdersPage === 'function') {
          window.vsLoadOrdersPage(true);
        }
        // Apply categories pagination when Categories tab is shown
        if (tabId === 'product-categories' && typeof window.vsApplyCategoriesPagination === 'function') {
          window.vsApplyCategoriesPagination(true);
        }
        // Apply best clients pagination when Best Clients tab is shown
        if (tabId === 'best-clients' && typeof window.vsApplyBestClientsPagination === 'function') {
          window.vsApplyBestClientsPagination(true);
        }
        // Apply wallet pagination when Wallet tab is shown
        if (tabId === 'wallet') {
          // First apply pagination on server-rendered rows
          if (typeof window.vsApplyWalletPagination === 'function') {
            window.vsApplyWalletPagination(true);
          }
          // Then refresh via AJAX (pagination is re-applied inside fetchWalletData success)
          if (typeof window.fetchWalletData === 'function') {
            window.fetchWalletData();
          }
        }
      });
    } else {
      console.error(vsText('tab_not_found', 'Tab not found:'), tabId);
    }

    // Products tab tools
    const isProducts = tabId === 'my-products';

    // $('#tab-my-products').toggle(isProducts); 
    // $('#vs-products-pane').toggle(isProducts);
    // $('#tab-my-products .vs-products-table').toggle(isProducts);
    // $('.vs-table-tools').toggle(isProducts);

    // Always keep forms hidden until user explicitly opens them
    $('#add-product-form-wrapper').hide();
    $('#vs-edit-product-wrapper').hide();
  });

  // ==============================
  // Product Categories CRUD
  // ==============================
  function vsHasSwal() {
    return (typeof Swal !== 'undefined') && Swal && (typeof Swal.fire === 'function');
  }

  function vsSwalLoading(title) {
    if (vsHasSwal()) {
      Swal.fire({ title: title || vsText('loading', 'Loading...'), allowOutsideClick: false, didOpen: () => Swal.showLoading() });
    }
  }

  function vsSwalClose() {
    if (vsHasSwal()) Swal.close();
  }

  // State tracking for the category modal so the Save button stays disabled until something changes
  let vsCategoryFormMode = 'add'; // 'add' or 'edit'
  let vsCategoryFormOriginal = null;

  function vsEscapeHtml(str) {
    return String(str || '').replace(/[&<>\"']/g, (m) => ({
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      "'": '&#39;'
    })[m] || '');
  }

  function vsEscapeHtmlAttr(str) {
    return vsEscapeHtml(str).replace(/\"/g, '&quot;');
  }

  function vsSetCategorySaveButtonEnabled(enabled) {
    const $btn = $('#vs-category-save');
    if (!$btn.length) return;
    $btn.prop('disabled', !enabled);
    $btn.toggleClass('vs-btn--disabled', !enabled);
  }

  function vsIsCategoryFormDirty() {
    if (!vsCategoryFormOriginal) return false;
    const current = {
      name: String($('#vs-category-name').val() || '').trim(),
      slug: String($('#vs-category-slug').val() || '').trim(),
      parent: String($('#vs-category-parent').val() || '0').trim(),
      description: String($('#vs-category-description').val() || '').trim()
    };
    if (vsCategoryFormMode === 'add') {
      // For new categories, only require name to be non-empty
      return current.name.length > 0;
    }
    // For edits, ensure at least one field differs
    return current.name !== vsCategoryFormOriginal.name
      || current.slug !== vsCategoryFormOriginal.slug
      || current.parent !== vsCategoryFormOriginal.parent
      || current.description !== vsCategoryFormOriginal.description;
  }

  function vsUpdateCategorySaveState() {
    const enabled = vsIsCategoryFormDirty();
    vsSetCategorySaveButtonEnabled(enabled);
  }

  function vsPinUncategorizedFirst() {
    const uncategorizedId = String(
      (window.vs_vars && window.vs_vars.uncategorized_term_id)
      || (window.vs_vars && window.vs_vars.default_product_cat)
      || ''
    );
    const $targets = $('#add-product-cat, #edit-product-cat, select[name="product_cat"]');
    if (!$targets.length) return;

    $targets.each(function () {
      const $select = $(this);
      if (!$select.length) return;

      let $uncat = $();
      if (uncategorizedId) {
        $uncat = $select.find(`option[value="${uncategorizedId}"]`).first();
      }
      if (!$uncat.length) {
        $uncat = $select.find('option').filter(function () {
          return /uncategorized/i.test(String($(this).text() || ''));
        }).first();
      }
      if (!$uncat.length) return;

      // Keep "Please select / None" placeholder first if present; otherwise pin uncategorized at top.
      const $first = $select.find('option').first();
      const firstVal = String($first.val() || '');
      const isPlaceholder = firstVal === '' || firstVal === '0' || /none|select/i.test(String($first.text() || ''));
      if (isPlaceholder && !$uncat.is($first)) {
        $uncat.detach();
        $first.after($uncat);
      } else if (!$uncat.is($first)) {
        $uncat.detach();
        $select.prepend($uncat);
      }
    });
  }

  function vsRenderCategoryRow(cat) {
    const termId = parseInt(cat.term_id, 10) || 0;
    const name = cat.name || '';
    const slug = cat.slug || '';
    const parentName = cat.parent_name || '';
    const parentId = parseInt(cat.parent, 10) || 0;
    const description = cat.description || '';
    const count = (cat.count !== undefined && cat.count !== null) ? parseInt(cat.count, 10) : 0;

    return `
      <tr id="vs-cat-row-${termId}" style="border-bottom:1px solid #f1f5f9;">
        <td style="padding:15px; width: 40px;">
          <input type="checkbox" class="vs-cat-checkbox" value="${termId}" style="cursor:pointer; width:18px; height:18px;">
        </td>
        <td style="padding:15px; font-weight:600; color:#1e293b;">${vsEscapeHtml(name)}</td>
        <td style="padding:15px; color:#475569;">${vsEscapeHtml(slug)}</td>
        <td style="padding:15px; color:#475569;">${vsEscapeHtml(parentName)}</td>
        <td style="padding:15px; color:#475569;">${count}</td>
        <td style="padding:15px; text-align:right;">
          <div style="display:inline-flex; gap:10px; flex-wrap:wrap; justify-content:flex-end;">
            <button type="button"
              class="vs-edit-category-btn"
              data-term-id="${termId}"
              data-name="${vsEscapeHtmlAttr(name)}"
              data-slug="${vsEscapeHtmlAttr(slug)}"
              data-parent="${parentId}"
              data-description="${vsEscapeHtmlAttr(description)}"
              style="background:#0ea5e9; color:white; border:none; padding:8px 14px; border-radius:8px; cursor:pointer; font-size:13px; font-weight:600; display:flex; align-items:center; gap:6px;">
              <i class="fas fa-pen"></i> ${vsEscapeHtml(vsText('edit', 'Edit'))}
            </button>
            <button type="button"
              class="vs-delete-category-btn"
              data-term-id="${termId}"
              style="background:#fff; color:#ef4444; border:1px solid #fca5a5; padding:8px 14px; border-radius:8px; cursor:pointer; font-size:13px; font-weight:600; display:flex; align-items:center; gap:6px;">
              <i class="fas fa-trash-alt"></i> ${vsEscapeHtml(vsText('delete', 'Delete'))}
            </button>
          </div>
        </td>
      </tr>
    `;
  }

  function vsUpdateCategoryRow(cat) {
    const termId = parseInt(cat.term_id, 10) || 0;
    const $row = $(`#vs-cat-row-${termId}`);
    if (!$row.length) return;

    $row.find('td').eq(1).text(cat.name || '');
    $row.find('td').eq(2).text(cat.slug || '');
    $row.find('td').eq(3).text(cat.parent_name || '');
    $row.find('td').eq(4).text((cat.count !== undefined && cat.count !== null) ? parseInt(cat.count, 10) || 0 : 0);

    const $editBtn = $row.find('.vs-edit-category-btn').first();
    if ($editBtn.length) {
      $editBtn.attr('data-name', cat.name || '');
      $editBtn.attr('data-slug', cat.slug || '');
      $editBtn.attr('data-parent', String(cat.parent || 0));
      $editBtn.attr('data-description', cat.description || '');
    }

    // Update any relevant category dropdowns on the page that reference this category
    const $categorySelects = $('select[name="product_cat"], select[name="vs_category_parent"], #vs-category-parent');
    $categorySelects.find(`option[value="${termId}"]`).each(function () {
      $(this).text(cat.name || '');
    });
  }

  function vsAddOrUpdateCategoryOption(cat) {
    const termId = parseInt(cat.term_id, 10) || 0;
    const name = cat.name || '';
    if (!termId) return;

    const $categorySelects = $('select[name="product_cat"], select[name="vs_category_parent"], #vs-category-parent');

    // Update existing option labels (in case a category name changed)
    $categorySelects.find('option').each(function () {
      if (String(this.value) === String(termId)) {
        $(this).text(name);
      }
    });

    // Add option to any relevant select that does not have it yet
    $categorySelects.each(function () {
      const $select = $(this);
      if ($select.find(`option[value="${termId}"]`).length === 0) {
        $select.append(`<option value="${termId}">${vsEscapeHtml(name)}</option>`);
      }
    });
    vsPinUncategorizedFirst();
  }

  function vsCloseCategoryModal() {
    const $modal = $('#vs-category-modal');
    if (!$modal.length) return;
    $modal.hide();

    // Show all options in the parent dropdown
    $('#vs-category-parent option').show();

    // Reset modal state so "Save" is disabled next time
    vsCategoryFormOriginal = null;
    vsCategoryFormMode = 'add';
    vsSetCategorySaveButtonEnabled(false);
  }

  function vsWarn(title, text) {
    if (vsHasSwal()) return Swal.fire(title || vsText('warning', 'Warning'), text || '', 'warning');
    window.alert((title || vsText('warning', 'Warning')) + (text ? ('\n' + text) : ''));
  }

  function vsError(title, text) {
    if (vsHasSwal()) return Swal.fire(title || vsText('error', 'Error'), text || '', 'error');
    window.alert((title || vsText('error', 'Error')) + (text ? ('\n' + text) : ''));
  }

  function vsSuccess(title, text) {
    if (vsHasSwal()) {
      return Swal.fire({
        title: title || vsText('success', 'Success'),
        text: text || '',
        icon: 'success',
        timer: 1800,
        showConfirmButton: false
      });
    }
    if (text) {
      window.alert((title || vsText('success', 'Success')) + '\n' + text);
    }
  }

  function vsOpenCategoryModal(mode, data) {
    const $modal = $('#vs-category-modal');
    if (!$modal.length) return;

    vsCategoryFormMode = mode === 'edit' ? 'edit' : 'add';

    const termId = (data && data.term_id) ? String(data.term_id) : '';
    const name = (data && data.name) ? String(data.name) : '';
    const slug = (data && data.slug) ? String(data.slug) : '';
    const description = (data && data.description) ? String(data.description) : '';
    const parent = (data && (data.parent !== undefined)) ? String(data.parent) : '0';

    vsCategoryFormOriginal = {
      name,
      slug,
      parent,
      description
    };

    $('#vs-category-modal-title').text(mode === 'edit' ? vsText('edit_category', 'Edit Category') : vsText('add_category', 'Add Category'));
    $('#vs-category-save').text(vsText('save', 'Save'));
    $('#vs-category-term-id').val(termId);
    $('#vs-category-name').val(name);
    $('#vs-category-slug').val(slug);
    $('#vs-category-description').val(description);
    $('#vs-category-parent').val(parent);

    // Hide excluded categories when editing to prevent circular references
    if (vsCategoryFormMode === 'edit' && termId) {
        $.ajax({
          url: (window.vs_vars && vs_vars.ajaxurl) ? vs_vars.ajaxurl : (typeof ajaxurl !== 'undefined' ? ajaxurl : '/wp-admin/admin-ajax.php'),
          type: 'POST',
          data: {
            action: 'vs_get_category_excludes',
            security: $('#vs-categories-security').val(),
            term_id: termId
          },
          success: function(response) {
            if (response.success && response.data.excludes) {
              response.data.excludes.forEach(function(excludeId) {
                $('#vs-category-parent option[value="' + excludeId + '"]').hide();
              });
            }
          }
        });
    }

    vsUpdateCategorySaveState();

    $modal.css('display', 'flex');
  }

  $(document).on('click', '#vs-add-category-btn', function (e) {
    e.preventDefault();
    try {
      console.log('vs: add category button clicked');
      try { vsShowDebugToast('Add Category clicked'); } catch (e) {}
      vsOpenCategoryModal('add', { parent: 0 });
      // Defensive fallback: ensure modal becomes visible
      setTimeout(function () {
        const $m = $('#vs-category-modal');
        if ($m.length && $m.css('display') === 'none') {
          $m.css('display', 'flex');
        }
      }, 50);
    } catch (err) {
      console.error('vs: error opening category modal', err);
      try { vsShowDebugToast('Error opening modal'); } catch (e) {}
      const $m = $('#vs-category-modal');
      if ($m.length) $m.css('display', 'flex');
    }
  });

  // Vendor request open
  $(document).on('click', '#vs-request-category-btn', function (e) {
    e.preventDefault();
    try {
      console.log('vs: request category button clicked');
      try { vsShowDebugToast('Request Category clicked'); } catch (e) {}
      vsOpenCategoryModal('add', { parent: 0 });
      setTimeout(function () {
        const $m = $('#vs-category-modal');
        if ($m.length && $m.css('display') === 'none') {
          $m.css('display', 'flex');
        }
      }, 50);
    } catch (err) {
      console.error('vs: error opening request modal', err);
      try { vsShowDebugToast('Error opening request modal'); } catch (e) {}
      const $m = $('#vs-category-modal');
      if ($m.length) $m.css('display', 'flex');
    }
  });

  $(document).on('click', '#vs-category-modal-close, #vs-category-cancel', function (e) {
    e.preventDefault();
    vsCloseCategoryModal();
  });

  $(document).on('click', '#vs-category-modal', function (e) {
    if (e.target === this) {
      vsCloseCategoryModal();
    }
  });

  $(document).on('click', '.vs-edit-category-btn', function (e) {
    e.preventDefault();
    const $btn = $(this);
    vsOpenCategoryModal('edit', {
      term_id: $btn.data('term-id'),
      name: $btn.data('name'),
      slug: $btn.data('slug'),
      parent: $btn.data('parent'),
      description: $btn.data('description')
    });
  });

  // Keep the save button disabled until fields change
  $(document).on('input change', '#vs-category-name, #vs-category-slug, #vs-category-parent, #vs-category-description', function () {
    vsUpdateCategorySaveState();
  });

  function vsGetInlineCategorySelect($btn) {
    const $field = $btn.closest('.vs-field');
    if (!$field.length) return $();
    return $field.find('select').first();
  }

  $(document).on('click', '.vs-inline-cat-manage', function (e) {
    e.preventDefault();
    const $link = $('.vs-tab-link[data-tab="product-categories"]').first();
    if ($link.length) $link.trigger('click');
  });

  $(document).on('click', '.vs-inline-cat-add', function (e) {
    e.preventDefault();
    // If modal exists, open directly and reset to "add" mode.
    const $modal = $('#vs-category-modal');
    if ($modal.length) {
      $('#vs-category-modal-title').text(vsText('add_category', 'Add Category'));
      $('#vs-category-term-id').val('');
      $('#vs-category-name').val('');
      $('#vs-category-slug').val('');
      $('#vs-category-parent').val('0');
      $('#vs-category-description').val('');
      $modal.css('display', 'flex');
    }
    vsOpenCategoryModal('add', { parent: 0 });
  });

  $(document).on('click', '.vs-inline-cat-edit', function (e) {
    e.preventDefault();
    const $select = vsGetInlineCategorySelect($(this));
    const termId = parseInt(String($select.val() || '0'), 10) || 0;
    const security = ($('#vs-categories-security').val()) || (window.vs_vars ? vs_vars.nonce : '');

    if (termId <= 0) {
      vsWarn('No category selected', 'Please select a category first.');
      return;
    }

    vsSwalLoading(vsText('loading', 'Loading...'));
    $.ajax({
      url: vs_vars.ajaxurl,
      type: 'POST',
      dataType: 'json',
      data: {
        action: 'vs_get_product_category',
        security,
        term_id: termId
      },
      success: function (res) {
        vsSwalClose();
        if (res && res.success && res.data) {
          vsOpenCategoryModal('edit', res.data);
        } else {
          vsError(vsText('error', 'Error'), (res && res.data) ? res.data : vsText('request_failed', 'Request failed'));
        }
      },
      error: function (xhr) {
        vsSwalClose();
        vsError(vsText('error', 'Error'), vsSprintf(vsText('request_failed_status', 'Request failed: %s'), xhr.status));
      }
    });
  });

  $(document).on('click', '.vs-inline-cat-delete', function (e) {
    e.preventDefault();
    const $select = vsGetInlineCategorySelect($(this));
    const termId = parseInt(String($select.val() || '0'), 10) || 0;
    const security = ($('#vs-categories-security').val()) || (window.vs_vars ? vs_vars.nonce : '');

    if (termId <= 0) {
      vsWarn('No category selected', 'Please select a category first.');
      return;
    }

    const doDelete = () => {
      vsSwalLoading(vsText('deleting', 'Deleting...'));
      $.ajax({
        url: vs_vars.ajaxurl,
        type: 'POST',
        dataType: 'json',
        data: {
          action: 'vs_delete_product_category',
          security,
          term_id: termId
        },
        success: function (res) {
          vsSwalClose();
          if (res && res.success) {
            window.location.reload();
          } else {
            vsError(vsText('error', 'Error'), (res && res.data) ? res.data : vsText('request_failed', 'Request failed'));
          }
        },
        error: function (xhr) {
          vsSwalClose();
          vsError(vsText('error', 'Error'), vsSprintf(vsText('request_failed_status', 'Request failed: %s'), xhr.status));
        }
      });
    };

    if (vsHasSwal()) {
      Swal.fire({
        title: vsText('delete_category', 'Delete category?'),
        text: 'This will permanently delete the category.',
        icon: 'warning',
        showCancelButton: true,
        confirmButtonText: vsText('confirm_delete', 'Delete'),
        confirmButtonColor: '#ef4444'
      }).then((result) => {
        if (!result.isConfirmed) return;
        doDelete();
      });
    } else {
      if (window.confirm(vsText('delete_category_confirm', 'Delete this category permanently?'))) doDelete();
    }
  });

  // Bulk Selection and Deletion for Categories
  $(document).on('change', '#vs-select-all-categories', function() {
    $('.vs-cat-checkbox').prop('checked', $(this).prop('checked'));
    toggleBulkDeleteBtn();
  });

  $(document).on('change', '.vs-cat-checkbox', function() {
    const allChecked = $('.vs-cat-checkbox:checked').length === $('.vs-cat-checkbox').length;
    $('#vs-select-all-categories').prop('checked', allChecked);
    toggleBulkDeleteBtn();
  });

  function toggleBulkDeleteBtn() {
    const selectedCount = $('.vs-cat-checkbox:checked').length;
    if (selectedCount > 0) {
      $('#vs-bulk-delete-categories-btn').show();
    } else {
      $('#vs-bulk-delete-categories-btn').hide();
    }
  }

  $(document).on('click', '#vs-bulk-delete-categories-btn', function(e) {
    e.preventDefault();
    const selectedIds = [];
    $('.vs-cat-checkbox:checked').each(function() {
      selectedIds.push($(this).val());
    });

    if (selectedIds.length === 0) return;

    const security = ($('#vs-categories-security').val()) || (window.vs_vars ? vs_vars.nonce : '');

    const doBulkDelete = () => {
      vsSwalLoading(vsText('deleting', 'Deleting...'));
      $.ajax({
        url: vs_vars.ajaxurl,
        type: 'POST',
        dataType: 'json',
        data: {
          action: 'vs_bulk_delete_product_categories',
          security,
          term_ids: selectedIds
        },
        success: function(res) {
          vsSwalClose();
          if (res && res.success) {
            if (res.data.errors && res.data.errors.length > 0) {
                // Some errors occurred but some might have been deleted
                vsWarn('Partial Success', 'Some categories could not be deleted:\n' + res.data.errors.join('\n'));
            }
            // Refresh to see changes or manually remove rows
            if (res.data.deleted_ids) {
                res.data.deleted_ids.forEach(id => {
                   $(`#vs-cat-row-${id}`).fadeOut(300, function() { $(this).remove(); });
                });
            }
            $('#vs-bulk-delete-categories-btn').hide();
            $('#vs-select-all-categories').prop('checked', false);
          } else {
            vsError(vsText('error', 'Error'), (res && res.data) ? res.data : vsText('request_failed', 'Request failed'));
          }
        },
        error: function(xhr) {
          vsSwalClose();
          vsError(vsText('error', 'Error'), vsSprintf(vsText('request_failed_status', 'Request failed: %s'), xhr.status));
        }
      });
    };

    if (vsHasSwal()) {
      Swal.fire({
        title: vsText('delete_selected_categories', 'Delete selected categories?'),
        text: vsSprintf(vsText('delete_selected_categories_confirm', 'Are you sure you want to delete %d categories?'), selectedIds.length),
        icon: 'warning',
        showCancelButton: true,
        confirmButtonText: vsText('confirm_delete', 'Delete'),
        confirmButtonColor: '#ef4444'
      }).then((result) => {
        if (!result.isConfirmed) return;
        doBulkDelete();
      });
    } else {
      if (window.confirm(vsSprintf(vsText('delete_selected_categories_confirm_prompt', 'Delete %d categories permanently?'), selectedIds.length))) doBulkDelete();
    }
  });

  // Open requests modal (admin)
  $(document).on('click', '#vs-open-requests-btn', function (e) {
    e.preventDefault();
    const security = ($('#vs-categories-security').val()) || (window.vs_vars ? vs_vars.nonce : '');
    vsSwalLoading(vsText('loading', 'Loading...'));
    $.ajax({
      url: vs_vars.ajaxurl,
      type: 'POST',
      dataType: 'json',
      data: {
        action: 'vs_list_category_requests',
        security
      },
      success: function(res) {
        vsSwalClose();
        if (!res || !res.success) {
          vsError(vsText('error','Error'), (res && res.data) ? res.data : vsText('request_failed','Request failed'));
          return;
        }
        const rows = res.data.requests || [];
        const $table = $('#vs-requests-table');
        const $theadTr = $table.find('thead tr').first();
        if ($theadTr.length && $theadTr.find('.vs-req-parent').length === 0) {
          // Insert Parent column after Category
          $theadTr.find('th').eq(1).after('<th class="vs-req-parent" style="padding:8px; text-align:left;">' + vsEscapeHtml(vsText('parent', 'Parent')) + '</th>');
        }
       

        const $tbody = $table.find('tbody');
        $tbody.empty();
        if (!rows.length) {
          // Adjust colspan to match dynamic number of columns (calculate)
          const colCount = $theadTr.find('th').length || 7;
          $tbody.append('<tr><td colspan="' + colCount + '" style="padding:12px;text-align:center;">No requests found.</td></tr>');
        } else {
          rows.forEach(function(r) {
            const actions = [];
            if ((window.vs_vars && window.vs_vars.is_admin) || (window.vs_vars && window.vs_vars.can_manage_terms)) {
              actions.push('<button class="vs-approve-request" data-id="'+r.id+'" style="margin-right:6px;">Approve</button>');
              actions.push('<button class="vs-reject-request" data-id="'+r.id+'">Reject</button>');
            }
            // Resolve parent name if possible (look up select option), otherwise show parent ID or em-dash
            let parentDisplay = '';
            const parentId = parseInt(r.parent || 0, 10) || 0;
            if (parentId > 0) {
              const $opt = $('#vs-category-parent option[value="' + parentId + '"]');
              if ($opt.length) parentDisplay = vsEscapeHtml($opt.text());
              else parentDisplay = '(' + parentId + ')';
            } else {
              parentDisplay = '—';
            }

            const vendorIdDisplay = (r.author_id ? String(r.author_id) : '');

            $tbody.append('\n              <tr data-id="'+r.id+'">\n                <td style="padding:8px;">#'+r.id+'</td>\n                <td style="padding:8px;">'+vsEscapeHtml(r.title || '')+'</td>\n                <td style="padding:8px;">'+vsEscapeHtml(parentDisplay)+'</td>\n                <td style="padding:8px;">'+vsEscapeHtml(vendorIdDisplay)+'</td>\n                <td style="padding:8px;">'+vsEscapeHtml(r.author_name || '')+'</td>\n                <td style="padding:8px;">'+vsEscapeHtml(r.content || '')+'</td>\n                <td style="padding:8px;">'+vsRenderCategoryRequestStatus(r.status)+'</td>\n                <td style="padding:8px;">'+vsEscapeHtml(r.date || '')+'</td>\n                <td style="padding:8px; text-align:right;">'+actions.join('')+'</td>\n              </tr>\n            ');
          });
        }
        $('#vs-requests-modal').css('display','flex');
      },
      error: function(xhr) { vsSwalClose(); vsError(vsText('error','Error'), vsSprintf(vsText('request_failed_status','Request failed: %s'), xhr.status)); }
    });
  });

  function vsRenderCategoryRequestStatus(status) {
    const s = String(status || '').toLowerCase();
    if (s === 'pending') {
      return '<span style="display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:999px;background:#fef3c7;color:#92400e;font-weight:700;font-size:12px;">Pending approval</span>';
    }
    if (s === 'approved' || s === 'publish') {
      return '<span style="display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:999px;background:#dcfce7;color:#166534;font-weight:700;font-size:12px;">Approved</span>';
    }
    if (s === 'rejected' || s === 'draft') {
      return '<span style="display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:999px;background:#fee2e2;color:#991b1b;font-weight:700;font-size:12px;">Rejected</span>';
    }
    return vsEscapeHtml(status || '');
  }

  function vsLoadVendorCategoryRequests() {
    const $table = $('#vs-vendor-category-requests-table');
    if (!$table.length) return;

    const security = ($('#vs-categories-security').val()) || (window.vs_vars ? vs_vars.nonce : '');
    const $tbody = $table.find('tbody');
    const $empty = $('#vs-vendor-category-requests-empty');

    $tbody.empty();
    vsSwalLoading(vsText('loading', 'Loading...'));
    $.ajax({
      url: vs_vars.ajaxurl,
      type: 'POST',
      dataType: 'json',
      data: { action: 'vs_list_category_requests', security },
      success: function(res) {
        vsSwalClose();
        if (!res || !res.success) {
          $empty.show();
          vsError(vsText('error', 'Error'), (res && res.data) ? res.data : vsText('request_failed', 'Request failed'));
          return;
        }

        const rows = res.data.requests || [];
        if (!rows.length) {
          $empty.show();
          $tbody.append('<tr><td colspan="5" style="padding:12px;text-align:center;">No requests found.</td></tr>');
          return;
        }

        $empty.hide();
        rows.forEach(function(r) {
          const actions = [];
          if (String(r.status).toLowerCase() === 'pending') {
            actions.push('<button class="vs-cancel-request vs-btn--cancel" data-id="'+r.id+'"><i class="fas fa-times-circle"></i> ' + vsText('cancel', 'Cancel') + '</button>');
          }

          $tbody.append(
            '<tr data-id="'+r.id+'" style="border-bottom:1px solid #f1f5f9;">' +
              '<td style="padding:8px;">#'+r.id+'</td>' +
              '<td style="padding:8px; font-weight:700; color:#0f172a;">'+vsEscapeHtml(r.title || '')+'</td>' +
              '<td style="padding:8px;">'+vsEscapeHtml(r.content || '')+'</td>' +
              '<td style="padding:8px;">'+vsRenderCategoryRequestStatus(r.status)+'</td>' +
              '<td style="padding:8px;">'+vsEscapeHtml(r.date || '')+'</td>' +
              '<td style="padding:8px; text-align:right;">'+actions.join('')+'</td>' +
            '</tr>'
          );
        });
      },
      error: function(xhr) {
        vsSwalClose();
        $empty.show();
        vsError(vsText('error','Error'), vsSprintf(vsText('request_failed_status','Request failed: %s'), xhr.status));
      }
    });
  }

  $(document).on('click', '#vs-refresh-vendor-category-requests', function(e){
    e.preventDefault();
    vsLoadVendorCategoryRequests();
  });

  // Close requests modal
  $(document).on('click', '#vs-requests-modal-close', function(e){ e.preventDefault(); $('#vs-requests-modal').hide(); });

 // Approve handler with Swal
$(document).on('click', '.vs-approve-request', function(e){
  e.preventDefault();

  const id = $(this).data('id');
  const security = ($('#vs-categories-security').val()) || (window.vs_vars ? vs_vars.nonce : '');

  Swal.fire({
    title: 'Are you sure?',
    text: 'Approve this category request?',
    icon: 'warning',
    showCancelButton: true,
    confirmButtonColor: '#10b981',
    cancelButtonColor: '#6b7280',
    confirmButtonText: 'Yes, approve it',
    cancelButtonText: 'Cancel'
  }).then((result) => {

    if (!result.isConfirmed) return;

    // 🔄 Loading
    vsSwalLoading(vsText('processing','Processing...'));

    $.post(vs_vars.ajaxurl, {
      action: 'vs_approve_category_request',
      security,
      request_id: id
    }, function(res){

      vsSwalClose();

      if (res && res.success) {

        const cat = res.data || {};

        // حذف الصف
        $('tr[data-id="'+id+'"]').fadeOut(300, function(){
          $(this).remove();
        });

        // تحديث البادج
        updateCategoryRequestsBadge(null, res.data.pending_count);

        // إضافة للكategories table
        const $tbody = $('.vs-categories-table tbody');
        if ($tbody.length) {
          $tbody.prepend(vsRenderCategoryRow(cat));
        }

        // تحديث select
        if (typeof vsAddOrUpdateCategoryOption === 'function') {
          vsAddOrUpdateCategoryOption(cat);
        }

        // ✅ نجاح
        Swal.fire({
          icon: 'success',
          title: vsText('success','Success'),
          text: 'Category has been approved and added.',
          timer: 1500,
          showConfirmButton: false
        });

      } else {
        Swal.fire(
          vsText('error','Error'),
          (res && res.data) ? res.data : vsText('request_failed','Request failed'),
          'error'
        );
      }

    }, 'json');

  });

});

  $(document).on('click', '.vs-cancel-request', function(e) {
    e.preventDefault();
    const id = $(this).data('id');
    const security = ($('#vs-categories-security').val()) || (window.vs_vars ? vs_vars.nonce : '');

    const doCancel = () => {
      vsSwalLoading(vsText('cancelling', 'Cancelling...'));
      $.ajax({
        url: vs_vars.ajaxurl,
        type: 'POST',
        dataType: 'json',
        data: {
          action: 'vs_cancel_category_request',
          security,
          request_id: id
        },
        success: function(res) {
          vsSwalClose();
          if (res && res.success) {
            $(`tr[data-id="${id}"]`).fadeOut(300, function() {
              $(this).remove();
              if ($('#vs-vendor-category-requests-table tbody tr').length === 0) {
                 $('#vs-vendor-category-requests-empty').show();
              }
            });
            vsSuccess(vsText('success', 'Success'), res.data.message);
          } else {
            vsError(vsText('error', 'Error'), (res && res.data) ? res.data : vsText('request_failed', 'Request failed'));
          }
        },
        error: function(xhr) {
          vsSwalClose();
          vsError(vsText('error', 'Error'), vsSprintf(vsText('request_failed_status', 'Request failed: %s'), xhr.status));
        }
      });
    };

    if (vsHasSwal()) {
      Swal.fire({
        title: vsText('cancel_request', 'Cancel Request?'),
        text: 'Are you sure you want to cancel this category request?',
        icon: 'warning',
        showCancelButton: true,
        confirmButtonText: vsText('yes_cancel', 'Yes, cancel it'),
        confirmButtonColor: '#ef4444'
      }).then((result) => {
        if (result.isConfirmed) doCancel();
      });
    } else {
      if (window.confirm(vsText('cancel_request_confirm', 'Are you sure you want to cancel this category request?'))) doCancel();
    }
  });

  $(document).on('click', '.vs-reject-request', function(e){
    e.preventDefault();
    const id = $(this).data('id');
    const security = ($('#vs-categories-security').val()) || (window.vs_vars ? vs_vars.nonce : '');
    if (!confirm('Reject this category request?')) return;
    $.post(vs_vars.ajaxurl, { action: 'vs_reject_category_request', security, request_id: id }, function(res){
      if (res && res.success) {
        $('tr[data-id="'+id+'"]').fadeOut(function(){ $(this).remove(); });
        updateCategoryRequestsBadge(null, res.data.pending_count);
        Swal.fire(vsText('success','Success'), 'Category request has been rejected.', 'success');
      } else {
        vsError(vsText('error','Error'), (res && res.data) ? res.data : vsText('request_failed','Request failed'));
      }
    }, 'json');
  });

  function updateCategoryRequestsBadge(delta, newCount = null) {
    const $badge = $('#vs-category-requests-badge');
    let nextCount;
    if (newCount !== null) {
      nextCount = parseInt(newCount, 10) || 0;
    } else {
      const current = $badge.length ? (parseInt($badge.text(), 10) || 0) : 0;
      nextCount = Math.max(0, current + delta);
    }

    if ($badge.length) {
      if (nextCount > 0) {
        $badge.text(nextCount).show();
      } else {
        $badge.hide();
      }
    }
  }

	  $(document).on('submit', '#vs-category-form', function (e) {
    e.preventDefault();

    const termId = String($('#vs-category-term-id').val() || '').trim();
    const name = String($('#vs-category-name').val() || '').trim();
    const slug = String($('#vs-category-slug').val() || '').trim();
    const parent = String($('#vs-category-parent').val() || '0').trim();
    const description = String($('#vs-category-description').val() || '').trim();
    const security = ($('#vs-categories-security').val()) || (window.vs_vars ? vs_vars.nonce : '');

    if (!name) {
      vsWarn(vsText('missing_name', 'Missing name'), vsText('category_name_required', 'Category name is required.'));
      return;
    }

    const isEdit = termId !== '';
    // If user cannot manage terms, always send a request for new categories.
    // This avoids relying on role flags that can vary across installations.
    const canManageTerms = !!(window.vs_vars && window.vs_vars.can_manage_terms);
    let action = isEdit ? 'vs_update_product_category' : 'vs_create_product_category';
    if (!canManageTerms && !isEdit) {
      action = 'vs_request_product_category';
    }

    vsSwalLoading(isEdit ? vsText('saving', 'Saving...') : vsText('creating', 'Creating...'));

    $.ajax({
      url: vs_vars.ajaxurl,
      type: 'POST',
      dataType: 'json',
      data: {
        action,
        security,
        term_id: termId,
        name,
        slug,
        parent,
        description
      },
	      success: function (res) {
	        if (res && res.success) {
	          vsSwalClose();
	          vsCloseCategoryModal();

          const cat = res.data || {};
          // If the action was a request, just notify the user
	          if (action === 'vs_request_product_category') {
	            vsSuccess(
	              vsText('success', 'Success'),
	              (res.data && res.data.message) ? res.data.message : vsText('request_submitted', 'Request submitted.')
	            );
	            // Refresh vendor requests table if present
	            vsLoadVendorCategoryRequests();
	            return;
	          }

          vsAddOrUpdateCategoryOption(cat);

          if (isEdit) {
            vsUpdateCategoryRow(cat);
            vsSuccess(vsText('success', 'Success'), vsText('category_updated', 'Category updated successfully.'));
          } else {
            const $tbody = $('.vs-categories-table tbody');
            if ($tbody.length) {
              $tbody.prepend(vsRenderCategoryRow(cat));
            }
            // Make the newly created category immediately usable in product forms.
            const newTermId = parseInt(cat.term_id, 10) || 0;
            if (newTermId > 0) {
              $('select[name="product_cat"]').val(String(newTermId)).trigger('change');
            }
            vsSuccess(vsText('success', 'Success'), vsText('category_created', 'Category created successfully.'));
          }
        } else {
          vsError(vsText('error', 'Error'), (res && res.data) ? res.data : vsText('request_failed', 'Request failed'));
        }
	      },
      error: function (xhr) {
        vsError(vsText('error', 'Error'), vsSprintf(vsText('request_failed_status', 'Request failed: %s'), xhr.status));
      }
	  });

  // Auto-load vendor category requests table when present
  $(function () {
    if ($('#vs-vendor-category-requests-table').length) {
      vsLoadVendorCategoryRequests();
    }
  });
  });

  $(document).on('click', '.vs-delete-category-btn', function (e) {
    e.preventDefault();
    const termId = $(this).data('term-id');
    const security = ($('#vs-categories-security').val()) || (window.vs_vars ? vs_vars.nonce : '');

    const doDelete = () => {
      vsSwalLoading(vsText('deleting', 'Deleting...'));
      $.ajax({
        url: vs_vars.ajaxurl,
        type: 'POST',
        dataType: 'json',
        data: {
          action: 'vs_delete_product_category',
          security,
          term_id: termId
        },
        success: function (res) {
          if (res && res.success) {
            vsSwalClose();
            $('#vs-cat-row-' + termId).remove();
          } else {
            vsError(vsText('error', 'Error'), (res && res.data) ? res.data : vsText('request_failed', 'Request failed'));
          }
        },
        error: function (xhr) {
          vsError(vsText('error', 'Error'), vsSprintf(vsText('request_failed_status', 'Request failed: %s'), xhr.status));
        }
      });
    };

    if (vsHasSwal()) {
      Swal.fire({
        title: vsText('delete_category', 'Delete category?'),
        text: 'This will permanently delete the category.',
        icon: 'warning',
        showCancelButton: true,
        confirmButtonText: vsText('confirm_delete', 'Delete'),
        confirmButtonColor: '#ef4444'
      }).then((result) => {
        if (!result.isConfirmed) return;
        doDelete();
      });
    } else {
      if (window.confirm(vsText('delete_category_confirm', 'Delete this category permanently?'))) doDelete();
    }
  });


  // Ensure correct initial state (in case inline styles fail)
  $(document).ready(function () {
    vsPinUncategorizedFirst();
    // Wait a bit to ensure all tabs are rendered
    setTimeout(function () {
      vsPinUncategorizedFirst();
      // Defensive fix: if markup from any tab renderer accidentally breaks nesting,
      // some .vs-tab nodes may end up outside .vs-content, leaving a large empty area.
      // Move any orphan tabs back under .vs-content so the layout stays consistent.
      (function normalizeVsTabPlacement() {
        const $dash = $('.vs-dashboard');
        if (!$dash.length) return;
        const $content = $dash.find('.vs-content').first();
        if (!$content.length) return;

        $dash.find('.vs-tab').each(function () {
          const $tab = $(this);
          if ($tab.closest('.vs-content').length) return;
          $content.append($tab);
        });
      })();

      $('.vs-tab').hide();

      // Utility to show a tab by id
      function showTabById(tabId) {
        const target = $('#tab-' + tabId);
        if (target.length) {
          target.show();
          console.log('Initial active tab:', tabId);
          return true;
        }
        return false;
      }

      // 1) If URL contains ?tab=..., try to open that tab
      const params = new URLSearchParams(window.location.search);
      const tabFromUrl = params.get('tab');
      if (tabFromUrl && showTabById(tabFromUrl)) {
        $('.vs-tab-link').removeClass('active');
        $(`.vs-tab-link[data-tab="${tabFromUrl}"]`).addClass('active');
        if (tabFromUrl === 'my-products') {
          vsLoadProductsPage(1, true);
        }
        if (tabFromUrl === 'wallet' && typeof window.vsApplyWalletPagination === 'function') {
          window.vsApplyWalletPagination(true);
        }
      } else {
        // 2) If a link has .active in markup, respect it
        const $activeLink = $('.vs-tab-link.active');
        if ($activeLink.length) {
          const initialTab = $activeLink.data('tab');
          if (!showTabById(initialTab)) {
            $('#tab-my-products').show();
          }
          if (initialTab === 'my-products') {
            vsLoadProductsPage(1, true);
          }
          if (initialTab === 'wallet' && typeof window.vsApplyWalletPagination === 'function') {
            window.vsApplyWalletPagination(true);
          }
        } else {
          // 3) Fallback: default to My Products
          $('#tab-my-products').show(); // Default tab
          vsLoadProductsPage(1, true);
        }

        // Ensure product forms are hidden on initial render
        $('#add-product-form-wrapper').hide();
        $('#vs-edit-product-wrapper').hide();
      }

      // Debug: Log available tabs
      const availableTabs = $('.vs-tab').map(function () { return this.id; }).get();
      console.log('Available tabs:', availableTabs);

      // Expose fetch function to allow inline scripts to refresh wallet without reload
      function fetchWalletData() {
        if (!window.vs_vars || !vs_vars.ajaxurl) return;
        jQuery.ajax({
          url: vs_vars.ajaxurl,
          type: 'POST',
          data: {
            action: 'vs_get_wallet_data',
            security: vs_vars.nonce
          },
          success: function (response) {
            if (!response || !response.success) return;
            const data = response.data || {};

            // Update numbers (use formatted values from server when available)
            if (data.formatted_gross) $('#vs-gross-sales').html(data.formatted_gross);
            if (data.formatted_commission) $('#vs-total-commission').html('-' + data.formatted_commission);
            if (data.formatted_net) $('#vs-total-revenue').html(data.formatted_net);
            if (data.formatted_available) $('#vs-available-balance').html(data.formatted_available);
            if (data.formatted_pending) $('#vs-pending-revenue').html(data.formatted_pending);

            // Update transactions table (Order Earnings + Withdrawals)
            const $tbody = $('#vs-transaction-history-body');
            if ($tbody.length && Array.isArray(data.history)) {
              let html = '';
              if (data.history.length === 0) {
                html = '<tr><td colspan="4" style="padding:40px; text-align:center; color:#6b7280;">No recent activity.</td></tr>';
              } else {
                data.history.forEach(function (item) {
                  const status = (item.status || '').toLowerCase();
                  let statusColor = '#6b7280';
                  if (status === 'paid' || status === 'completed') statusColor = '#10b981';
                  else if (status === 'pending' || status === 'processing') statusColor = '#f59e0b';
                  else if (status === 'failed' || status === 'cancelled') statusColor = '#ef4444';

                  const amountColor = item.amount >= 0 ? '#059669' : '#dc2626';

                  html += `<tr style="border-bottom:1px solid #e5e7eb;">
                      <td style="padding:12px; font-size:13px; color:#4b5563;">${item.formatted_date || item.date}</td>
                      <td style="padding:12px;">
                          <div style="font-weight:600; font-size:14px; color:#111827;">${item.type}</div>
                          <div style="font-size:11px; color:#6b7280; text-transform:uppercase; letter-spacing:0.5px;">${item.label}</div>
                      </td>
                      <td style="padding:12px; font-weight:700; font-size:15px; color:${amountColor};">
                          ${item.amount_formatted}
                      </td>
                      <td style="padding:12px;">
                          <span style="color:white; background:${statusColor}; padding:4px 8px; border-radius:4px; text-transform:uppercase; font-size:10px; font-weight:bold;">
                              ${status}
                          </span>
                      </td>
                  </tr>`;
                });
              }
              $tbody.html(html);
              if (typeof window.vsRefreshTableSorters === 'function') {
                window.vsRefreshTableSorters('#tab-wallet');
              }
              if (typeof window.vsApplyWalletPagination === 'function') {
                window.vsApplyWalletPagination(true);
              }
            }
          },
          error: function (err) {
            console.warn('Failed to fetch wallet data', err);
          }
        });
      }

      // Make it globally available
      window.fetchWalletData = fetchWalletData;

      // Check if wallet tab exists
      if ($('#tab-wallet').length) {
        console.log('✅ Wallet tab found in DOM');
        try {
          console.log('Wallet content:', $('#tab-wallet').html().substring(0, 100));
        } catch (e) {
          console.warn('Could not read wallet HTML content', e);
        }
      } else {
        console.warn('❌ Wallet tab NOT found in DOM!');
        console.log('All tabs:', $('.vs-tab').map(function () { return this.id; }).get());
      }

      // Initialize wallet pagination on page load (rows prepared but tab hidden)
      if (typeof window.vsApplyWalletPagination === 'function') {
        window.vsApplyWalletPagination(true);
      }
    }, 100);
  });


  // ==============================
  // Generic Table Sorting
  // ==============================
  (function () {
    const tableState = new WeakMap();
    const SORT_STYLE_ID = 'vs-generic-table-sort-style';

    function ensureSortStyle() {
      if (document.getElementById(SORT_STYLE_ID)) return;
      const css = `
        .vs-table-sortable th[data-vs-sortable-col="1"]{cursor:pointer;user-select:none;position:relative;padding-right:26px !important}
        .vs-table-sortable th[data-vs-sortable-col="1"] .vs-sort-indicator{position:absolute;right:10px;top:50%;transform:translateY(-50%);font-size:11px;opacity:.75}
      `;
      const style = document.createElement('style');
      style.id = SORT_STYLE_ID;
      style.textContent = css;
      document.head.appendChild(style);
    }

    function norm(v) {
      return String(v || '').replace(/\s+/g, ' ').trim().toLowerCase();
    }

    function isNoSortHeader($th, index, $table) {
      if ($th.is('[data-vs-nosort="1"]')) return true;
      if ($th.hasClass('vs-sortable')) return true; // handled by dedicated scripts
      if ($th.find('input[type="checkbox"], button, select, textarea').length) return true;

      const label = norm($th.text());
      if (!label) return true;
      if (label === 'actions' || label === 'action') return true;

      const $sampleCell = $table.find('tbody tr td:nth-child(' + (index + 1) + ')').first();
      if ($sampleCell.length) {
        const sampleText = norm($sampleCell.text());
        const hasImg = $sampleCell.find('img').length > 0;
        const controlsCount = $sampleCell.find('button,input,select,textarea').length;
        if (!sampleText && controlsCount > 0) return true;
        if (!sampleText && hasImg) return true;
      }
      return false;
    }

    function valueFromCell($cell) {
      const custom = $cell.attr('data-sort-value');
      const raw = custom !== undefined ? String(custom) : String($cell.text() || '');
      const text = raw.replace(/\s+/g, ' ').trim();
      if (!text) return { kind: 'text', value: '' };

      const maybeDate = Date.parse(text);
      if (!Number.isNaN(maybeDate) && /[0-9]/.test(text)) {
        return { kind: 'number', value: maybeDate };
      }

      const numeric = Number(text.replace(/[^0-9.+-]/g, ''));
      if (Number.isFinite(numeric) && /[0-9]/.test(text)) {
        return { kind: 'number', value: numeric };
      }

      return { kind: 'text', value: text.toLowerCase() };
    }

    function compareValues(a, b) {
      if (a.kind === 'number' && b.kind === 'number') {
        if (a.value === b.value) return 0;
        return a.value > b.value ? 1 : -1;
      }
      const x = String(a.value || '');
      const y = String(b.value || '');
      return x.localeCompare(y);
    }

    function updateIndicators($table, state) {
      $table.find('th .vs-sort-indicator').text('');
      if (state.colIndex < 0) return;
      const $active = $table.find('thead th').eq(state.colIndex);
      const marker = state.dir === 'asc' ? '^' : 'v';
      $active.find('.vs-sort-indicator').text(marker);
    }

    function applySort($table) {
      const tableEl = $table.get(0);
      if (!tableEl) return;
      const state = tableState.get(tableEl) || { colIndex: -1, dir: 'asc' };
      if (state.colIndex < 0) return;

      const $tbody = $table.children('tbody').first();
      if (!$tbody.length) return;

      const rows = $tbody.children('tr').toArray();
      if (!rows.length) return;

      const sortable = [];
      const fixed = [];

      rows.forEach((tr, idx) => {
        const $tr = $(tr);
        const cells = $tr.children('td');
        if (cells.length <= 1 || $tr.hasClass('no-results')) {
          fixed.push(tr);
          return;
        }
        sortable.push({ tr: tr, idx: idx, value: valueFromCell(cells.eq(state.colIndex)) });
      });

      sortable.sort((a, b) => {
        let cmp = compareValues(a.value, b.value);
        if (state.dir === 'desc') cmp *= -1;
        if (cmp !== 0) return cmp;
        return a.idx - b.idx;
      });

      sortable.forEach((x) => $tbody.append(x.tr));
      fixed.forEach((tr) => $tbody.append(tr));
      updateIndicators($table, state);
    }

    function rerenderTableState($table) {
      const $tab = $table.closest('.vs-tab');
      const tabId = $tab.attr('id') || '';

      if (tabId === 'tab-my-products') {
        vsLoadProductsPage(1, true);
        return;
      }
      if (tabId === 'tab-restore-products' && typeof window.vsApplyRestorePagination === 'function') {
        window.vsApplyRestorePagination(true);
        return;
      }
      if (tabId === 'tab-product-categories' && typeof window.vsApplyCategoriesPagination === 'function') {
        window.vsApplyCategoriesPagination(true);
        return;
      }
      if (tabId === 'tab-best-clients' && typeof window.vsApplyBestClientsPagination === 'function') {
        window.vsApplyBestClientsPagination(true);
        return;
      }
      if (tabId === 'tab-wallet' && typeof window.vsApplyWalletPagination === 'function') {
        window.vsApplyWalletPagination(true);
        return;
      }
      if (tabId === 'tab-my-orders') {
        const $ordersSearch = $('#vs-orders-search');
        if ($ordersSearch.length) {
          $ordersSearch.trigger('input');
          return;
        }
      }
      if (typeof window.vsRefreshGenericPagers === 'function') {
        window.vsRefreshGenericPagers(true);
      }
    }

    function initTable($table) {
      if (!$table.length) return;
      if ($table.hasClass('vs-best-clients-table')) return; // custom sorter already exists
      if ($table.find('th.vs-sortable').length) return; // custom sorter already exists
      if ($table.attr('data-vs-sort-init') === '1') return;

      const $thead = $table.children('thead');
      const $tbody = $table.children('tbody');
      if (!$thead.length || !$tbody.length) return;

      const $ths = $thead.find('th');
      if ($ths.length < 2) return;

      let sortableCount = 0;
      $ths.each(function (idx) {
        const $th = $(this);
        if (isNoSortHeader($th, idx, $table)) {
          $th.attr('data-vs-sortable-col', '0');
          return;
        }
        sortableCount += 1;
        $th.attr('data-vs-sortable-col', '1');
        if (!$th.find('.vs-sort-indicator').length) {
          $th.append('<span class="vs-sort-indicator"></span>');
        }
      });

      if (!sortableCount) return;

      $table.addClass('vs-table-sortable');
      $table.attr('data-vs-sort-init', '1');
      tableState.set($table.get(0), { colIndex: -1, dir: 'asc' });
    }

    function initTables(scope) {
      const $scope = $(scope || document);
      $scope.find('.vs-tab table').each(function () {
        initTable($(this));
      });
    }

    window.vsRefreshTableSorters = function (scope) {
      initTables(scope || document);
    };

    $(document).on('click', '.vs-table-sortable thead th[data-vs-sortable-col="1"]', function () {
      const $th = $(this);
      const $table = $th.closest('table');
      const tableEl = $table.get(0);
      if (!tableEl) return;

      const $all = $table.find('thead th');
      const idx = $all.index($th);
      if (idx < 0) return;

      const state = tableState.get(tableEl) || { colIndex: -1, dir: 'asc' };
      if (state.colIndex === idx) {
        state.dir = state.dir === 'asc' ? 'desc' : 'asc';
      } else {
        state.colIndex = idx;
        state.dir = 'asc';
      }
      tableState.set(tableEl, state);

      applySort($table);
      rerenderTableState($table);
    });

    ensureSortStyle();
    initTables(document);
    $(document).on('click', '.vs-tab-link', function () {
      setTimeout(function () {
        initTables(document);
      }, 120);
    });
  })();


  // ==============================
  // Product Management: Add, Edit, Delete, Select
  // ==============================

  // --- Product Filtering & Search (Merged from vs-core.js) ---
  const $productTable = $('#tab-my-products .vs-products-table');
  if ($('#vs-product-search').length) {
    const $tbody = $productTable.find('tbody');

    $('#vs-product-search').on('keyup', function () {
      const val = $(this).val().toLowerCase().trim();
      const $rows = $productTable.find('tbody tr');

      if (!val) {
        // أظهر كل المنتجات
        $rows.not('.no-results').show().each(function () {
          const $nameTd = $(this).find('td.product-name');
          const $descTd = $(this).find('td.product-desc');

          $nameTd.html($nameTd.data('original') || $nameTd.text());
          $descTd.html($descTd.data('original') || $descTd.text());
        });

        // أخفِ صف "لا توجد منتجات"
        $rows.filter('.no-results').hide();
      } else {
        // البحث العادي
        $rows.not('.no-results').each(function () {
          const $nameTd = $(this).find('td.product-name');
          const $descTd = $(this).find('td.product-desc');

          // خزّن النص الأصلي مرة واحدة
          if (!$nameTd.data('original')) $nameTd.data('original', $nameTd.text());
          if (!$descTd.data('original')) $descTd.data('original', $descTd.text());

          const nameText = $nameTd.data('original');
          const descText = $descTd.data('original');

          const match =
            nameText.toLowerCase().includes(val) ||
            descText.toLowerCase().includes(val);

          $(this).toggle(match);

          if (match && val) {
            $nameTd.html(highlight(nameText, val));
            $descTd.html(highlight(descText, val));
          } else {
            $nameTd.html(nameText);
            $descTd.html(descText);
          }
        });

        // إظهار صف "لا توجد منتجات" إذا لم يوجد أي صف مرئي
        const anyVisible = $rows.not('.no-results').filter(':visible').length > 0;
        $rows.filter('.no-results').toggle(!anyVisible);
      }

      if (typeof saveSearch === 'function') saveSearch(val);
      checkProductResults();

    });


    // دالة highlight
    function highlight(text, term) {
      if (!term) return text;
      const regex = new RegExp(`(${term})`, 'gi');
      return text.replace(regex, '<span class="vs-highlight">$1</span>');
    }




    function saveSearch(term) {
      if (!term) return;

      let history = JSON.parse(localStorage.getItem('vsSearchHistory')) || [];

      history = history.filter(item => item !== term);
      history.unshift(term);

      if (history.length > 5) history.pop();

      localStorage.setItem('vsSearchHistory', JSON.stringify(history));
    }
   
    // Filter by stock
    $('#vs-product-filter-stock').on('change', function () {
      const val = $(this).val();
      $('#tab-my-products .vs-products-table tbody tr').not('.no-results').each(function () {
        const stock = $(this).find('td.product-stock').text().trim();
        if (val === "in-stock") $(this).toggle(stock !== '0' && stock !== 'OOS' && stock !== 'N/A');
        else if (val === "out-of-stock") $(this).toggle(stock === '0' || stock === 'OOS' || stock === 'N/A');
        else $(this).show();
      });
      checkProductResults();
    });

    // Filter by price
    $('#vs-product-filter-price').on('change', function () {
      const val = $(this).val();
      let rows = $('#tab-my-products .vs-products-table tbody tr').not('.no-results').get();

      rows.sort(function (a, b) {
        const priceA = parseFloat($(a).find('td.product-price').text().replace('$', '').replace(/,/g, '')) || 0;
        const priceB = parseFloat($(b).find('td.product-price').text().replace('$', '').replace(/,/g, '')) || 0;
        return val === 'low' ? priceA - priceB : priceB - priceA;
      });

      $.each(rows, function (index, row) {
        $tbody.append(row);
      });
      checkProductResults();
    });

    checkProductResults();
  }
  // عند الضغط على تبويب المنتجات
  $('#tab-my-products-tab').on('click', function () {
    // أظهر التبويب
    $('#tab-my-products').show();
    // أخفِ التبويبات الأخرى
    $('.vs-tab').not('#tab-my-products').hide();

    // شغّل الفحص الآن
    checkProductResults();
  });

  function checkProductResults() {
    const $tab = $('#tab-my-products');
    if (!$tab.is(':visible')) return; // لا تفعل شيء إذا التبويب مخفي

    const $table = $('#tab-my-products .vs-products-table');
    const visibleRows = $table.find('tbody tr').not('.no-results').filter(':visible').length;

    // إنشاء عنصر No Products إذا لم يوجد
    let $empty = $('#vs-no-products');
    if (!$empty.length) {
      const emptySrc = $('#vs-products-pane').data('empty-src') || '';
      const imgHtml = emptySrc ? `<img src="${emptySrc}" class="vs-empty-anim" alt="No products" style="max-width:220px; opacity:0.8;">` : '';
      $empty = $(`
            <div id="vs-no-products" style="display:none; text-align:center; padding:40px;">
                ${imgHtml}
                <p id="vs-no-products-text" data-default="No products found" style="color:#777; font-size:16px;">No products found</p>
            </div>
        `);
      $table.after($empty);
    }

    const $emptyText = $('#vs-no-products-text');

    if (visibleRows === 0) {
      $emptyText.text($('#vs-product-search').val().trim() ? 'No products match your search' : $emptyText.data('default'));
      $empty.fadeIn();
    } else {
      $empty.hide();
    }
  }

  // ==============================
  // TRUE DB-SIDE PAGINATION via AJAX
  // ==============================
  let vsProductsCurrentPage = 1;
  let vsProductsTotalPages  = 1;

  function vsRenderProductsPager(currentPage, totalPages) {
    const $pager = $('#vs-products-pagination');
    if (!$pager.length) return;

    totalPages  = Math.max(1, totalPages);
    currentPage = Math.min(currentPage, totalPages);

    const btn = (label, page, disabled, active) => {
      const cls = ['vs-page-btn', disabled ? 'is-disabled' : '', active ? 'is-active' : ''].join(' ').trim();
      return `<button type="button" class="${cls}" data-page="${page}" ${disabled ? 'disabled' : ''}>${label}</button>`;
    };

    let html = '';
    html += btn(vsText('prev', 'Prev'), Math.max(1, currentPage - 1), currentPage === 1, false);
    const start = Math.max(1, currentPage - 2);
    const end   = Math.min(totalPages, start + 4);
    for (let p = start; p <= end; p++) {
      html += btn(String(p), p, false, p === currentPage);
    }
    html += btn(vsText('next', 'Next'), Math.min(totalPages, currentPage + 1), currentPage === totalPages, false);
    $pager.html(html);
  }

  function vsLoadProductsPage(page, resetPage) {
    if (resetPage) page = 1;
    if (!window.vs_vars || !vs_vars.ajaxurl) return;

    const $tbody  = $('#vs-products-tbody');
    const $pager  = $('#vs-products-pagination');
    if (!$tbody.length) return;

    // Gather current filter values
    const search       = ($('#vs-product-search').val()       || '').trim();
    const stockFilter  = ($('#vs-product-filter-stock').val() || '').trim();
    const vendorFilter = ($('#vs-filter-vendor-id').val()     || 'all').trim();
    const metricFilter = (typeof getMetricFilterValue === 'function') ? getMetricFilterValue() : '';

    // Show loading indicator
    $tbody.html('<tr><td colspan="8" style="text-align:center;padding:30px;color:#94a3b8;">'
      + (vsText ? vsText('loading', 'Loading...') : 'Loading...') + '</td></tr>');

    jQuery.post(vs_vars.ajaxurl, {
      action:        'vs_get_products_page',
      security:      vs_vars.nonce,
      paged:         page,
      search:        search,
      stock_filter:  stockFilter,
      vendor_filter: vendorFilter !== 'all' ? vendorFilter : 0,
      status_filter: metricFilter,
    }, function(response) {
      if (!response.success) return;
      const d = response.data;
      vsProductsCurrentPage = d.paged;
      vsProductsTotalPages  = d.total_pages;
      $tbody.html(d.rows);
      vsRenderProductsPager(d.paged, d.total_pages);
    }).fail(function() {
      $tbody.html('<tr><td colspan="8" style="text-align:center;padding:30px;color:#e74c3c;">Error loading products.</td></tr>');
    });
  }

  // Expose for external calls (tab switch, filter reset, etc.)
  window.vsApplyProductsPagination = function(reset) { vsLoadProductsPage(vsProductsCurrentPage, !!reset); };

  // Click on pager buttons
  jQuery(document).on('click', '#vs-products-pagination .vs-page-btn', function () {
    const p = Number(jQuery(this).data('page') || 1);
    vsProductsCurrentPage = p;
    vsLoadProductsPage(p, false);
  });

  // Initial render of pager from PHP-provided data
  (function initProductsPager() {
    const $pager = $('#vs-products-pagination');
    if (!$pager.length) return;
    const totalPages = parseInt($pager.data('total-pages') || 1, 10);
    const total      = parseInt($pager.data('total')       || 0, 10);
    const perPage    = parseInt($pager.data('per-page')    || 10, 10);
    vsProductsTotalPages = totalPages;
    vsRenderProductsPager(1, totalPages);
  })();

  // ==============================
  // Shared pager renderer
  // ==============================
  function vsRenderPager($pager, currentPage, totalPages, onClickFn) {
    if (!$pager.length) return;
    const btn = (label, page, disabled, active) => {
      const cls = ['vs-page-btn', disabled ? 'is-disabled' : '', active ? 'is-active' : ''].join(' ').trim();
      return `<button type="button" class="${cls}" data-page="${page}" ${disabled ? 'disabled' : ''}>${label}</button>`;
    };
    let html = '';
    html += btn(vsText ? vsText('prev','Prev') : 'Prev', Math.max(1, currentPage-1), currentPage===1, false);
    const start = Math.max(1, currentPage-2);
    const end   = Math.min(totalPages, start+4);
    for (let p = start; p <= end; p++) html += btn(String(p), p, false, p===currentPage);
    html += btn(vsText ? vsText('next','Next') : 'Next', Math.min(totalPages, currentPage+1), currentPage===totalPages, false);
    $pager.html(html);
    $pager.off('click.vspager').on('click.vspager', '.vs-page-btn', function() {
      onClickFn(Number(jQuery(this).data('page') || 1));
    });
  }

  // ==============================
  // Restore Products – AJAX Pagination
  // ==============================
  let vsRestoreCurrentPage = 1;

  function vsLoadRestorePage(page, reset) {
    if (!window.vs_vars || !vs_vars.ajaxurl) return;
    if (reset) page = 1;
    vsRestoreCurrentPage = page;
    const $tbody = jQuery('#tab-restore-products .vs-products-table tbody');
    const $pager = jQuery('#vs-restore-pagination');
    if (!$tbody.length) return;
    const search = jQuery('#vs-restore-search').val() || '';
    $tbody.html('<tr><td colspan="5" style="text-align:center;padding:30px;color:#94a3b8;">' + (vsText ? vsText('loading','Loading...') : 'Loading...') + '</td></tr>');
    jQuery.post(vs_vars.ajaxurl, {
      action: 'vs_page_restore', security: vs_vars.nonce, paged: page, search: search,
    }, function(response) {
      if (!response.success) return;
      const d = response.data;
      vsRestoreCurrentPage = d.paged;
      $tbody.html(d.rows);
      vsRenderPager($pager, d.paged, d.total_pages, function(p) { vsLoadRestorePage(p, false); });
    }).fail(function() {
      $tbody.html('<tr><td colspan="5" style="text-align:center;padding:30px;color:#e74c3c;">Error loading products.</td></tr>');
    });
  }

  function vsApplyRestorePagination(reset) { vsLoadRestorePage(vsRestoreCurrentPage, !!reset); }
  window.vsApplyRestorePagination = vsApplyRestorePagination;


  // ==============================
  // Wallet Transaction Pagination (Simple version like Orders)
  // ==============================
  let vsWalletCurrentPage = 1;
  const VS_WALLET_PAGE_SIZE = 10;

  function vsApplyWalletPagination(reset) {
    const $tbody = jQuery('#vs-transaction-history-body');
    const $pager = jQuery('#vs-wallet-pagination');
    if (!$tbody.length || !$pager.length) return;

    if (reset) vsWalletCurrentPage = 1;

    const $rows = $tbody.find('tr').not(':has(td[colspan])'); // On ignore le message "No Activity"
    const total = $rows.length;

    // Toujours afficher le pager comme demandé
    $pager.show();

    const totalPages = Math.max(1, Math.ceil(total / VS_WALLET_PAGE_SIZE));
    vsWalletCurrentPage = Math.min(vsWalletCurrentPage, totalPages);

    // Filter view
    if (total > 0) {
      $rows.hide();
      const st = (vsWalletCurrentPage - 1) * VS_WALLET_PAGE_SIZE;
      $rows.slice(st, st + VS_WALLET_PAGE_SIZE).show();
    }

    // Render Pager Buttons
    const btn = (label, page, disabled, active) => {
      const cls = ['vs-page-btn', disabled ? 'is-disabled' : '', active ? 'is-active' : ''].join(' ').trim();
      const stl = active ? 'padding:8px 15px; background:#667eea; color:white; border-radius:5px;' : 'padding:8px 15px;';
      return `<button type="button" class="${cls}" data-page="${page}" style="${stl}" ${disabled ? 'disabled' : ''}>${label}</button>`;
    };

    let phtml = '';
    phtml += btn(vsText('prev', 'Prev'), Math.max(1, vsWalletCurrentPage - 1), vsWalletCurrentPage === 1, false);
    for (let p = 1; p <= totalPages; p++) {
      if (totalPages > 5 && Math.abs(p - vsWalletCurrentPage) > 2 && p !== 1 && p !== totalPages) continue;
      phtml += btn(String(p), p, false, p === vsWalletCurrentPage);
    }
    phtml += btn(vsText('next', 'Next'), Math.min(totalPages, vsWalletCurrentPage + 1), vsWalletCurrentPage === totalPages, false);

    $pager.show().html(phtml);
  }

  window.vsApplyWalletPagination = vsApplyWalletPagination;

  jQuery(document).on('click', '#vs-wallet-pagination .vs-page-btn', function () {
    vsWalletCurrentPage = Number(jQuery(this).data('page') || 1);
    vsApplyWalletPagination(false);
  });

  // ==============================
  // Categories – AJAX Pagination
  // ==============================
  let vsCategoriesCurrentPage = 1;

  function vsLoadCategoriesPage(page, reset) {
    if (!window.vs_vars || !vs_vars.ajaxurl) return;
    if (reset) page = 1;
    vsCategoriesCurrentPage = page;
    const $tbody = jQuery('.vs-categories-table tbody');
    const $pager = jQuery('#vs-categories-pagination');
    if (!$tbody.length) return;
    const search = jQuery('#vs-category-search').val() || '';
    $tbody.html('<tr><td colspan="6" style="text-align:center;padding:30px;color:#94a3b8;">' + (vsText ? vsText('loading','Loading...') : 'Loading...') + '</td></tr>');
    jQuery.post(vs_vars.ajaxurl, {
      action: 'vs_page_categories', security: vs_vars.nonce, paged: page, search: search,
    }, function(response) {
      if (!response.success) return;
      const d = response.data;
      vsCategoriesCurrentPage = d.paged;
      $tbody.html(d.rows);
      vsRenderPager($pager, d.paged, d.total_pages, function(p) { vsLoadCategoriesPage(p, false); });
    }).fail(function() {
      $tbody.html('<tr><td colspan="6" style="text-align:center;padding:30px;color:#e74c3c;">Error loading categories.</td></tr>');
    });
  }

  function vsApplyCategoriesPagination(reset) { vsLoadCategoriesPage(vsCategoriesCurrentPage, !!reset); }
  window.vsApplyCategoriesPagination = vsApplyCategoriesPagination;


  // ==============================
  // Best Clients – AJAX Pagination
  // ==============================
  let vsBestClientsCurrentPage = 1;
  let vsBestClientsSort = { key: 'total_spent', dir: 'desc' };

  function vsLoadBestClientsPage(page, reset) {
    if (!window.vs_vars || !vs_vars.ajaxurl) return;
    if (reset) page = 1;
    vsBestClientsCurrentPage = page;
    const $tbody = jQuery('.vs-best-clients-table tbody');
    const $pager = jQuery('#vs-best-clients-pagination');
    if (!$tbody.length) return;
    const search = jQuery('#vs-best-clients-search').val() || '';
    const period = jQuery('[name="vs_clients_period"]').val() || 'all';
    $tbody.html('<tr><td colspan="6" style="text-align:center;padding:30px;color:#94a3b8;">' + (vsText ? vsText('loading','Loading...') : 'Loading...') + '</td></tr>');
    jQuery.post(vs_vars.ajaxurl, {
      action: 'vs_page_best_clients', security: vs_vars.nonce,
      paged: page, search: search, period: period,
      sort: vsBestClientsSort.key, direction: vsBestClientsSort.dir,
    }, function(response) {
      if (!response.success) return;
      const d = response.data;
      vsBestClientsCurrentPage = d.paged;
      $tbody.html(d.rows);
      vsRenderPager($pager, d.paged, d.total_pages, function(p) { vsLoadBestClientsPage(p, false); });
    }).fail(function() {
      $tbody.html('<tr><td colspan="6" style="text-align:center;padding:30px;color:#e74c3c;">Error loading clients.</td></tr>');
    });
  }

  function vsApplyBestClientsPagination(reset) { vsLoadBestClientsPage(vsBestClientsCurrentPage, !!reset); }
  window.vsApplyBestClientsPagination = vsApplyBestClientsPagination;

  // Hook sort headers to AJAX
  jQuery(document).on('click', '.vs-best-clients-table th.vs-sortable', function() {
    const key = String(jQuery(this).data('sort-key') || 'total_spent');
    if (vsBestClientsSort.key === key) {
      vsBestClientsSort.dir = vsBestClientsSort.dir === 'asc' ? 'desc' : 'asc';
    } else {
      vsBestClientsSort.key = key;
      vsBestClientsSort.dir = 'desc';
    }
    vsLoadBestClientsPage(1, false);
  });

  // Hook search
  jQuery(document).on('keyup', '#vs-best-clients-search', function() { vsLoadBestClientsPage(1, false); });


  function setMetricValue(selector, value) {
    const $el = $(selector);
    if ($el.length) {
      $el.text(String(value));
    }
  }

  function toNumberOrNull(value) {
    if (value === null || value === undefined) return null;
    const str = String(value).trim();
    if (!str || str.toLowerCase() === 'n/a') return null;
    const parsed = Number(str.replace(/[^0-9.\-]/g, ''));
    return Number.isFinite(parsed) ? parsed : null;
  }

  function formatStockCellHtml(value) {
    if (value === null || value === undefined) return 'N/A';
    const raw = String(value).trim();
    if (!raw || raw.toLowerCase() === 'n/a') return 'N/A';
    if (raw.toUpperCase() === 'OOS') return '<span class="vs-status-badge rejected">OOS</span>';

    const parsed = toNumberOrNull(raw);
    if (parsed !== null && parsed <= 0) {
      return '<span class="vs-status-badge rejected">OOS</span>';
    }

    return $('<div>').text(raw).html();
  }

  function refreshProductMetricsFromTable() {
    const $rows = $('#tab-my-products .vs-products-table tbody tr').not('.no-results');

    let total = 0;
    let published = 0;
    let draft = 0;
    let pending = 0;
    let inStock = 0;
    let lowStock = 0;

    $rows.each(function () {
      total += 1;

      const $row = $(this);
      const $editBtn = $row.find('.vs-edit-btn').first();
      const status = String($editBtn.data('product-status') || $editBtn.attr('data-product-status') || '').toLowerCase().trim();

      if (status === 'publish') published += 1;
      else if (status === 'draft') draft += 1;
      else if (status === 'pending') pending += 1;

      const stockFromBtn = toNumberOrNull($editBtn.data('product-stock'));
      const stockFromCell = toNumberOrNull($row.find('td.product-stock').text());
      const stockValue = stockFromBtn !== null ? stockFromBtn : stockFromCell;

      if (stockValue !== null && stockValue > 0) {
        inStock += 1;
      }
      if (stockValue !== null && stockValue <= 5) {
        lowStock += 1;
      }
    });

    setMetricValue('#vs-metric-total-products', total);
    setMetricValue('#vs-metric-published-products', published);
    setMetricValue('#vs-metric-draft-products', draft);
    setMetricValue('#vs-metric-pending-products', pending);
    setMetricValue('#vs-metric-in-stock-products', inStock);
    setMetricValue('#vs-metric-low-stock-products', lowStock);
  }

  refreshProductMetricsFromTable();

  function highlightTerm(text, term) {
    if (!term) return text;
    const safeTerm = term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    const regex = new RegExp(`(${safeTerm})`, 'gi');
    return text.replace(regex, '<span class="vs-highlight">$1</span>');
  }

  function saveSearchTerm(term) {
    if (!term) return;
    let history = JSON.parse(localStorage.getItem('vsSearchHistory')) || [];
    history = history.filter(item => item !== term);
    history.unshift(term);
    if (history.length > 5) history.pop();
    localStorage.setItem('vsSearchHistory', JSON.stringify(history));
  }

  function getMetricFilterValue() {
    const active = $('.vs-metric-filter.is-active').first().data('metric-filter');
    return String(active || 'all').toLowerCase();
  }

  function getProductRowStatus($row) {
    const $editBtn = $row.find('.vs-edit-btn').first();
    return String($editBtn.data('product-status') || $editBtn.attr('data-product-status') || '').toLowerCase().trim();
  }

  function getProductRowStock($row) {
    const $editBtn = $row.find('.vs-edit-btn').first();
    const stockFromBtn = toNumberOrNull($editBtn.data('product-stock'));
    if (stockFromBtn !== null) return stockFromBtn;
    return toNumberOrNull($row.find('td.product-stock').text());
  }

  function applyUnifiedProductFilters() {
    // All filtering is handled server-side — reload from page 1 with current filter values
    vsLoadProductsPage(1, true);
  }

  function initUnifiedProductFilters() {
    const $table = $('#tab-my-products .vs-products-table');
    if (!$table.length) return;

    $('#vs-product-search').off('keyup').on('keyup.vsUnifiedFilter', function () {
      const value = ($(this).val() || '').toLowerCase().trim();
      saveSearchTerm(value);
      applyUnifiedProductFilters();
    });

    $('#vs-product-filter-stock').off('change').on('change.vsUnifiedFilter', function () {
      applyUnifiedProductFilters();
    });

    $('#vs-filter-vendor-id').off('change').on('change.vsUnifiedFilter', function () {
      applyUnifiedProductFilters();
    });

    $('#vs-product-filter-price').off('change').on('change.vsUnifiedFilter', function () {
      const val = $(this).val();
      const $tbody = $('#tab-my-products .vs-products-table tbody');
      let rows = $tbody.find('tr').not('.no-results').get();

      rows.sort(function (a, b) {
        const priceA = parseFloat($(a).find('td.product-price').text().replace('$', '').replace(/,/g, '')) || 0;
        const priceB = parseFloat($(b).find('td.product-price').text().replace('$', '').replace(/,/g, '')) || 0;
        return val === 'low' ? priceA - priceB : priceB - priceA;
      });

      $.each(rows, function (_index, row) {
        $tbody.append(row);
      });

      applyUnifiedProductFilters();
    });

    $(document).off('click.vsMetricFilter', '.vs-metric-filter').on('click.vsMetricFilter', '.vs-metric-filter', function () {
      $('.vs-metric-filter').removeClass('is-active');
      $(this).addClass('is-active');
      applyUnifiedProductFilters();
    });

    $(document).off('keydown.vsMetricFilter', '.vs-metric-filter').on('keydown.vsMetricFilter', '.vs-metric-filter', function (e) {
      if (e.key === 'Enter' || e.key === ' ') {
        e.preventDefault();
        $(this).trigger('click');
      }
    });

    applyUnifiedProductFilters();
  }

  initUnifiedProductFilters();

  // Show add product form
  $(document).on('click', '#add-product-btn-show', function (e) {
    e.preventDefault();
    const wrapper = $('#add-product-form-wrapper');
    if (wrapper.length) {
      $('#vs-edit-product-wrapper').slideUp(200);
      wrapper.slideDown(300);
      $('html, body').animate({ scrollTop: wrapper.offset().top - 100 }, 500);
    } else {
      console.error('Form wrapper not found');
    }
  });

  // Show add product form from image click
  $(document).on('click', '#add-product-btn', function (e) {
    e.preventDefault();
    const wrapper = $('#add-product-form-wrapper');
    if (wrapper.length) {
      $('#vs-edit-product-wrapper').slideUp(200);
      wrapper.slideDown(300);
      $('html, body').animate({ scrollTop: wrapper.offset().top - 100 }, 500);
    } else {
      console.error('Form wrapper not found');
    }
  });

  // Show add product form from sidebar menu item
  $(document).on('click', '#add-product-btn-menu', function (e) {
    e.preventDefault();
    openTab('my-products');
    setTimeout(function () {
      $('#add-product-btn-show').trigger('click');
    }, 120);
  });

  // Cancel add product
  $(document).on('click', '#vs-cancel-add', function (e) {
    e.preventDefault();
    $('#add-product-form-wrapper').slideUp(300);
    $('#vs-add-product-form')[0].reset();
    $('#add-product-type').trigger('change');

  });
  $('#vs-cancel-edit').click(function () {
    $('#vs-edit-product-wrapper').slideUp(300);
  });

  /* =========================
     Variable Products UI
  ========================= */
  function vsSlugify(str) {
    return String(str || '')
      .trim()
      .toLowerCase()
      .replace(/['"]/g, '')
      .replace(/[^a-z0-9]+/g, '-')
      .replace(/^-+|-+$/g, '');
  }

  function vsToggleVariableProductUI($form, type) {
    const isVariable = (type === 'variable');
    const $panel = $form.find('.vs-variable-product-panel').first();

    // Parent fields are not used for variable products in our backend.
    const $price = $form.find('[name="product_price"]').first();
    const $sale = $form.find('[name="product_sale_price"]').first();
    const $stock = $form.find('[name="product_stock"]').first();

    if (isVariable) {
      $panel.slideDown(150);

      // Disable + hide simple-only fields to avoid browser required validation.
      $price.prop('required', false).prop('disabled', true).closest('.vs-field').hide();
      $sale.prop('disabled', true).closest('.vs-field').hide();
      $stock.prop('required', false).prop('disabled', true).closest('.vs-field').hide();
    } else {
      $panel.slideUp(150);

      $price.prop('disabled', false).closest('.vs-field').show();
      $sale.prop('disabled', false).closest('.vs-field').show();
      $stock.prop('disabled', false).closest('.vs-field').show();

      // Keep the original required behavior for simple products.
      if ($form.attr('id') === 'vs-edit-product-form') {
        $price.prop('required', true);
        $stock.prop('required', true);
      } else if ($form.attr('id') === 'vs-add-product-form') {
        $price.prop('required', true);
      }
    }
  }

  $(document).on('change', '.vs-product-type-select', function () {
    const $select = $(this);
    const $form = $select.closest('form');
    vsToggleVariableProductUI($form, $select.val());
  });

  $(document).on('click', '.vs-add-attribute-btn', function (e) {
    e.preventDefault();
    const $form = $(this).closest('form');
    const $wrap = $form.find('.vs-attributes-wrapper').first();
    if (!$wrap.length) return;

    $wrap.append(`
      <div class="vs-attribute" style="display:flex; gap:10px; margin-bottom:10px;">
        <input type="text" class="vs-attr-name" name="attribute_name[]" placeholder="Attribute name (Size, Color)">
        <input type="text" class="vs-attr-values" name="attribute_values[]" placeholder="Values separated by | example: S|M|L">
        <button type="button" class="vs-remove-attr" style="padding:0 10px;">x</button>
      </div>
    `);
  });

  $(document).on('click', '.vs-remove-attr', function (e) {
    e.preventDefault();
    $(this).closest('.vs-attribute').remove();
  });

  function vsCartesian(attributes) {
    return attributes.reduce((acc, cur) => {
      const out = [];
      acc.forEach(prev => {
        cur.values.forEach(v => out.push(prev.concat([{ slug: cur.slug, name: cur.name, value: v }])));
      });
      return out;
    }, [[]]);
  }

  function vsEnableSortable($container) {
    if (!$container || !$container.length) return;
    if (typeof jQuery === 'undefined') return;
    if (typeof jQuery.fn.sortable !== 'function') return;
    try {
      $container.sortable({ handle: '.vs-variation-header' });
    } catch (_) {
      // ignore if jquery-ui sortable isn't available
    }
  }

  $(document).on('click', '.vs-generate-variations-btn', function (e) {
    e.preventDefault();
    const $form = $(this).closest('form');
    const $attrs = $form.find('.vs-attribute');
    const attributes = [];

    $attrs.each(function () {
      const $row = $(this);
      const name = String($row.find('.vs-attr-name').val() || '').trim();
      const raw = String($row.find('.vs-attr-values').val() || '').trim();
      if (!name || !raw) return;

      const slug = vsSlugify(name);
      const values = raw.split('|').map(v => String(v).trim()).filter(Boolean);
      if (!slug || !values.length) return;
      attributes.push({ name, slug, values });
    });

    if (!attributes.length) {
      Swal.fire(vsText('missing_attributes', 'Missing attributes'), vsText('add_attribute_values', 'Add at least one attribute with values.'), 'warning');
      return;
    }

    const combos = vsCartesian(attributes);
    const $container = $form.find('.vs-variations-container').first();
    if (!$container.length) return;
    $container.empty();

    combos.forEach((combo) => {
      const title = combo.map(a => `${a.name}:${a.value}`).join(' / ');
      const attrsMap = {};
      combo.forEach(a => { attrsMap[a.slug] = a.value; });

      $container.append(`
        <div class="vs-variation" style="border:1px solid #e5e7eb; border-radius:10px; margin-bottom:10px; background:#fff;">
          <div class="vs-variation-header" style="padding:12px; background:#f9fafb; display:flex; justify-content:space-between; cursor:move;">
            <strong>${title}</strong>
            <div>
              <button type="button" class="vs-variation-toggle" style="margin-right:6px;">v</button>
              <button type="button" class="vs-variation-delete">x</button>
            </div>
          </div>
          <div class="vs-variation-body" style="padding:15px; display:grid; grid-template-columns:repeat(4,1fr); gap:10px;">
            <input type="hidden" name="variation_title[]" value="${title}">
            <input type="hidden" name="variation_attrs[]" value="${$('<div>').text(JSON.stringify(attrsMap)).html()}">
            <input type="number" name="variation_price[]" step="0.01" placeholder="Price">
            <input type="number" name="variation_stock[]" step="1" min="0" placeholder="Stock">
            <input type="text" name="variation_sku[]" placeholder="SKU">
            <input type="file" name="variation_image[]">
          </div>
        </div>
      `);
    });

    vsEnableSortable($container);
  });

  $(document).on('click', '.vs-variation-toggle', function (e) {
    e.preventDefault();
    const $var = $(this).closest('.vs-variation');
    $var.find('.vs-variation-body').first().toggle();
  });

  $(document).on('click', '.vs-variation-delete', function (e) {
    e.preventDefault();
    $(this).closest('.vs-variation').remove();
  });

  $(document).on('click', '.vs-apply-bulk-btn', function (e) {
    e.preventDefault();
    const $form = $(this).closest('form');
    const price = String($form.find('.vs-bulk-price').first().val() || '').trim();
    const stock = String($form.find('.vs-bulk-stock').first().val() || '').trim();

    if (price !== '') {
      $form.find('input[name=\"variation_price[]\"]').val(price);
    }
    if (stock !== '') {
      $form.find('input[name=\"variation_stock[]\"]').val(stock);
    }
  });

  // Initialize panels for existing selects on first load.
  $('.vs-product-type-select').each(function () {
    const $select = $(this);
    vsToggleVariableProductUI($select.closest('form'), $select.val());
  });

  // Submit add product form
  $(document).on('submit', '#vs-add-product-form', function (e) {
    e.preventDefault();
    const formData = new FormData(this);
    formData.append('action', 'vs_add_product');
    Swal.fire({ title: vsText('adding_product', 'Adding Product...'), allowOutsideClick: false, didOpen: () => Swal.showLoading() });

    $.ajax({
      type: 'POST',
      url: vs_vars.ajaxurl,
      data: formData,
      processData: false,
      contentType: false,
      success: function (response) {
        console.log('Add product success:', response);
        if (response.success) {
          const d = response.data || {};
          const price = parseFloat(d.price || 0).toFixed(2);
          const stock = formatStockCellHtml(d.stock);

          const rowHtml = `
            <tr id="product-row-${d.product_id}" class="vs-row-added">
              <td><input type="checkbox" class="vs-select-product" value="${d.product_id}"></td>
              <td class="product-image">${d.img_html || vsText('no_image', 'No Image')}</td>
              <td class="product-name">${d.title || ''}</td>
              <td class="product-desc">${d.cats || '—'}</td>
              <td class="product-vendor">${d.vendor_email || vs_vars.current_user_email || ''}</td>
              <td class="product-price" style="display:none;">$${price}</td>
              <td class="product-stock">${stock}</td>
              <td class="product-status">
                  ${(() => {
                    const status = d.product_status || 'draft';
                    if (status === 'publish') {
                      return '<span class="vs-status-badge published">Published</span>';
                    } else if (status === 'pending') {
                      return '<span class="vs-status-badge pending">' + vsEscapeHtml(vsText('pending_approval', 'Pending Approval')) + '</span>';
                    } else {
                      return '<span class="vs-status-badge draft">Draft</span>';
                    }
                  })()}
              </td>
              <td style="min-width:5%;" data-export="skip">
                <div class="vs-action-buttons" style="display:flex; gap:5px; flex-wrap:nowrap; justify-content:flex-start;">
                 <button class="vs-delete-btn" 
        data-product-id="${d.product_id}" 
        style="background:#e74c3c; color:white; border:none; padding:5px 10px; border-radius:4px; cursor:pointer; transition:0.2s;">
    <i class="fas fa-trash"></i> 
</button>

<button class="vs-edit-btn"
        data-product-id="${d.product_id}"
        data-product-name="${d.title || ''}"
        data-product-desc="${d.desc || ''}"
        data-product-short-desc="${d.short_desc || ''}"
        data-product-price="${d.price || ''}"
        data-product-regular-price="${d.regular_price || ''}"
        data-product-sale-price="${d.sale_price || ''}"
        data-product-stock="${d.stock !== null && d.stock !== undefined ? d.stock : ''}"
        data-product-sku="${d.sku || ''}"
        data-product-type="${d.product_type || ''}"
        data-product-status="${d.product_status || ''}"
        data-product-cat="${d.product_cat || ''}"
        data-product-featured-id="${d.featured_id || ''}"
        data-product-featured-url="${d.featured_url || ''}"
        data-product-gallery-ids='${JSON.stringify(d.gallery_ids || [])}'
        data-product-gallery-urls='${JSON.stringify(d.gallery_urls || [])}'
        style="background:#3498db; color:white; border:none; padding:5px 10px; border-radius:4px; cursor:pointer; transition:0.2s;">
    <i class="fas fa-pen"></i> 
</button>

<button class="vs-quick-edit-btn" 
        data-product-id="${d.product_id}" 
        style="background:#0ea5e9; color:white; border:none; padding:5px 10px; border-radius:4px; cursor:pointer; transition:0.2s;">
    <i class="fas fa-bolt"></i> 
</button>

<a href="${d.permalink || '#'}" 
   target="_blank" 
   rel="noopener noreferrer" 
   class="vs-view-btn"
   style="background:#2ecc71; color:white; text-decoration:none; padding:5px 10px; border-radius:4px; cursor:pointer; transition:0.2s; display:flex; align-items:center; justify-content:center; gap:5px;">
    <i class="fas fa-eye"></i> 
</a>               </div>
              </td>
            </tr>
          `;

          let $table = $('.vs-products-table');
          if (!$table.length) {
            const tableHtml = `
              <table class="vs-products-table" style="width:100%; border:1px solid #ccc; border-collapse:collapse;">
                <thead>
                  <tr>
                    <th><input type="checkbox" id="vs-select-all"></th>
                    <th>${vsEscapeHtml(vsText('image', 'Image'))}</th>
                    <th>${vsEscapeHtml(vsText('name', 'Name'))}</th>
                    <th>${vsEscapeHtml(vsText('categories', 'Categories'))}</th>
                    <th>${vsEscapeHtml(vsText('vendor', 'Vendor'))}</th>
                    <th>${vsEscapeHtml(vsText('stock', 'Stock'))}</th>
                    <th>${vsEscapeHtml(vsText('status', 'Status'))}</th>
                    <th>${vsEscapeHtml(vsText('actions', 'Actions'))}</th>
                  </tr>
                </thead>
                <tbody></tbody>
              </table>
            `;
            $('.no-products').before(tableHtml);
            $table = $('.vs-products-table');
          }

          const $tbody = $table.find('tbody');
          $tbody.prepend(rowHtml);
          checkProductResults();
          refreshProductMetricsFromTable();
          initUnifiedProductFilters();
          applyUnifiedProductFilters();

          $('.no-products').hide();

          Swal.close();
          
          // Update the pending requests badge if product is pending approval
          if (response.data.pending_approval && response.data.pending_requests_count) {
            const pendingCount = response.data.pending_requests_count;
            
            // Update products badge
            const $productsBadge = $('#vs-products-badge');
            if ($productsBadge.length) {
              if (pendingCount > 0) {
                $productsBadge.show();
                $productsBadge.text(pendingCount);
              } else {
                $productsBadge.hide();
              }
            }
            
            // Update publish requests badge
            const $publishBadge = $('#vs-publish-requests-badge');
            if ($publishBadge.length) {
              if (pendingCount > 0) {
                $publishBadge.show();
                $publishBadge.text(pendingCount);
              } else {
                $publishBadge.hide();
              }
            }
          }
          
          // Check if product requires approval
          if (response.data.pending_approval) {
            Swal.fire({
              icon: 'warning',
              title: '⏳ Pending Administrator Approval',
              html: '<strong>Your product has been submitted for review!</strong><br><br>This product will <strong>NOT be visible</strong> to customers until it is approved by an administrator.<br><br>You will receive an email notification once it is reviewed.',
              confirmButtonColor: '#f59e0b',
              confirmButtonText: 'Got It!'
            });
          } else {
            showToast(vsText('product_added_successfully', 'Product added successfully'));
          }

          $('#vs-add-product-form')[0].reset();
          $('#add-product-form-wrapper').slideUp(200);

          setTimeout(function () {
            $('#product-row-' + d.product_id).removeClass('vs-row-added');
          }, 2200);
        } else {
          Swal.fire(vsText('error', 'Error'), response.data || vsText('failed_to_add_product', 'Failed to add product'), 'error');
        }
      },
      error: function (xhr, status, error) {
        console.log('AJAX Error:', error, xhr.responseText);
        Swal.fire(vsText('error', 'Error'), vsSprintf(vsText('failed_to_add_product_with_error', 'Failed to add product: %s'), error), 'error');
      }
    });
  });

  // Edit product button click

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

    const $form = $('#vs-edit-product-form');
    const $saveBtn = $form.find('button[type="submit"]');
    const $wrapper = $('#vs-edit-product-wrapper');
    let original = {};

    // ===== Style مرة واحدة =====
    if (!$('.vs-style').length) {
      $('<style class="vs-style">')
        .html(`
                .vs-btn-disabled {
                    opacity: 0.5;
                    cursor: not-allowed;
                    filter: grayscale(40%);
                    pointer-events: none;
                }
            `)
        .appendTo('head');
    }

    // تعطيل الزر افتراضياً
    disableSave();

    function disableSave() {
      $saveBtn.prop('disabled', true).addClass('vs-btn-disabled');
    }

    function enableSave() {
      $saveBtn.prop('disabled', false).removeClass('vs-btn-disabled');
    }

    // Sync TinyMCE changes with textarea to enable change detection
    if (typeof tinymce !== 'undefined') {
      const bindEditor = (editor) => {
        if (!editor) return;
        editor.on('change keyup', function () {
          const id = editor.id;
          $('#' + id).val(editor.getContent()).trigger('input');
        });
      };

      bindEditor(tinymce.get('edit_product_desc'));
      bindEditor(tinymce.get('edit_product_short_desc'));

      tinymce.on('AddEditor', function (e) {
        if (!e.editor) return;
        if (e.editor.id === 'edit_product_desc' || e.editor.id === 'edit_product_short_desc') {
          bindEditor(e.editor);
        }
      });
    }

    // ===== مراقبة التغييرات =====
    $form.on('input change', 'input, textarea, select', function () {

      let changed = false;

      $form.find('input, textarea, select').each(function () {
        const $el = $(this);
        const original = $el.attr('data-original');

        if ($el.attr('type') === 'file') {
          if ($el[0].files && $el[0].files.length > 0) {
            changed = true;
            return false;
          }
          return;
        }

        if (original !== undefined && $el.val() != original) {
          changed = true;
          return false;
        }
      });

      changed ? enableSave() : disableSave();
    });

    // ===== فتح نموذج التعديل =====
    $(document).on('click', '.vs-edit-btn', function (e) {
      e.preventDefault();
      const regularPrice = $(this).data('product-regular-price');
      const displayPrice = regularPrice !== undefined && regularPrice !== '' ? regularPrice : $(this).data('product-price');

      const fields = {
        'edit-product-id': $(this).data('product-id'),
        'edit-product-name': $(this).data('product-name'),
        'edit-product-price': displayPrice,
        'edit-product-sale-price': $(this).data('product-sale-price'),
        'edit-product-stock': $(this).data('product-stock'),
        'edit-product-sku': $(this).data('product-sku'),
        'edit-product-type': $(this).data('product-type'),
        'edit-product-status': $(this).data('product-status'),
        'edit-product-cat': $(this).data('product-cat')
      };

      for (let id in fields) {
        $('#' + id)
          .val(fields[id])
          .attr('data-original', fields[id]);
      }

      // Toggle variable UI for this product type.
      $('#edit-product-type').trigger('change');

      // Editors (description + short description)
      const desc = $(this).data('product-desc') || '';
      const shortDesc = $(this).data('product-short-desc') || '';

      $('#edit_product_desc')
        .val(desc)
        .attr('data-original', desc)
        .trigger('input');

      $('#edit_product_short_desc')
        .val(shortDesc)
        .attr('data-original', shortDesc)
        .trigger('input');

      if (typeof tinymce !== 'undefined') {
        const ed1 = tinymce.get('edit_product_desc');
        if (ed1) ed1.setContent(desc);
        const ed2 = tinymce.get('edit_product_short_desc');
        if (ed2) ed2.setContent(shortDesc);
      }

      // Current images (featured + gallery)
      $('#vs-remove-gallery-ids').val('');
      $('#vs-remove-featured').val('0');
      const featuredId = $(this).data('product-featured-id') || '';
      const featuredUrl = $(this).data('product-featured-url') || '';
      const galleryIdsRaw = $(this).attr('data-product-gallery-ids') || '[]';
      const galleryUrlsRaw = $(this).attr('data-product-gallery-urls') || '[]';
      let galleryIds = [];
      let galleryUrls = [];
      try { galleryIds = JSON.parse(galleryIdsRaw); } catch (e) { galleryIds = []; }
      try { galleryUrls = JSON.parse(galleryUrlsRaw); } catch (e) { galleryUrls = []; }

      const $imgBox = $('#vs-edit-images');
      $imgBox.empty();

      if (featuredId && featuredUrl) {
        $imgBox.append(`
                <div class="vs-edit-img" data-id="${featuredId}" data-type="featured">
                    <button type="button" class="vs-remove-img">×</button>
                    <img src="${featuredUrl}" alt="Featured">
                    <span class="vs-img-label">Featured</span>
                </div>
            `);
      }

      if (galleryIds.length) {
        galleryIds.forEach((gid, idx) => {
          const url = galleryUrls[idx] || '';
          if (!url) return;
          $imgBox.append(`
                    <div class="vs-edit-img" data-id="${gid}" data-type="gallery">
                        <button type="button" class="vs-remove-img">×</button>
                        <img src="${url}" alt="Gallery">
                        <span class="vs-img-label">Gallery</span>
                    </div>
                `);
        });
      }

      if (!$imgBox.children().length) {
        $imgBox.append('<div style="color:#777; font-size:12px;">No images</div>');
      }

      disableSave();

      $('#add-product-form-wrapper').slideUp(200);
      $('#vs-edit-product-wrapper').slideDown();
      $('html, body').animate({
        scrollTop: $('#vs-edit-product-wrapper').offset().top
      }, 500);
    });

    // ===== إرسال AJAX =====
    $form.on('submit', function (e) {
      e.preventDefault();

      Swal.fire({
        title: 'Confirm Update',
        text: 'Are you sure you want to save these changes?',
        icon: 'warning',
        showCancelButton: true,
        confirmButtonText: 'Yes, save it!'
      }).then((result) => {

        if (!result.isConfirmed) return;

        let formData = new FormData(this);
        formData.append('action', 'vs_edit_product');
        const restoreEditButton = setButtonBusy($saveBtn, vsText('updating', 'Updating...'));

        Swal.fire({
          title: 'Saving...',
          allowOutsideClick: false,
          didOpen: () => Swal.showLoading()
        });

        $.ajax({
          url: vs_vars.ajaxurl,
          type: 'POST',
          data: formData,
          processData: false,
          contentType: false,
          success: function (response) {

            Swal.close();
            if (response.success) {

              const pid = $('#edit-product-id').val();
              const $row = $('#product-row-' + pid);

              const newName = $('#edit-product-name').val();
              const newDesc = $('#edit_product_desc').val();
              const newShortDesc = $('#edit_product_short_desc').val();
              const newPrice = $('#edit-product-price').val();
              const newSalePrice = $('#edit-product-sale-price').val();
              const newStock = $('#edit-product-stock').val();
              const newSku = $('#edit-product-sku').val();
              const newType = $('#edit-product-type').val();
              const newStatus = $('#edit-product-status').val();
              const newCat = $('#edit-product-cat').val();

              const originalName = $('#edit-product-name').attr('data-original');
              const originalDesc = $('#edit_product_desc').attr('data-original');
              const originalPrice = $('#edit-product-price').attr('data-original');
              const originalStock = $('#edit-product-stock').attr('data-original');

              // تحديث القيم في الجدول
              // Reset cached 'original' values so applyUnifiedProductFilters shows the updated data
              $row.find('td.product-name').removeData('original');
              $row.find('td.product-desc').removeData('original');
              $row.find('.product-name').text(newName);
              $row.find('.product-desc').html(response.data && response.data.cats ? response.data.cats : '—');
              const serverType = (response.data && response.data.product_type) ? response.data.product_type : newType;
              const finalDisplayPrice = (serverType === 'variable' && response.data && response.data.price !== undefined)
                ? response.data.price
                : (newSalePrice ? newSalePrice : newPrice);
              const finalStock = (serverType === 'variable' && response.data && response.data.stock !== undefined)
                ? response.data.stock
                : newStock;

              const priceNumber = parseFloat(finalDisplayPrice || 0);
              $row.find('.product-price').text('$' + (isFinite(priceNumber) ? priceNumber.toFixed(2) : '0.00'));
              $row.find('.product-stock').html(formatStockCellHtml(finalStock));

              // Update Status Badge
              const serverStatus = response.data.product_status || newStatus;
              let badgeHtml = '<span class="vs-status-badge draft">Draft</span>';
              if (serverStatus === 'publish') badgeHtml = '<span class="vs-status-badge published">Published</span>';
              else if (serverStatus === 'pending') badgeHtml = '<span class="vs-status-badge pending">Pending Approval</span>';

              $row.find('.product-status').html(badgeHtml);


              if (response.data && response.data.img_html) {
                $row.find('.product-image').html(response.data.img_html);
              }
              // 🔄 تحديث data attributes في زر التعديل
              const $editBtn = $row.find('.vs-edit-btn');

              $editBtn
                .data('product-name', newName)
                .data('product-desc', newDesc)
                .data('product-short-desc', newShortDesc)
                .data('product-price', finalDisplayPrice)
                .data('product-regular-price', (serverType === 'variable') ? '' : newPrice)
                .data('product-sale-price', (serverType === 'variable') ? '' : newSalePrice)
                .data('product-stock', finalStock)
                .data('product-sku', newSku)
                .data('product-type', serverType)
                .data('product-status', serverStatus)
                .data('product-cat', newCat);

              refreshProductMetricsFromTable();
              applyUnifiedProductFilters();

              if (response.data) {
                $editBtn
                  .data('product-featured-id', response.data.featured_id || '')
                  .data('product-featured-url', response.data.featured_url || '')
                  .attr('data-product-gallery-ids', JSON.stringify(response.data.gallery_ids || []))
                  .attr('data-product-gallery-urls', JSON.stringify(response.data.gallery_urls || []));
              }

              // Reset previous highlight classes
              $row.removeClass('vs-update-price vs-update-stock vs-update-text vs-pulse vs-row-added');

              // Scroll
              $('html, body').animate({
                scrollTop: $row.offset().top - 120
              }, 400);

              // Use same highlight as "add" effect
              $row.addClass('vs-row-added');

              // Check if product requires approval
              if (response.data.pending_approval) {
                Swal.fire({
                  icon: 'warning',
                  title: '⏳ Pending Administrator Approval',
                  html: '<strong>Your product has been updated and re-submitted for review!</strong><br><br>This product will <strong>NOT be visible</strong> to customers until it is approved by an administrator.<br><br>You will receive an email notification once it is reviewed.',
                  confirmButtonColor: '#f59e0b',
                  confirmButtonText: 'Got It!'
                });
              } else {
                showToast(vsText('product_updated_successfully', 'Product updated successfully'));
              }

              // إزالة التأثير
              setTimeout(() => {
                $row.removeClass('vs-row-added');
              }, 2200);

              // Reset file input + hide edit form to avoid accidental resubmit
              $('#edit-product-image').val('');
              $wrapper.slideUp(200);

              restoreEditButton();
              disableSave();
            }



            else {
              restoreEditButton();
              Swal.fire(vsText('error', 'Error'), response.data || vsText('update_failed', 'Update failed.'), 'error');
            }
          },
          error: function () {
            restoreEditButton();
            Swal.close();
            Swal.fire(vsText('error', 'Error'), vsText('ajax_request_failed', 'AJAX request failed.'), 'error');
          }
        });
      });
    });

  });

  function scrollToRow($row) {
    $('html, body').animate({
      scrollTop: $row.offset().top - 120
    }, 500);
  }

  function showToast(msg, icon = 'success') {
    Swal.fire({
      toast: true,
      position: 'top-end',
      icon: icon,
      title: msg,
      showConfirmButton: false,
      timer: 2500,
      timerProgressBar: true
    });
  }

  // Delete single product

  let productCount = Number($('#vs-products-wrapper').data('product-count')) || 0;









  $(document).on('click', '.vs-delete-btn', function (e) {
    e.preventDefault();
    const pid = $(this).data('product-id');
    const $row = $('#product-row-' + pid).length ? $('#product-row-' + pid) : $('#vs-restore-row-' + pid);

    const mode_attr = $(this).data('mode');

    if (mode_attr === 'permanent') {
      Swal.fire({
        title: vsText('delete_permanently', 'Delete Permanently?'),
        text: 'This product will be gone forever!',
        icon: 'warning',
        showCancelButton: true,
        confirmButtonColor: '#d33',
        confirmButtonText: vsText('yes_delete_forever', 'Yes, Delete Forever')
      }).then((result) => {
        if (result.isConfirmed) {
          executeDelete(pid, 'permanent', $row);
        }
      });
    } else {
      Swal.fire({
        title: vsText('delete_product', 'Delete Product?'),
        text: vsText('move_product_to_trash_or_delete', 'Do you want to move this product to the trash or delete it permanently?'),
        icon: 'warning',
        showCancelButton: true,
        showDenyButton: true,
        confirmButtonText: '<i class="fas fa-trash"></i> ' + vsText('move_to_trash', 'Move to Trash'),
        denyButtonText: '<i class="fas fa-times"></i> ' + vsText('delete_permanently_action', 'Delete Permanently'),
        confirmButtonColor: '#ff9800',
        denyButtonColor: '#d33',
        cancelButtonColor: '#3085d6',
      }).then((result) => {
        let mode = '';
        if (result.isConfirmed) mode = 'trash';
        else if (result.isDenied) mode = 'permanent';
        else return;
        executeDelete(pid, mode, $row);
      });
    }

    function executeDelete(pid, mode, $row) {
      Swal.fire({
        title: mode === 'trash' ? vsText('trashing', 'Trashing...') : vsText('deleting', 'Deleting...'),
        text: vsText('please_wait', 'Please wait'),
        allowOutsideClick: false,
        didOpen: () => {
          Swal.showLoading();
        }
      });
      $.ajax({
        type: 'POST',
        url: vs_vars.ajaxurl,
        data: {
          action: 'vs_delete_product',
          product_id: pid,
          mode: mode,
          security: $('input[name="security"]').val()
        },
        dataType: 'json',
        success: function (response) {
          if (response.success) {
            $row.fadeOut(300, function () {
              const fromRestore = $row.closest('#tab-restore-products').length > 0;
              $(this).remove();
              checkProductResults();
              refreshProductMetricsFromTable();
              applyUnifiedProductFilters();
              if (typeof refreshSidebarNotifCount === 'function') refreshSidebarNotifCount();

              if (mode === 'trash' || fromRestore) {
                refreshRestoreTab();
              }
            });

            Swal.fire(
              mode === 'trash' ? vsText('moved_to_trash', 'Moved to Trash!') : vsText('deleted', 'Deleted!'),
              mode === 'trash' ? vsText('product_moved_to_trash', 'Product has been moved to trash.') : vsText('product_deleted_permanently', 'Product has been permanently deleted.'),
              'success'
            );
          } else {
            Swal.fire(vsText('error', 'Error'), response.data || vsText('failed_to_delete', 'Failed to delete'), 'error');
          }
        },
        error: function (xhr, status, error) {
          console.log('AJAX Error:', error, xhr.responseText);
          Swal.fire(vsText('error', 'Error'), vsText('failed_to_delete_product', 'Failed to delete product'), 'error');
        }
      });
    }
  });

  // Restore product
  $(document).on('click', '.vs-restore-btn', function (e) {
    e.preventDefault();
    const pid = $(this).data('product-id');
    const $row = $('#product-row-' + pid).length ? $('#product-row-' + pid) : $('#vs-restore-row-' + pid);

    Swal.fire({
      title: vsText('restoring', 'Restoring...'),
      text: vsText('please_wait', 'Please wait'),
      allowOutsideClick: false,
      didOpen: () => {
        Swal.showLoading();
      }
    });

    $.ajax({
      type: 'POST',
      url: vs_vars.ajaxurl,
      data: {
        action: 'vs_restore_product',
        product_id: pid,
        security: $('input[name="security"]').val()
      },
      dataType: 'json',
      success: function (response) {
        if (response.success) {
          Swal.fire(vsText('restored', 'Restored!'), vsText('product_restored', 'Product has been restored.'), 'success');
          refreshProductsTab();
          refreshRestoreTab();
        } else {
          Swal.fire(vsText('error', 'Error'), response.data || vsText('failed_to_restore', 'Failed to restore'), 'error');
        }
      },
      error: function () {
        Swal.fire(vsText('error', 'Error'), vsText('failed_to_restore_product', 'Failed to restore product'), 'error');
      }
    });
  });

  function refreshProductsTab() {
    $.ajax({
      url: vs_vars.ajaxurl,
      type: 'POST',
      data: {
        action: 'vs_refresh_products_tab',
        security: vs_vars.nonce
      },
      success: function (response) {
        if (response.success) {
          const isVisible = $('#tab-my-products').is(':visible');
          $('#tab-my-products').replaceWith(response.data);
          if (isVisible) {
            $('#tab-my-products').show();
          }
          // Re-apply pagination if function exists
          if (typeof window.applyUnifiedProductFilters === 'function') {
            window.applyUnifiedProductFilters();
          }
        }
      }
    });
  }

  function refreshRestoreTab() {
    $.ajax({
      url: vs_vars.ajaxurl,
      type: 'POST',
      data: {
        action: 'vs_refresh_restore_tab',
        security: vs_vars.nonce
      },
      success: function (response) {
        if (response.success) {
          const isVisible = $('#tab-restore-products').is(':visible');
          $('#tab-restore-products').replaceWith(response.data);
          if (isVisible) {
            $('#tab-restore-products').show();
          }
          if (typeof window.vsApplyRestorePagination === 'function') {
            window.vsApplyRestorePagination(true);
          }
        }
      }
    });
  }

  // Select all checkbox
  $(document).on('change', '#vs-select-all', function () {
    console.log('Select all checkbox changed');
    const isChecked = $(this).is(':checked');
    $('.vs-select-product').prop('checked', isChecked);
    updateDeleteButtonState();
  });

  // Individual product checkbox
  $(document).on('change', '.vs-select-product', function () {
    const total = $('.vs-select-product').length;
    const checked = $('.vs-select-product:checked').length;
    $('#vs-select-all').prop('checked', total > 0 && total === checked);
    updateDeleteButtonState();
  });

  // Update delete button state
  function updateDeleteButtonState() {
    const selectedCount = $('.vs-select-product:checked').length;
    const $deleteBtn = $('#vs-delete-selected');
    const $bulkEditBtn = $('#vs-bulk-quick-edit');

    if (selectedCount > 0) {
      $deleteBtn.removeAttr('disabled').css('opacity', '1').css('cursor', 'pointer');
      $bulkEditBtn.removeAttr('disabled').css('opacity', '1').css('cursor', 'pointer');
    } else {
      $deleteBtn.attr('disabled', 'disabled').css('opacity', '0.5').css('cursor', 'not-allowed');
      $bulkEditBtn.attr('disabled', 'disabled').css('opacity', '0.5').css('cursor', 'not-allowed');
    }
  }

  // --- Restore Selection Logic ---
  $(document).on('change', '#vs-select-all-restore', function () {
    const isChecked = $(this).is(':checked');
    $('.vs-select-product-restore').prop('checked', isChecked);
    updateRestoreDeleteButtonState();
  });

  $(document).on('change', '.vs-select-product-restore', function () {
    const total = $('.vs-select-product-restore').length;
    const checked = $('.vs-select-product-restore:checked').length;
    $('#vs-select-all-restore').prop('checked', total > 0 && total === checked);
    updateRestoreDeleteButtonState();
  });

  function updateRestoreDeleteButtonState() {
    const selectedCount = $('.vs-select-product-restore:checked').length;
    const $deleteBtn = $('#vs-delete-selected-restore');
    const $restoreBtn = $('#vs-restore-selected');

    if (selectedCount > 0) {
      $deleteBtn.removeAttr('disabled').css({ 'opacity': '1', 'cursor': 'pointer' });
      $restoreBtn.removeAttr('disabled').css({ 'opacity': '1', 'cursor': 'pointer' });
    } else {
      $deleteBtn.attr('disabled', 'disabled').css({ 'opacity': '0.5', 'cursor': 'not-allowed' });
      $restoreBtn.attr('disabled', 'disabled').css({ 'opacity': '0.5', 'cursor': 'not-allowed' });
    }
  }

  // Restore selected products
  $(document).on('click', '#vs-restore-selected', function (e) {
    e.preventDefault();
    const selected = $('.vs-select-product-restore:checked').map(function () {
      return $(this).val();
    }).get();

    if (selected.length === 0) {
      Swal.fire(vsText('info', 'Info'), vsText('select_products_to_restore', 'Please select products to restore'), 'info');
      return;
    }

    Swal.fire({
      title: vsText('restoring_selected', 'Restoring Selected...'),
      text: vsSprintf(vsText('restore_selected_products_count', 'Do you want to restore %s selected products?'), selected.length),
      icon: 'question',
      showCancelButton: true,
      confirmButtonText: vsText('yes_restore_all', 'Yes, Restore All'),
      confirmButtonColor: '#10b981'
    }).then((result) => {
      if (!result.isConfirmed) return;

      Swal.fire({
        title: vsText('restoring', 'Restoring...'),
        text: vsText('please_wait', 'Please wait'),
        allowOutsideClick: false,
        didOpen: () => {
          Swal.showLoading();
        }
      });

      $.ajax({
        type: 'POST',
        url: vs_vars.ajaxurl,
        data: {
          action: 'vs_restore_multiple',
          products: selected,
          security: $('input[name="security"]').val() || vs_vars.nonce
        },
        dataType: 'json',
        success: function (response) {
          if (response.success) {
            Swal.fire(vsText('restored', 'Restored!'), vsSprintf(vsText('products_restored_count', '%s products have been restored.'), selected.length), 'success');
            refreshProductsTab();
            refreshRestoreTab();
          } else {
            Swal.fire(vsText('error', 'Error'), response.data || vsText('failed_to_restore', 'Failed to restore'), 'error');
          }
        },
        error: function () {
          Swal.fire(vsText('error', 'Error'), vsText('failed_to_restore_products', 'Failed to restore products'), 'error');
        }
      });
    });
  });

  // Delete selected products (Main Products Tab)
  $(document).on('click', '#vs-delete-selected', function (e) {
    e.preventDefault();
    handleBulkDelete('.vs-select-product', 'product-row-');
  });

  // Delete selected products (Restore Tab)
  $(document).on('click', '#vs-delete-selected-restore', function (e) {
    e.preventDefault();
    handleBulkDelete('.vs-select-product-restore', 'vs-restore-row-', 'permanent');
  });

  function handleBulkDelete(selector, rowPrefix, forceMode) {
    const selected = $(selector + ':checked').map(function () {
      return $(this).val();
    }).get();

    if (selected.length === 0) {
      Swal.fire(vsText('info', 'Info'), vsText('select_products_to_delete', 'Please select products to delete'), 'info');
      return;
    }

    const startDelete = (mode) => {
      Swal.fire({
        title: mode === 'trash' ? vsText('trashing', 'Trashing...') : vsText('deleting', 'Deleting...'),
        text: vsText('please_wait', 'Please wait'),
        allowOutsideClick: false,
        didOpen: () => {
          Swal.showLoading();
        }
      });

      $.ajax({
        type: 'POST',
        url: vs_vars.ajaxurl,
        data: {
          action: 'vs_delete_multiple',
          products: selected,
          mode: mode,
          security: $('input[name="security"]').val() || vs_vars.nonce
        },
        dataType: 'json',
        success: function (response) {
          if (response.success) {
            let removedDone = 0;
            const done = () => {
              removedDone += 1;
              if (removedDone >= selected.length) {
                checkProductResults();
                refreshProductMetricsFromTable();
                applyUnifiedProductFilters();
                if (rowPrefix === 'vs-restore-row-') refreshRestoreTab();
              }
            };

            selected.forEach(pid => {
              const $row = $('#' + rowPrefix + pid);
              if (!$row.length) {
                done();
                return;
              }
              $row.fadeOut(300, function () {
                $(this).remove();
                done();
              });
            });
            $('#vs-select-all').prop('checked', false);
            $('#vs-select-all-restore').prop('checked', false);
            updateDeleteButtonState();
            updateRestoreDeleteButtonState();

            Swal.fire(
              mode === 'trash' ? vsText('moved_to_trash', 'Moved to Trash!') : vsText('deleted', 'Deleted!'),
              vsSprintf(
                mode === 'trash' ? vsText('products_moved_to_trash_count', '%s products moved to trash.') : vsText('products_deleted_permanently_count', '%s products permanently deleted.'),
                selected.length
              ),
              'success'
            );
          } else {
            Swal.fire(vsText('error', 'Error'), response.data || vsText('failed_to_delete', 'Failed to delete'), 'error');
          }
        },
        error: function (xhr, status, error) {
          console.log('AJAX Error:', error, xhr.responseText);
          Swal.fire(vsText('error', 'Error'), vsText('failed_to_delete_products', 'Failed to delete products'), 'error');
        }
      });
    };

    if (forceMode === 'permanent') {
      Swal.fire({
        title: vsText('delete_permanently', 'Delete Permanently?'),
        text: vsSprintf(vsText('delete_selected_products_permanently_count', 'Do you want to permanently delete %s selected products?'), selected.length),
        icon: 'warning',
        showCancelButton: true,
        confirmButtonColor: '#d33',
        confirmButtonText: vsText('yes_delete_permanently', 'Yes, Delete Permanently')
      }).then((result) => {
        if (result.isConfirmed) startDelete('permanent');
      });
    } else {
      Swal.fire({
        title: vsText('delete_selected_products', 'Delete Selected Products?'),
        text: vsSprintf(vsText('move_selected_products_to_trash_or_delete', 'Do you want to move %s products to the trash or delete them permanently?'), selected.length),
        icon: 'warning',
        showCancelButton: true,
        showDenyButton: true,
        confirmButtonText: '<i class="fas fa-trash"></i> ' + vsText('move_to_trash', 'Move to Trash'),
        denyButtonText: '<i class="fas fa-times"></i> ' + vsText('delete_permanently_action', 'Delete Permanently'),
        confirmButtonColor: '#ff9800',
        denyButtonColor: '#d33',
        cancelButtonColor: '#3085d6',
      }).then((result) => {
        if (result.isConfirmed) startDelete('trash');
        else if (result.isDenied) startDelete('permanent');
      });
    }
  }


  // Export Products to CSV (Robust version)
  $(document).on('click', '#vs-export-csv', function (e) {
    e.preventDefault();
    const $targetTab = $('#tab-my-products');
    if (!$targetTab.is(':visible')) {
      // Optional: could return or try to find the table anyway if it exists
    }

    const $table = $targetTab.find('.vs-products-table').first();
    if (!$table.length) {
      Swal.fire(vsText('info', 'Info'), vsText('no_products_table_found', 'No products table found'), 'info');
      return;
    }

    const headers = ['ID', 'Name', 'Description', 'Price', 'Stock', 'Status'];
    const rows = [headers.join(',')];

    // Find rows that are NOT explicitly hidden by FILTERS. 
    // Pagination also hides rows, but we want to export ALL that match the filters.
    // In our logic, filters call .toggle(match). 
    // We can find matching rows by checking if they don't have style="display: none" 
    // BUT pagination complicates this. 
    // BETTER: Check the rows that are NOT the 'no-results' placeholder.
    // If you want ONLY filtered results, you need to rely on visibility before pagination kicks in, 
    // or re-run a simple check.

    // For now, let's export all rows that aren't 'no-results', 
    // but check if they've been filtered out.
    // In our filter logic, we use .hide()/.show().

    $table.find('tbody tr').not('.no-results').each(function () {
      const $row = $(this);

      // If the row is hidden by filter (not pagination), skip. 
      // Because pagination also hides, we have to be careful.
      // However, usually users want EVERYTHING when they click export unless they've searched.

      const id = $row.attr('id') ? $row.attr('id').replace('product-row-', '') : '';
      const name = $row.find('.product-name').text().trim();
      const desc = $row.find('.product-desc').text().trim();
      const priceText = $row.find('.product-price').text().trim().replace(/[$,]/g, '');
      const stock = $row.find('.product-stock').text().trim();
      const status = $row.find('.product-status').text().trim();

      // Skip if explicitly filtered out (if we can detect it)
      // Since we don't have a class for filtered-out, and :visible is affected by pagination,
      // we'll just export all for now, which is safer than exporting none.
      // If we want to support filtered export, we should add a class during applyUnifiedProductFilters.

      const escape = (val) => {
        let s = String(val || '').replace(/"/g, '""');
        // Replace newlines with spaces to keep CSV valid for simple parsers
        s = s.replace(/[\r\n]+/g, ' ');
        return `"${s}"`;
      };

      const csvRow = [
        escape(id),
        escape(name),
        escape(desc),
        escape(priceText),
        escape(stock),
        escape(status)
      ];
      rows.push(csvRow.join(','));
    });

    if (rows.length <= 1) {
      Swal.fire(vsText('info', 'Info'), vsText('no_products_found_to_export', 'No products found to export'), 'info');
      return;
    }

    // Build XLSX for clean Excel display
    const xlsxData = rows.map(function(line) {
      // Parse the CSV line back into an array of values
      var result = [], cur = '', inQ = false;
      for (var i = 0; i < line.length; i++) {
        var ch = line[i];
        if (ch === '"') { inQ = !inQ; } else if (ch === ',' && !inQ) { result.push(cur); cur = ''; } else { cur += ch; }
      }
      result.push(cur);
      return result;
    });
    var ws = XLSX.utils.aoa_to_sheet(xlsxData);
    // Auto column widths
    var colWidths = xlsxData[0].map(function(_, ci) {
      return { wch: Math.max.apply(null, xlsxData.map(function(row) { return row[ci] ? String(row[ci]).length : 10; })) + 2 };
    });
    ws['!cols'] = colWidths;
    var wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, 'Products');
    XLSX.writeFile(wb, 'my-products.xlsx');
  });

  // Initialize delete button state on load
  updateDeleteButtonState();

  // ==============================
  // Vendor Orders: search/filter/pagination/export
  // ==============================
  // Remove image in edit form (featured/gallery)
  $(document).on('click', '.vs-remove-img', function (e) {
    e.preventDefault();
    const $item = $(this).closest('.vs-edit-img');
    const id = $item.data('id');
    const type = $item.data('type');

    if (type === 'featured') {
      $('#vs-remove-featured').val('1');
    } else {
      const current = $('#vs-remove-gallery-ids').val().trim();
      const ids = current ? current.split(',').map(s => s.trim()).filter(Boolean) : [];
      if (id && !ids.includes(String(id))) ids.push(String(id));
      $('#vs-remove-gallery-ids').val(ids.join(','));
    }

    $item.remove();
    $('#vs-save-edit').prop('disabled', false).removeClass('vs-btn-disabled');
  });
  const $tbody = $('#vs-orders-tbody');
  if (!$tbody.length) {
    console.log('No orders section found');
  } else {
    console.log('Orders section found, initializing...');

    const $rows = () => $tbody.find('tr');
    const $search = $('#vs-orders-search');
    const $status = $('#vs-orders-filter-status');
    const $from = $('#vs-orders-date-from');
    const $to = $('#vs-orders-date-to');
    const $export = $('#vs-orders-export');
    const $reset = $('#vs-orders-reset');
    const $pager = $('#vs-orders-pagination');
    const $summary = $('#vs-orders-summary');

    const PAGE_SIZE = 10;
    let currentPage = 1;

    const norm = (s) => String(s || '').toLowerCase().trim();
    const parseYmd = (ymd) => {
      if (!ymd) return null;
      const d = new Date(ymd + 'T00:00:00');
      return isNaN(d.getTime()) ? null : d;
    };

    const getFiltered = () => {
      const q = norm($search.val());
      const st = norm($status.val());
      const dFrom = parseYmd($from.val());
      const dTo = parseYmd($to.val());

      return $rows().toArray().filter((tr) => {
        const $tr = $(tr);
        const orderNo = norm($tr.data('order-number'));
        const name = norm($tr.data('customer-name'));
        const email = norm($tr.data('customer-email'));
        const rowStatus = norm($tr.data('status'));
        const rowDate = parseYmd($tr.data('date'));

        if (q) {
          const ok = orderNo.includes(q) || name.includes(q) || email.includes(q);
          if (!ok) return false;
        }
        if (st && rowStatus !== st) return false;
        if (dFrom && (!rowDate || rowDate < dFrom)) return false;
        if (dTo && (!rowDate || rowDate > dTo)) return false;
        return true;
      });
    };

    const money = (value, currency) => {
      const n = Number(value || 0);
      try {
        return new Intl.NumberFormat(undefined, { style: 'currency', currency: currency || 'USD' }).format(n);
      } catch (_) {
        return '$' + (Math.round(n * 100) / 100).toFixed(2);
      }
    };

    const renderSummary = (filtered) => {
      let total = 0;
      let processing = 0;
      let completed = 0;

      filtered.forEach((tr) => {
        const $tr = $(tr);
        total += Number($tr.data('vendor-total') || 0);
        const st = norm($tr.data('status'));
        if (st === 'processing') processing += 1;
        if (st === 'completed') completed += 1;
      });

      const count = filtered.length;
      $summary.html(`
        <div class="vs-orders-cards">
          <div class="vs-card">
            <div class="vs-card-title">${vsEscapeHtml(vsText('orders', 'Orders'))}</div>
            <div class="vs-card-value">${count}</div>
          </div>
          <div class="vs-card">
            <div class="vs-card-title">${vsEscapeHtml(vsText('processing', 'Processing'))}</div>
            <div class="vs-card-value">${processing}</div>
          </div>
          <div class="vs-card">
            <div class="vs-card-title">${vsEscapeHtml(vsText('completed', 'Completed'))}</div>
            <div class="vs-card-value">${completed}</div>
          </div>
        </div>
      `);
    };

    const renderPager = (totalItems) => {
      const totalPages = Math.max(1, Math.ceil(totalItems / PAGE_SIZE));
      currentPage = Math.min(currentPage, totalPages);

      const btn = (label, page, disabled, active) => {
        const cls = ['vs-page-btn', disabled ? 'is-disabled' : '', active ? 'is-active' : ''].join(' ').trim();
        return `<button type="button" class="${cls}" data-page="${page}" ${disabled ? 'disabled' : ''}>${label}</button>`;
      };

      let html = '';
      html += btn(vsText('prev', 'Prev'), Math.max(1, currentPage - 1), currentPage === 1, false);

      const start = Math.max(1, currentPage - 2);
      const end = Math.min(totalPages, start + 4);
      for (let p = start; p <= end; p++) {
        html += btn(String(p), p, false, p === currentPage);
      }

      html += btn(vsText('next', 'Next'), Math.min(totalPages, currentPage + 1), currentPage === totalPages, false);
      $pager.html(html);
    };

    const apply = () => {
      const filtered = getFiltered();

      $rows().hide();

      const startIdx = (currentPage - 1) * PAGE_SIZE;
      const pageRows = filtered.slice(startIdx, startIdx + PAGE_SIZE);
      pageRows.forEach((tr) => $(tr).show());

      renderPager(filtered.length);
      renderSummary(filtered);
    };

    const exportCsv = () => {
      const filtered = getFiltered();
      const headers = [vsText('order_number', 'Order #'), vsText('customer', 'Customer'), vsText('email', 'Email'), vsText('date', 'Date'), vsText('status', 'Status'), vsText('vendor_total', 'Vendor Total')];
      const lines = [headers.join(',')];

      filtered.forEach((tr) => {
        const $tr = $(tr);
        const row = [
          $tr.data('order-number'),
          $tr.data('customer-name'),
          $tr.data('customer-email'),
          $tr.data('date'),
          $tr.data('status'),
          $tr.data('vendor-total'),
        ].map((v) => `"${String(v || '').replace(/"/g, '""')}"`);
        lines.push(row.join(','));
      });

      // Build XLSX for clean Excel display
      var xlsxData = lines.map(function(line) {
        var result = [], cur = '', inQ = false;
        for (var i = 0; i < line.length; i++) {
          var ch = line[i];
          if (ch === '"') { inQ = !inQ; } else if (ch === ',' && !inQ) { result.push(cur); cur = ''; } else { cur += ch; }
        }
        result.push(cur);
        return result;
      });
      var ws = XLSX.utils.aoa_to_sheet(xlsxData);
      var colWidths = xlsxData[0].map(function(_, ci) {
        return { wch: Math.max.apply(null, xlsxData.map(function(row) { return row[ci] ? String(row[ci]).length : 10; })) + 2 };
      });
      ws['!cols'] = colWidths;
      var wb = XLSX.utils.book_new();
      XLSX.utils.book_append_sheet(wb, ws, 'Orders');
      XLSX.writeFile(wb, 'orders-vendor.xlsx');
    };

    // ---- AJAX loader for orders ----
    function vsLoadOrdersAjax(page, reset) {
      if (!window.vs_vars || !vs_vars.ajaxurl) { apply(); return; }
      if (reset) page = 1;
      currentPage = page;
      $tbody.html('<tr><td colspan="7" style="text-align:center;padding:30px;color:#94a3b8;">' + (vsText ? vsText('loading','Loading...') : 'Loading...') + '</td></tr>');
      $.post(vs_vars.ajaxurl, {
        action: 'vs_page_orders', security: vs_vars.nonce,
        paged: page,
        search: $search.val() || '',
        status_filter: $status.val() || '',
        date_from: $from.val() || '',
        date_to: $to.val() || '',
      }, function(response) {
        if (!response.success) return;
        const d = response.data;
        currentPage = d.paged;
        $tbody.html(d.rows);
        vsRenderPager($pager, d.paged, d.total_pages, function(p) { vsLoadOrdersAjax(p, false); });
        renderSummary($tbody.find('tr').toArray());
      }).fail(function() {
        $tbody.html('<tr><td colspan="7" style="text-align:center;padding:30px;color:#e74c3c;">Error loading orders.</td></tr>');
      });
    }

    $search.on('input', function () { vsLoadOrdersAjax(1, true); });
    $status.on('change', function () { vsLoadOrdersAjax(1, true); });
    $from.on('change', function () {
      const val = $(this).val();
      if (val) $to.attr('min', val);
      else $to.removeAttr('min');
      vsLoadOrdersAjax(1, true);
    });
    $to.on('change', function () {
      const val = $(this).val();
      if (val) $from.attr('max', val);
      else $from.removeAttr('max');
      vsLoadOrdersAjax(1, true);
    });

    if ($export.length) {
      $export.on('click', exportCsv);
    }

    if ($reset.length) {
      $reset.on('click', function () {
        $search.val('');
        $status.val('');
        $from.val('');
        $to.val('');
        vsLoadOrdersAjax(1, true);
      });
    }

    // Initial load via AJAX (replaces apply())
    vsLoadOrdersAjax(1, true);

    // Expose for tab switch
    window.vsLoadOrdersPage = function(reset) { vsLoadOrdersAjax(currentPage, !!reset); };
  }


  // ==============================
  // Generic pager for other tables (Prev/Next + page buttons)
  // Attach to any pager element with an id ending in "-pagination" that
  // doesn't already have a dedicated JS handler above.
  // ==============================
  (function () {
    const genericState = {};
    const DEFAULT_PAGE_SIZE = 10;

    function renderGenericPager($pager, currentPage, totalItems, pageSize) {
      const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
      const btn = (label, page, disabled, active) => {
        const cls = ['vs-page-btn', disabled ? 'is-disabled' : '', active ? 'is-active' : ''].join(' ').trim();
        return `<button type="button" class="${cls}" data-page="${page}" ${disabled ? 'disabled' : ''}>${label}</button>`;
      };

      let html = '';
      html += btn(vsText('prev', 'Prev'), Math.max(1, currentPage - 1), currentPage === 1, false);
      const start = Math.max(1, currentPage - 2);
      const end = Math.min(totalPages, start + 4);
      for (let p = start; p <= end; p++) html += btn(String(p), p, false, p === currentPage);
      html += btn(vsText('next', 'Next'), Math.min(totalPages, currentPage + 1), currentPage === totalPages, false);
      $pager.html(html);
    }

    function applyGenericPager($pager, resetToFirstPage, pageSize) {
      pageSize = Number(pageSize) || DEFAULT_PAGE_SIZE;
      const id = $pager.attr('id') || $pager.data('vs-generic-id') || null;
      if (!id) {
        // give it an id so we can store state
        const genId = 'vs-generic-pager-' + Math.random().toString(36).slice(2, 9);
        $pager.attr('id', genId);
      }
      const pid = $pager.attr('id');

      if (resetToFirstPage) genericState[pid] = 1;
      if (!genericState[pid]) genericState[pid] = 1;

      // Find related table: prefer same tab, else nearest previous table
      const $tab = $pager.closest('.vs-tab');
      let $table = $tab.find('table').first();
      if (!$table.length) $table = $pager.prevAll('table').first();
      if (!$table.length) return;
      if ($tab.length && !$tab.is(':visible')) return; // only paginate visible tabs

      const $allRows = $table.find('tbody tr').not('.no-results');
      const filtered = $allRows.filter(':visible').toArray();

      const total = filtered.length;
      const current = Math.max(1, Math.min(genericState[pid], Math.max(1, Math.ceil(total / pageSize))));
      genericState[pid] = current;

      $allRows.hide();
      const startIdx = (current - 1) * pageSize;
      const pageRows = filtered.slice(startIdx, startIdx + pageSize);
      pageRows.forEach(tr => jQuery(tr).show());

      renderGenericPager($pager, current, total, pageSize);
    }

    window.vsRefreshGenericPagers = function (resetToFirstPage) {
      jQuery('[data-vs-generic]').each(function () {
        const $p = jQuery(this);
        applyGenericPager($p, !!resetToFirstPage, $p.data('page-size') || DEFAULT_PAGE_SIZE);
      });
    };

    // Mark pagers that don't have a dedicated handler as generic and apply
    jQuery(function ($) {
      $('[id$="-pagination"]').each(function () {
        const $p = $(this);
        const id = $p.attr('id');
        if (!id) return;
        // Only apply generic pager to pagers that don't already have page buttons
        // This prevents overwriting pagers that have dedicated logic (products/orders/restore)
        if ($p.find('.vs-page-btn').length) return;
        $p.attr('data-vs-generic', '1');
        applyGenericPager($p, true, $p.data('page-size') || DEFAULT_PAGE_SIZE);
      });

      // Click handler for generic pagers
      $(document).on('click', '[data-vs-generic] .vs-page-btn', function (e) {
        e.preventDefault();
        const $btn = $(this);
        const $pager = $btn.closest('[data-vs-generic]');
        const page = Number($btn.data('page') || 1);
        const pid = $pager.attr('id');
        if (!pid) return;
        // Save state and re-apply
        const pageSize = Number($pager.data('page-size')) || DEFAULT_PAGE_SIZE;
        // store state
        // genericState is closed over
        genericState[pid] = page;
        applyGenericPager($pager, false, pageSize);
      });
    });
  })();



  // ==============================
  // Delete Order
  // ==============================
  $(document).on('click', '.vs-delete-order', function () {
    const orderId = $(this).data('order-id');
    const $btn = $(this);
    const $row = $btn.closest('tr');

    Swal.fire({
      title: 'Are you sure?',
      text: "You won't be able to revert this!",
      icon: 'warning',
      showCancelButton: true,
      confirmButtonColor: '#d33',
      cancelButtonColor: '#3085d6',
      confirmButtonText: 'Yes, delete it!'
    }).then((result) => {
      if (result.isConfirmed) {
        $.ajax({
          type: 'POST',
          url: vs_vars.ajaxurl,
          data: {
            action: 'vs_delete_order',
            order_id: orderId,
            security: vs_vars.orders_nonce || vs_vars.nonce
          },
          success: function (response) {
            if (response.success) {
              $row.fadeOut(300, function () { $(this).remove(); });
              Swal.fire(vsText('deleted', 'Deleted!'), vsText('order_deleted', 'Order has been deleted.'), 'success');
            } else {
              Swal.fire(vsText('error', 'Error'), response.data || vsText('failed_to_delete_order', 'Failed to delete order'), 'error');
            }
          },
          error: function () {
            Swal.fire(vsText('error', 'Error'), vsText('connection_failed', 'Connection failed'), 'error');
          }
        });
      }
    });
  });

  // ==============================
  // Update Order Status
  // ==============================
  $(document).on('change', '.vs-order-status-select', function () {
    const $select = $(this);
    const orderId = $select.data('order-id');
    const newStatus = $select.val();
    const $row = $select.closest('tr');

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

    $.ajax({
      type: 'POST',
      url: vs_vars.ajaxurl,
      data: {
        action: 'vs_update_order_status',
        order_id: orderId,
        status: newStatus,
        security: vs_vars.orders_nonce || vs_vars.nonce
      },
      success: function (response) {
        $select.prop('disabled', false);
        if (response.success) {
          showToast(vsSprintf(vsText('status_updated_to', 'Status updated to %s'), newStatus));

          // Update colors based on status
          let bg = '#f3f4f6';
          let color = '#374151';
          if (newStatus === 'completed') {
            bg = '#d1fae5';
            color = '#065f46';
          } else if (newStatus === 'processing') {
            bg = '#dbeafe';
            color = '#1e40af';
          } else if (newStatus === 'cancelled') {
            bg = '#fee2e2';
            color = '#991b1b';
          }

          $select.css({
            'background': bg,
            'color': color
          });

          // Update data attribute for filtering
          $row.data('status', newStatus);
          $row.attr('data-status', newStatus);
        } else {
          // If the backend returns success:false but the action worked? Unlikely.
          // But user says "il changer mais il ya une message qui saffiche erreur"
          // This implies the AJAX 'error' callback ran, OR 'response.success' was false.
          // If response.success was false, we show error. 
          // If AJAX error (parsererror), we show 'Connection failed'. This is likely the cause if unwanted output exists.

          Swal.fire(vsText('error', 'Error'), response.data || vsText('failed_to_update_status', 'Failed to update status'), 'error');
        }
      },
      error: function () {
        $select.prop('disabled', false);
        Swal.fire(vsText('error', 'Error'), vsText('connection_failed', 'Connection failed'), 'error');
      }
    });
  });

  // Chat system moved to assets/vs-chat.js

  // ==============================
  // Vendor Profile
  // ==============================
  function vsProfilePost(action, data, onSuccess, onError) {
    let payload;
    if (Array.isArray(data)) {
      payload = data.slice();
      const hasAction = payload.some(item => item && item.name === 'action');
      const hasSecurity = payload.some(item => item && item.name === 'security');
      if (!hasAction) payload.push({ name: 'action', value: action });
      if (!hasSecurity) payload.push({ name: 'security', value: vs_vars.nonce });
    } else {
      payload = $.extend({}, data || {});
      if (!payload.action) payload.action = action;
      if (!payload.security) payload.security = vs_vars.nonce || $('#vs-categories-security').val() || (typeof vs_nonce !== 'undefined' ? vs_nonce : '');
    }

    $.ajax({
      type: 'POST',
      url: vs_vars.ajaxurl,
      data: payload,
      dataType: 'json',
      success: function (response) {
        if (response && response.success) {
          if (typeof onSuccess === 'function') onSuccess(response);
        } else {
          if (typeof onError === 'function') {
            onError(response || { success: false, data: vsText('request_failed', 'Request failed') });
          } else {
            Swal.fire(vsText('error', 'Error'), (response && response.data) ? response.data : vsText('request_failed', 'Request failed'), 'error');
          }
        }
      },
      error: function (xhr, textStatus) {
        let message = 'Connection failed';
        const raw = (xhr && typeof xhr.responseText === 'string') ? xhr.responseText.trim() : '';

        if (raw === '-1') {
          message = 'Session expired. Please refresh the page and try again.';
        } else if (raw) {
          try {
            const parsed = JSON.parse(raw);
            if (parsed && parsed.data) {
              message = (typeof parsed.data === 'string') ? parsed.data : vsText('request_failed', 'Request failed');
            }
          } catch (_e) {
            if (xhr && xhr.status >= 500) {
              message = vsText('server_error_try_again', 'Server error. Please try again.');
            }
          }
        }

        console.error('VS Profile AJAX Error:', textStatus, xhr ? xhr.status : '', raw);
        if (typeof onError === 'function') {
          onError({ success: false, data: message });
        } else {
          Swal.fire('Error', message, 'error');
        }
      }
    });
  }

  function setButtonBusy($button, busyText) {
    if (!$button || !$button.length) {
      return function restoreNoop() {};
    }

    if (!$button.data('vs-original-html')) {
      $button.data('vs-original-html', $button.html());
    }

    $button.prop('disabled', true).addClass('vs-btn-disabled').text(busyText);

    return function restoreButton() {
      const originalHtml = $button.data('vs-original-html');
      $button.prop('disabled', false).removeClass('vs-btn-disabled');
      if (originalHtml) {
        $button.html(originalHtml);
      }
    };
  }

  function openTab(tabName) {
    const $link = $(`.vs-tab-link[data-tab="${tabName}"]`);
    if ($link.length) {
      $link.trigger('click');
    }
  }

  $(document).on('click', '#vs-open-account-settings', function () {
    openTab('profile');
    const panel = document.getElementById('vs-account-panel');
    if (panel) panel.open = true;
    setTimeout(() => {
      const target = document.getElementById('vs-account-panel');
      if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }, 120);
  });

  $(document).on('click', '[data-vs-open-tab]', function (e) {
    e.preventDefault();
    openTab($(this).data('vs-open-tab'));
  });

  $(document).on('click', '#vs-go-add-product', function () {
    openTab('my-products');
    setTimeout(function () {
      $('#add-product-btn-show').trigger('click');
    }, 120);
  });

  function normalizeEmail(value) {
    return String(value || '').trim().toLowerCase();
  }

  function isValidEmailFormat(value) {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(value || '').trim());
  }

  let accountEmailCheckXhr = null;
  let accountEmailCheckTimer = null;
  const accountEmailValidation = {
    lastChecked: '',
    available: true,
    checking: false,
    message: ''
  };

  function setAccountEmailStatus(message, type = '') {
    const $status = $('#vs-account-email-status');
    const $input = $('#vs-account-email');

    if (!$status.length || !$input.length) {
      return;
    }

    $status.text(message || '').removeClass('is-error is-info is-success');
    $input.toggleClass('is-invalid', type === 'error');

    if (!message) {
      $status.hide();
      return;
    }

    if (type) {
      $status.addClass(`is-${type}`);
    }
    $status.show();
  }

  function clearAccountEmailValidation() {
    accountEmailValidation.lastChecked = '';
    accountEmailValidation.available = true;
    accountEmailValidation.checking = false;
    accountEmailValidation.message = '';
    setAccountEmailStatus('');
  }

  function checkAccountEmailAvailability(options = {}) {
    const settings = $.extend({
      force: false,
      showStatus: true
    }, options || {});

    const currentEmail = normalizeEmail($('#vs-account-current-email').val());
    const enteredEmail = normalizeEmail($('#vs-account-email').val());
    const deferred = $.Deferred();

    if (enteredEmail === '' || enteredEmail === currentEmail) {
      clearAccountEmailValidation();
      accountEmailValidation.lastChecked = enteredEmail;
      deferred.resolve({ available: true, skipped: true });
      return deferred.promise();
    }

    if (!isValidEmailFormat(enteredEmail)) {
      const message = vsText('valid_email_required', 'Please provide a valid email address.');
      accountEmailValidation.lastChecked = enteredEmail;
      accountEmailValidation.available = false;
      accountEmailValidation.checking = false;
      accountEmailValidation.message = message;
      if (settings.showStatus) {
        setAccountEmailStatus(message, 'error');
      }
      deferred.resolve({ available: false, message: message });
      return deferred.promise();
    }

    if (!settings.force && accountEmailValidation.lastChecked === enteredEmail && !accountEmailValidation.checking) {
      if (settings.showStatus) {
        setAccountEmailStatus(
          accountEmailValidation.available ? '' : accountEmailValidation.message,
          accountEmailValidation.available ? '' : 'error'
        );
      }
      deferred.resolve({
        available: accountEmailValidation.available,
        message: accountEmailValidation.message,
        cached: true
      });
      return deferred.promise();
    }

    if (accountEmailCheckXhr) {
      accountEmailCheckXhr.abort();
      accountEmailCheckXhr = null;
    }

    accountEmailValidation.lastChecked = enteredEmail;
    accountEmailValidation.available = false;
    accountEmailValidation.checking = true;
    accountEmailValidation.message = '';

    if (settings.showStatus) {
      setAccountEmailStatus(vsText('checking_email', 'Checking email...'), 'info');
    }

    accountEmailCheckXhr = $.ajax({
      type: 'POST',
      url: vs_vars.ajaxurl,
      data: {
        action: 'vs_profile_check_email',
        security: vs_vars.nonce,
        email: enteredEmail
      },
      dataType: 'json'
    })
      .done(function (response) {
        accountEmailValidation.checking = false;

        if (response && response.success) {
          accountEmailValidation.available = true;
          accountEmailValidation.message = '';
          if (settings.showStatus) {
            setAccountEmailStatus('');
          }
          deferred.resolve({ available: true });
          return;
        }

        const message = (response && typeof response.data === 'string' && response.data)
          ? response.data
          : vsText('email_already_registered', 'This email address is already registered.');

        accountEmailValidation.available = false;
        accountEmailValidation.message = message;
        if (settings.showStatus) {
          setAccountEmailStatus(message, 'error');
        }
        deferred.resolve({ available: false, message: message });
      })
      .fail(function (xhr, status) {
        accountEmailValidation.checking = false;

        if (status === 'abort') {
          deferred.reject({ aborted: true });
          return;
        }

        accountEmailValidation.available = true;
        accountEmailValidation.message = '';
        if (settings.showStatus) {
          setAccountEmailStatus('');
        }
        deferred.resolve({ available: true, skipped: true });
      })
      .always(function () {
        accountEmailCheckXhr = null;
      });

    return deferred.promise();
  }

  function buildAccountPayload(extra = {}) {
    return $.extend({
      action: 'vs_profile_save_account',
      security: vs_vars.nonce,
      username: $('#vs-account-username').val(),
      display_name: $('#vs-account-display-name').val(),
      email: $('#vs-account-email').val(),
      first_name: $('#vs-account-first-name').val(),
      last_name: $('#vs-account-last-name').val(),
      address: $('#vs-account-address').val(),
      country: $('#vs-account-country').val(),
      city: $('#vs-account-city').val(),
      new_password: $('#vs-account-password').val(),
      confirm_password: $('#vs-account-password-confirm').val()
    }, extra || {});
  }

  function syncAccountSummary(data) {
    const account = (data && data.account) ? data.account : {};
    const displayName = String(account.display_name || $('#vs-account-display-name').val() || '').trim();
    const username = String(account.username || $('#vs-account-username').val() || '').trim();
    const email = String(account.email || $('#vs-account-email').val() || '').trim();

    if (email !== '') {
      $('#vs-account-current-email').val(email);
      $('.vs-user-email').text(email);
    }

    $('.vs-user-name').text(displayName || username);
    clearAccountEmailValidation();
  }

  function resetAccountSecurityUi() {
    $('#vs-account-password').val('');
    $('#vs-account-password-confirm').val('');
    $('#vs-profile-otp-message').text('').removeClass('is-error is-success');
    $('#vs-profile-otp-overlay .vs-otp-digit').val('');
    checkProfileOtpComplete();
  }

  $(document).on('input', '#vs-account-email', function () {
    if (accountEmailCheckTimer) {
      clearTimeout(accountEmailCheckTimer);
    }

    const currentEmail = normalizeEmail($('#vs-account-current-email').val());
    const enteredEmail = normalizeEmail($(this).val());

    if (enteredEmail === currentEmail) {
      clearAccountEmailValidation();
      $('#vs-profile-otp-message').text('').removeClass('is-error is-success');
      return;
    }

    accountEmailValidation.lastChecked = '';
    accountEmailValidation.available = true;
    accountEmailValidation.checking = false;
    accountEmailValidation.message = '';
    setAccountEmailStatus('');

    if (enteredEmail !== '' && isValidEmailFormat(enteredEmail)) {
      accountEmailCheckTimer = setTimeout(function () {
        checkAccountEmailAvailability({ showStatus: true });
      }, 350);
    }
  });

  $(document).on('blur', '#vs-account-email', function () {
    if (accountEmailCheckTimer) {
      clearTimeout(accountEmailCheckTimer);
      accountEmailCheckTimer = null;
    }

    checkAccountEmailAvailability({
      force: true,
      showStatus: true
    });
  });

  $(document).on('submit', '#vs-account-form', function (e) {
    if ($(this).data('otp-verified')) {
      return; 
    }
    
    e.preventDefault();
    if (accountEmailCheckTimer) {
      clearTimeout(accountEmailCheckTimer);
      accountEmailCheckTimer = null;
    }
    const restoreButton = setButtonBusy($(this).find('button[type="submit"]').first(), vsText('saving', 'Saving...'));

    checkAccountEmailAvailability({
      force: true,
      showStatus: true
    }).done(function (validation) {
      if (validation && validation.available === false) {
        restoreButton();
        Swal.fire(vsText('error', 'Error'), validation.message || vsText('email_already_registered', 'This email address is already registered.'), 'error');
        return;
      }

      vsProfilePost('vs_profile_save_account', buildAccountPayload(), function (response) {
        const data = (response && response.data) ? response.data : {};
        
        if (data.otp_required) {
          restoreButton();
          openProfileOtpModal();
          return;
        }

        syncAccountSummary(data);
        resetAccountSecurityUi();
        restoreButton();
        showToast(data.message || vsText('account_updated_successfully', 'Account updated successfully'));
      }, function (response) {
        restoreButton();
        const message = (response && typeof response.data === 'string' && response.data) ? response.data : vsText('request_failed', 'Request failed');
        Swal.fire(vsText('error', 'Error'), message, 'error');
      });
    }).fail(function () {
      restoreButton();
    });
  });

  function openProfileOtpModal() {
    const $overlay = $('#vs-profile-otp-overlay');
    const $inputs = $('.vs-otp-digit', $overlay);
    const $message = $('#vs-profile-otp-message');
    
    $message.text('').removeClass('is-error is-success');
    $inputs.val('');
    $overlay.fadeIn(200);
    checkProfileOtpComplete();
    $inputs.first().trigger('focus');
  }

  function closeProfileOtpModal() {
    $('#vs-profile-otp-overlay').fadeOut(200);
  }

  $(document).on('click', '#vs-profile-otp-close, #vs-profile-otp-cancel', function(e) {
    e.preventDefault();
    closeProfileOtpModal();
  });

  $(document).on('input', '#vs-profile-otp-overlay .vs-otp-digit', function(e) {
    const $this = $(this);
    let val = $this.val().replace(/\D/g, '');
    $this.val(val ? val.charAt(val.length - 1) : '');
    
    if ($this.val() && $this.next('.vs-otp-digit').length) {
      $this.next('.vs-otp-digit').focus();
    }
    
    checkProfileOtpComplete();
  });

  $(document).on('keydown', '#vs-profile-otp-overlay .vs-otp-digit', function(e) {
    if (e.key === 'Backspace' && !$(this).val() && $(this).prev('.vs-otp-digit').length) {
      $(this).prev('.vs-otp-digit').focus();
    }
  });

  function checkProfileOtpComplete() {
    const otp = getProfileOtpValue();
    $('#vs-profile-otp-verify').prop('disabled', otp.length !== 4);
  }

  function getProfileOtpValue() {
    let otp = '';
    $('#vs-profile-otp-overlay .vs-otp-digit').each(function() {
      otp += $(this).val();
    });
    return otp;
  }

  $(document).on('click', '#vs-profile-otp-verify', function(e) {
    e.preventDefault();
    const otp = getProfileOtpValue();
    if (otp.length !== 4) return;

    const $btn = $(this);
    const $message = $('#vs-profile-otp-message');
    
    $btn.prop('disabled', true).find('span').text('Verifying...');
    $message.text('').removeClass('is-error');

    vsProfilePost('vs_profile_save_account', buildAccountPayload({ otp: otp }), function(response) {
      $btn.prop('disabled', false).find('span').text('Verify & Save');
      const data = (response && response.data) ? response.data : {};
      $message.text(data.message || vsText('account_updated_successfully', 'Account updated successfully')).removeClass('is-error').addClass('is-success');
      setTimeout(function() {
        closeProfileOtpModal();
        syncAccountSummary(data);
        resetAccountSecurityUi();
        showToast(data.message || vsText('account_updated_successfully', 'Account updated successfully'));
      }, 1000);
    }, function(response) {
      const message = (response && typeof response.data === 'string' && response.data) ? response.data : vsText('invalid_code', 'Invalid code');
      $btn.prop('disabled', false).find('span').text('Verify & Save');
      $message.text(message).removeClass('is-success').addClass('is-error');
    });
  });

  // Re-enable original send reset and verification buttons
  $(document).on('click', '#vs-send-reset-email', function () {
    vsProfilePost('vs_profile_send_reset', {
      action: 'vs_profile_send_reset',
      security: vs_vars.nonce
    }, function (response) {
      showToast((response.data && response.data.message) ? response.data.message : vsText('reset_email_sent', 'Reset email sent'));
    });
  });

  $(document).on('click', '#vs-send-verification-email', function () {
    vsProfilePost('vs_profile_send_email_verification', {
      action: 'vs_profile_send_email_verification',
      security: vs_vars.nonce
    }, function (response) {
      showToast((response.data && response.data.message) ? response.data.message : vsText('verification_email_sent', 'Verification email sent'));
    });
  });

  function submitStoreSettings() {
    const form = document.getElementById('vs-store-form');
    if (!form) return;

    const restoreButton = setButtonBusy($(form).find('button[type="submit"]').first(), vsText('updating', 'Updating...'));
    const fd = new FormData(form);
    fd.append('action', 'vs_profile_save_store');
    fd.append('security', vs_vars.nonce);

    $.ajax({
      type: 'POST',
      url: vs_vars.ajaxurl,
      data: fd,
      processData: false,
      contentType: false,
      dataType: 'json',
      success: function (response) {
        restoreButton();
        if (response && response.success) {
          showToast((response.data && response.data.message) ? response.data.message : vsText('store_settings_updated', 'Store settings updated'));
        } else {
          Swal.fire(vsText('error', 'Error'), (response && response.data) ? response.data : vsText('failed_to_save_store_settings', 'Failed to save store settings'), 'error');
        }
      },
      error: function () {
        restoreButton();
        Swal.fire(vsText('error', 'Error'), vsText('connection_failed', 'Connection failed'), 'error');
      }
    });
  }

  $(document).on('submit', '#vs-store-form', function (e) {
    e.preventDefault();
    submitStoreSettings();
  });

  $(document).on('click', '#vs-save-extra-settings', function () {
    const restoreButton = setButtonBusy($(this), vsText('saving', 'Saving...'));
    vsProfilePost('vs_profile_save_extra', {
      action: 'vs_profile_save_extra',
      security: vs_vars.nonce,
      custom_css: $('#vs-store-custom-css').val() || '',
      plantuml_source: $('#vs-plantuml-source').val() || ''
    }, function (response) {
      restoreButton();
      showToast((response.data && response.data.message) ? response.data.message : vsText('extra_settings_updated', 'Extra settings updated'));
    }, function (response) {
      restoreButton();
      const message = (response && typeof response.data === 'string' && response.data) ? response.data : vsText('request_failed', 'Request failed');
      Swal.fire(vsText('error', 'Error'), message, 'error');
    });
  });

  $(document).on('submit', '#vs-visibility-form', function (e) {
    e.preventDefault();
    const restoreButton = setButtonBusy($(this).find('button[type="submit"]').first(), vsText('saving', 'Saving...'));
    const payload = $(this).serializeArray();
    payload.push({ name: 'action', value: 'vs_profile_save_visibility' });
    payload.push({ name: 'security', value: vs_vars.nonce });
    vsProfilePost('vs_profile_save_visibility', payload, function (response) {
      restoreButton();
      showToast((response.data && response.data.message) ? response.data.message : vsText('visibility_saved', 'Visibility saved'));
    }, function (response) {
      restoreButton();
      const message = (response && typeof response.data === 'string' && response.data) ? response.data : vsText('request_failed', 'Request failed');
      Swal.fire(vsText('error', 'Error'), message, 'error');
    });
  });

  $(document).on('click', '#vs-mark-notifications-read', function () {
    vsProfilePost('vs_profile_mark_notifications_read', {
      action: 'vs_profile_mark_notifications_read',
      security: vs_vars.nonce
    }, function (response) {
      showToast((response.data && response.data.message) ? response.data.message : vsText('notifications_updated', 'Notifications updated'));
      $('#vs-notification-count').text('0 notifications');
    });
  });

  $(document).on('click', '#vs-create-landing-page', function () {
    vsProfilePost('vs_profile_create_landing_page', {
      action: 'vs_profile_create_landing_page',
      security: vs_vars.nonce,
        title: vsText('vendor_promotion_landing_page', 'Vendor Promotion Landing Page')
    }, function (response) {
      const d = response.data || {};
      const html = d.edit_url ? `<a href="${d.edit_url}" target="_blank" rel="noopener noreferrer">${vsEscapeHtml(vsText('edit_landing_page', 'Edit Landing Page'))}</a> | <a href="${d.preview_url}" target="_blank" rel="noopener noreferrer">${vsEscapeHtml(vsText('preview', 'Preview'))}</a>` : vsText('landing_page_created', 'Landing page created');
      $('#vs-landing-result').html(html);
      showToast(d.message || vsText('landing_page_created', 'Landing page created'));
    });
  });

  function drawSalesTrendChart() {
    const canvas = document.getElementById('vs-sales-trend-chart');
    if (!canvas) return;

    let labels = [];
    let values = [];
    try {
      labels = JSON.parse(canvas.dataset.labels || '[]');
      values = JSON.parse(canvas.dataset.values || '[]');
    } catch (_) {
      return;
    }
    if (!labels.length || !values.length) return;

    const rect = canvas.getBoundingClientRect();
    const width = Math.max(520, Math.floor(rect.width || 520));
    const height = 220;
    canvas.width = width;
    canvas.height = height;

    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    const pad = { l: 44, r: 18, t: 18, b: 36 };
    const chartW = width - pad.l - pad.r;
    const chartH = height - pad.t - pad.b;
    const maxVal = Math.max(1, ...values.map(v => Number(v) || 0));

    ctx.clearRect(0, 0, width, height);
    ctx.strokeStyle = '#e5e7eb';
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(pad.l, pad.t);
    ctx.lineTo(pad.l, pad.t + chartH);
    ctx.lineTo(pad.l + chartW, pad.t + chartH);
    ctx.stroke();

    ctx.strokeStyle = '#2563eb';
    ctx.lineWidth = 2.5;
    ctx.beginPath();
    values.forEach((v, i) => {
      const x = pad.l + (chartW * i) / Math.max(1, values.length - 1);
      const y = pad.t + chartH - ((Number(v) || 0) / maxVal) * chartH;
      if (i === 0) ctx.moveTo(x, y);
      else ctx.lineTo(x, y);
    });
    ctx.stroke();

    ctx.fillStyle = '#334155';
    ctx.font = '12px Segoe UI, sans-serif';
    labels.forEach((label, i) => {
      const x = pad.l + (chartW * i) / Math.max(1, labels.length - 1);
      ctx.fillText(label, x - 18, height - 12);
    });
  }

  function quickEditEnter($row) {
    if ($row.hasClass('vs-quick-editing')) return;

    const $name = $row.find('.product-name');
    const $price = $row.find('.product-price');
    const $stock = $row.find('.product-stock');
    const $actions = $row.find('td[data-export="skip"]').first();

    const $catCell = $row.find('.product-desc');
    const $statusCell = $row.find('.product-status');
    const $vendorCell = $row.find('.product-vendor');

    const backup = {
      name: $name.html(),
      price: $price.html(),
      stock: $stock.html(),
      category: $catCell.html(),
      status: $statusCell.html(),
      vendor: $vendorCell.length ? $vendorCell.html() : null,
      actions: $actions.html()
    };

    $row.data('vsQuickBackup', backup);

    const priceNumber = parseFloat(($price.text() || '').replace(/[^0-9.]/g, '')) || 0;
    const stockText = ($stock.text() || '').trim();
    const $editBtn = $row.find('.vs-edit-btn').first();
    const stockFromBtn = toNumberOrNull($editBtn.data('product-stock'));
    const stockValue = stockFromBtn !== null ? stockFromBtn : (stockText.toUpperCase() === 'N/A' || stockText.toUpperCase() === 'OOS' ? '' : stockText);

    const currentStatus = String($editBtn.data('product-status') || $editBtn.attr('data-product-status') || '').toLowerCase().trim();
    const currentCat = String($editBtn.data('product-cat') || $editBtn.attr('data-product-cat') || '').trim();
    const vendorEmail = $vendorCell.length ? $('<div>').html($vendorCell.html() || '').text().trim() : '';

    const $statusSource = $('#edit-product-status');
    const $catSource = $('#edit-product-cat');

    const statusHtml = $statusSource.length
      ? $('<div>').append($statusSource.clone().removeAttr('id').removeAttr('name').removeAttr('style').addClass('vs-quick-input vs-quick-status').val(currentStatus)).html()
      : `<input type="text" class="vs-quick-input vs-quick-status" value="${currentStatus}">`;
    const catHtml = $catSource.length
      ? $('<div>').append($catSource.clone().removeAttr('id').removeAttr('name').removeAttr('style').addClass('vs-quick-input vs-quick-cat').val(currentCat)).html()
      : `<input type="text" class="vs-quick-input vs-quick-cat" value="${currentCat}">`;

    $name.html(`
      <label style="display:block; font-size:10px; color:#64748b; margin-bottom:4px; font-weight:600; text-transform:uppercase;">Name</label>
      <input type="text" class="vs-quick-input vs-quick-name" value="${$('<div>').text($name.text().trim()).html()}" style="width:100%; min-width:140px;">
    `);
    $price.html(`
      <label style="display:block; font-size:10px; color:#64748b; margin-bottom:4px; font-weight:600; text-transform:uppercase;">Price</label>
      <input type="number" step="0.01" class="vs-quick-input vs-quick-price" value="${priceNumber.toFixed(2)}" style="width:100%; min-width:80px;">
    `);
    $stock.html(`
      <label style="display:block; font-size:10px; color:#64748b; margin-bottom:4px; font-weight:600; text-transform:uppercase;">Stock</label>
      <input type="number" step="1" min="0" class="vs-quick-input vs-quick-stock" value="${stockValue}" style="width:100%; min-width:70px;">
    `);
    $catCell.html(`
      <label style="display:block; font-size:10px; color:#64748b; margin-bottom:4px; font-weight:600; text-transform:uppercase;">Category</label>
      ${catHtml}
    `);
    $statusCell.html(`
      <label style="display:block; font-size:10px; color:#64748b; margin-bottom:4px; font-weight:600; text-transform:uppercase;">Status</label>
      ${statusHtml}
    `);
    
    // Add vendor name if admin and it exists
    if ($vendorCell.length && vendorEmail) {
      $vendorCell.html(`<span style="color:#cbd5f5; font-size:12px;">${vendorEmail}</span>`);
    }
    
    $actions.html(`
      <div class="vs-action-buttons" style="display:flex; gap:5px;">
        <button class="vs-quick-save-btn" style="background:#16a34a; color:#fff; border:none; padding:5px 10px; border-radius:4px; cursor:pointer; font-weight:600;">${vsEscapeHtml(vsText('save', 'Save'))}</button>
        <button class="vs-quick-cancel-btn" style="background:#6b7280; color:#fff; border:none; padding:5px 10px; border-radius:4px; cursor:pointer; font-weight:600;">${vsEscapeHtml(vsText('cancel', 'Cancel'))}</button>
      </div>
    `);

    $row.addClass('vs-quick-editing');
    $row.css('background-color', '#fef3c7'); // لون أصفر فاتح أثناء التعديل

    // Enter = Save
    $row.find('input').off('keydown').on('keydown', function (e) {
      if (e.key === 'Enter') {
        $row.find('.vs-quick-save-btn').click();
      }
    });
  }

  function quickEditRestore($row) {
    const backup = $row.data('vsQuickBackup');
    if (!backup) return;

    $row.find('.product-name').html(backup.name);
    $row.find('.product-price').html(backup.price);
    $row.find('.product-stock').html(backup.stock);
    $row.find('.product-desc').html(backup.category);
    $row.find('.product-status').html(backup.status);
    
    // Restore vendor cell if it was backed up
    if (backup.vendor) {
      $row.find('.product-vendor').html(backup.vendor);
    }
    
    $row.find('td[data-export="skip"]').first().html(backup.actions);

    // إعادة لون الصف الطبيعي
    $row.css('background-color', '');
    $row.removeClass('vs-quick-editing');
    $row.removeData('vsQuickBackup');
  }

  function applyQuickUpdateToRow($row, d) {
    const title = $('<div>').text(d.title || $row.find('.product-name').text().trim()).html();
    const price = '$' + (d.price || $row.find('.product-price').text().trim().replace(/[^0-9.]/g, ''));
    const stock = formatStockCellHtml((d.stock !== undefined) ? d.stock : (function () {
      const t = $row.find('.product-stock').text().trim();
      return /^\d+$/.test(t) ? t : (t.toUpperCase() === 'OOS' ? 0 : t);
    })());

    const existingCat = $row.find('.product-desc').text().trim();
    const catName = (d.cat_name !== undefined && d.cat_name !== null) ? (d.cat_name || '—') : existingCat;
    const status = d.status || $row.find('.vs-edit-btn').data('product-status') || '';
    const statusLabel = d.status_label || (status === 'publish' ? vsText('published', 'Published') : status === 'pending' ? vsText('pending_approval', 'Pending Approval') : vsText('draft', 'Draft'));
    const statusClass = d.status_class || (status === 'publish' ? 'published' : status === 'pending' ? 'pending' : 'draft');

    $row.find('.product-name').html(title);
    $row.find('.product-price').html(price);
    $row.find('.product-stock').html(stock);
    $row.find('.product-desc').html(catName);
    $row.find('.product-status').html(`<span class="vs-status-badge ${statusClass}">${statusLabel}</span>`);

    const catId = d.cat_id !== undefined ? d.cat_id : $row.find('.vs-edit-btn').data('product-cat');
    const productStatus = d.status || status;

    $row.find('.vs-edit-btn').first()
      .data('product-stock', (d.stock !== undefined) ? d.stock : null)
      .data('product-cat', catId)
      .data('product-status', productStatus)
      .attr('data-product-stock', (d.stock !== undefined) ? d.stock : '')
      .attr('data-product-cat', catId)
      .attr('data-product-status', productStatus);
  }

  function bulkQuickEditDialog() {
    const selectedIds = $('.vs-select-product:checked').map(function () {
      return $(this).val();
    }).get();

    if (!selectedIds.length) {
      Swal.fire(vsText('info', 'Info'), vsText('select_products_to_edit', 'Please select products to edit'), 'info');
      return;
    }

    const $statusSource = $('#edit-product-status');
    const $catSource = $('#edit-product-cat');

   const statusHtml = $statusSource.length
  ? $('<div>')
      .append(
        $statusSource
          .clone()
          .removeAttr('id')
          .removeAttr('name')
          .removeAttr('style')
          .addClass('vs-bulk-quick-field vs-bulk-quick-status')
      )
      .html()
  : '<input type="text" class="vs-bulk-quick-field vs-bulk-quick-status" placeholder="Enter status">';

const catHtml = $catSource.length
  ? $('<div>')
      .append(
        $catSource
          .clone()
          .removeAttr('id')
          .removeAttr('name')
          .removeAttr('style')
          .addClass('vs-bulk-quick-field vs-bulk-quick-cat')
      )
      .html()
  : '<input type="text" class="vs-bulk-quick-field vs-bulk-quick-cat" placeholder="Enter category ID">';
  
    Swal.fire({
      title: vsText('bulk_quick_edit', 'Bulk Quick Edit'),
    html: `
  <div class="vs-bulk-modal-body">
    <div class="vs-bulk-modal-card">
      <label class="vs-bulk-modal-label">Category</label>
      <div class="vs-bulk-modal-control">
        ${catHtml}
      </div>
    </div>

    <div class="vs-bulk-modal-card">
      <label class="vs-bulk-modal-label">Status</label>
      <div class="vs-bulk-modal-control">
        ${statusHtml}
      </div>
    </div>

    <div class="vs-bulk-modal-note">
      Only the selected fields will be applied to chosen products.
    </div>
  </div>
`,
      showCancelButton: true,
      confirmButtonText: 'Apply',
      preConfirm: () => {
        let category = $('.vs-bulk-quick-cat').val();
        let status = $('.vs-bulk-quick-status').val();
        category = category === '0' ? '' : (category || '');
        status = status || '';
        if (!category && !status) {
          Swal.showValidationMessage(vsText('select_category_or_status', 'Select at least Category or Status to apply.'));
          return false;
        }
        return { category, status };
      }
    }).then((result) => {
      if (!result.isConfirmed) return;
      const { category, status } = result.value;
      bulkQuickEditApply(selectedIds, { category, status });
    });
  }

  function bulkQuickEditApply(ids, { category, status }) {
    if (!ids.length) return;

    Swal.fire({
      title: 'Updating products...',
      html: vsText('please_wait_selected_products_updated', 'Please wait while the selected products are updated.'),
      allowOutsideClick: false,
      didOpen: () => {
        Swal.showLoading();
      }
    });

    const promises = ids.map((id) => {
      const $row = $(`#product-row-${id}`);
      if (!$row.length) return Promise.resolve({ id, success: false, reason: 'Row not found' });

      const title = $row.find('.product-name').text().trim();
      const price = $row.find('.product-price').text().trim().replace(/[^0-9.]/g, '') || '0';
      let stockText = $row.find('.product-stock').text().trim();
      if (stockText.toUpperCase() === 'OOS') stockText = '0';
      const stock = /^\d+$/.test(stockText) ? stockText : '0';

      return new Promise((resolve) => {
        const payload = {
          action: 'vs_profile_quick_update_product',
          security: vs_vars.nonce,
          product_id: id,
          title: title,
          price: price,
          stock: stock
        };
        if (category) payload.category = category;
        if (status) payload.status = status;

        vsProfilePost('vs_profile_quick_update_product', payload, (response) => {
          if (response && response.success && response.data) {
            applyQuickUpdateToRow($row, response.data);
            resolve({ id, success: true });
          } else {
            resolve({ id, success: false, reason: response && response.data ? response.data : 'Unknown' });
          }
        });
      });
    });

    Promise.all(promises).then((results) => {
      const failed = results.filter(r => !r.success);
      Swal.close();

      if (!failed.length) {
        Swal.fire(vsText('done', 'Done'), vsText('selected_products_updated', 'Selected products updated successfully.'), 'success');
      } else {
        Swal.fire(vsText('partial_update', 'Partial Update'), vsSprintf(vsText('partial_update_message', '%1$s updated, %2$s failed.'), ids.length - failed.length, failed.length), 'warning');
      }
    });
  }

  $(document).on('click', '#vs-bulk-quick-edit', function (e) {
    e.preventDefault();
    bulkQuickEditDialog();
  });

  $(document).on('click', '.vs-quick-edit-btn', function (e) {
    e.preventDefault();
    const $row = $(this).closest('tr');
    quickEditEnter($row);
  });

  $(document).on('click', '.vs-quick-cancel-btn', function (e) {
    e.preventDefault();
    quickEditRestore($(this).closest('tr'));
  });

  $(document).on('click', '.vs-quick-save-btn', function (e) {
    e.preventDefault();
    const $row = $(this).closest('tr');
    const productId = Number(($row.attr('id') || '').replace('product-row-', '')) || 0;
    const $titleInput = $row.find('.vs-quick-name').first();
    const $priceInput = $row.find('.vs-quick-price').first();
    const $stockInput = $row.find('.vs-quick-stock').first();
    const $categoryInput = $row.find('.vs-quick-cat').first();
    const $statusInput = $row.find('.vs-quick-status').first();
    const title = String($titleInput.val() || '').trim();
    const price = String($priceInput.val() || '').trim();
    const stock = String($stockInput.val() || '').trim();
    const category = $categoryInput.length ? $categoryInput.val() : '';
    const status = $statusInput.length ? $statusInput.val() : '';

    // منع الحفظ إذا فارغ
    if (!title) {
      Swal.fire({
        icon: 'warning',
        title: vsText('error', 'Error'),
        html: '<strong>❌ Please fill all required fields:</strong><br>• Product Name<br>• Price',
        confirmButtonText: vsText('ok', 'OK'),
        confirmButtonColor: '#2563eb'
      });
      return;
    }

    // تغيير لون الصف أثناء الحفظ
    $row.css('background-color', '#dbeafe');
    const $saveBtn = $(this);
    $saveBtn.prop('disabled', true).text('Saving...');
    // If admin requires approval and vendor tries to publish, notify them
    if (vs_vars && vs_vars.require_product_approval && !vs_vars.is_admin && String(status || '').toLowerCase() === 'publish') {
      Swal.fire({
        icon: 'info',
        title: vsText('awaiting_admin_approval', 'Awaiting admin approval'),
        html: vsText('awaiting_admin_approval_message', 'Products require admin approval. Your product will be submitted for review and will go live after an administrator approves it.'),
        confirmButtonText: vsText('ok', 'OK')
      });
    }

    vsProfilePost('vs_profile_quick_update_product', {
      action: 'vs_profile_quick_update_product',
      security: vs_vars.nonce,
      product_id: productId,
      title: title,
      price: price,
      stock: stock,
      category: category,
      status: status
    }, function (response) {
      $saveBtn.prop('disabled', false).text('Save');
      
      if (!response || !response.success) {
        Swal.fire({
          icon: 'error',
          title: vsText('error', 'Error'),
          html: '<strong>❌ Failed to update product:</strong><br>' + (response.data || 'Unknown error'),
          confirmButtonText: vsText('ok', 'OK'),
          confirmButtonColor: '#dc2626'
        });
        $row.css('background-color', '');
        return;
      }

      const d = response.data || {};
      const backup = $row.data('vsQuickBackup') || {};

      const newTitle = $('<div>').text(d.title || title).html();
      const newPrice = '$' + (d.price || price);
      const newStock = formatStockCellHtml((d.stock !== undefined) ? d.stock : stock);

      const newCatName = (d.cat_name !== undefined ? d.cat_name : $row.find('.vs-quick-cat option:selected').text()) || '—';
      let newStatus = d.status || status;
      let statusLabel = d.status_label || (newStatus === 'publish' ? vsText('published', 'Published') : newStatus === 'pending' ? vsText('pending_approval', 'Pending Approval') : vsText('draft', 'Draft'));
      let statusClass = d.status_class || (newStatus === 'publish' ? 'published' : newStatus === 'pending' ? 'pending' : 'draft');

      // If admin requires approval and a vendor attempted to publish, show Pending Approval
      if (vs_vars && vs_vars.require_product_approval && !vs_vars.is_admin && String(status || '').toLowerCase() === 'publish') {
        newStatus = 'pending';
        statusLabel = vsText('pending_approval', 'Pending Approval');
        statusClass = 'pending';
      }

      backup.name = newTitle;
      backup.price = newPrice;
      backup.stock = newStock;
      backup.category = newCatName;
      backup.status = `<span class="vs-status-badge ${statusClass}">${statusLabel}</span>`;
      $row.data('vsQuickBackup', backup);

      const catId = (d.cat_id !== undefined ? d.cat_id : category);
      const $editBtn = $row.find('.vs-edit-btn').first();
      $editBtn
        .data('product-stock', (d.stock !== undefined) ? d.stock : stock)
        .data('product-cat', catId)
        .data('product-status', newStatus)
        .attr('data-product-stock', (d.stock !== undefined) ? d.stock : stock)
        .attr('data-product-cat', catId)
        .attr('data-product-status', newStatus);

      if ($('#edit-product-cat').length) {
        $('#edit-product-cat').val(catId);
      }
      if ($('#edit-product-status').length) {
        $('#edit-product-status').val(newStatus);
      }

      $row.find('.product-desc').html(newCatName);
      $row.find('.product-status').html(`<span class="vs-status-badge ${statusClass}">${statusLabel}</span>`);

      // Reset cached 'original' values so applyUnifiedProductFilters shows the updated data
      $row.find('td.product-name').removeData('original');
      $row.find('td.product-desc').removeData('original');

      quickEditRestore($row);

      Swal.fire({
        icon: 'success',
        title: '✅ Product Updated Successfully!',
        html: '<strong>' + newTitle + '</strong><br>All changes have been saved.',
        confirmButtonText: vsText('ok', 'OK'),
        confirmButtonColor: '#16a34a',
        timer: 3000,
        timerProgressBar: true
      });
    }, function (error) {
      $saveBtn.prop('disabled', false).text('Save');
      $row.css('background-color', '');
      Swal.fire({
        icon: 'error',
        title: vsText('error', 'Error'),
        html: '<strong>❌ Connection failed!</strong><br>Please check your internet and try again.',
        confirmButtonText: vsText('ok', 'OK'),
        confirmButtonColor: '#dc2626'
      });
    });
  });


  // Keep session alive for long dashboard sessions.
  setInterval(function () {
    if (!document.querySelector('.vs-dashboard')) return;
    $.post(vs_vars.ajaxurl, {
      action: 'vs_profile_keepalive',
      security: vs_vars.nonce
    });
  }, 240000);

  drawSalesTrendChart();
  $(document).on('click', '.vs-tab-link[data-tab="profile"]', function () {
    setTimeout(drawSalesTrendChart, 120);
  });

  // Poll publish requests and badges for admins, refresh rows if tab visible
  if (vs_vars && vs_vars.is_admin) {
    const POLL_INTERVAL = 8000; // ms
    function applyPendingCounts(data) {
      const n = parseInt(data.pending || 0, 10) || 0;
      const cat = parseInt(data.pending_cat || 0, 10) || 0;
      const total = n + cat;
      const $pubBadge = $('#vs-publish-requests-badge');
      const $prodBadge = $('#vs-products-badge');
      const $catBadge = $('#vs-category-requests-badge');
      const $countTitle = $('#vs-publish-requests-count');

      if ($pubBadge.length) { if (n>0) $pubBadge.text(n).show(); else $pubBadge.hide(); }
      if ($prodBadge.length) { if (total>0) $prodBadge.text(total).show(); else $prodBadge.hide(); }
      if ($catBadge.length) { if (cat>0) $catBadge.text(cat).show(); else $catBadge.hide(); }
      if ($countTitle.length) { $countTitle.text(n); }
    }

    function pollPending() {
      $.post(vs_vars.ajaxurl, { action: 'vs_get_pending_counts' }, function(resp) {
        if (resp && resp.success && resp.data) {
          applyPendingCounts(resp.data);
        }
      });

      // If publish requests tab visible — refresh rows only
      const $tab = $('#tab-publish-requests');
      if ($tab.length && $tab.is(':visible')) {
        $.post(vs_vars.ajaxurl, { action: 'vs_refresh_publish_requests_rows' }, function(r) {
          if (r && r.success && r.data) {
            const html = r.data.html || '';
            const pending = r.data.pending_count || 0;
            $tab.find('tbody').html(html);
            $('#vs-publish-requests-count').text(pending);
            const $badge = $('#vs-publish-requests-badge');
            if ($badge.length) { if (pending>0) $badge.text(pending).show(); else $badge.hide(); }
          }
        });
      }
    }

    // start polling
    setInterval(pollPending, POLL_INTERVAL);
    // initial fetch
    setTimeout(pollPending, 800);
  }


  // ==============================
  // Mobile Hamburger Toggle
  // ==============================
  jQuery(document).on('click', '.vs-sidebar-toggle', function () {
    var $sidebar = jQuery('.vs-sidebar');
    $sidebar.toggleClass('vs-sidebar--hidden');
  });

});
