/* PrimeLink Admin JS (REST-only)
 * Version: 1.0.0
 */

(function($){
  'use strict';

  // Global adminUrl fallback to avoid ReferenceError in older code paths.
  // Prefer mtPrimeLink.adminUrl if available, otherwise derive from ajaxurl or location.
  if (typeof window.adminUrl === 'undefined') {
    if (typeof mtPrimeLink !== 'undefined' && mtPrimeLink.adminUrl) {
      window.adminUrl = mtPrimeLink.adminUrl;
    } else if (typeof ajaxurl !== 'undefined') {
      window.adminUrl = ajaxurl.replace(/admin-ajax\.php.*/, '');
    } else {
      window.adminUrl = window.location.origin + '/wp-admin/';
    }
  }

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

  // ============================================
  // Toast Notifications System
  // ============================================
  
  /**
   * Initialize toast container if it doesn't exist
   */
  function initToastContainer() {
    if ($('#mt_primelink-toast-container').length === 0) {
      $('body').append('<div id="mt_primelink-toast-container" class="mt_primelink-toast-container"></div>');
    }
  }

  /**
   * Show a toast notification
   * @param {string} type - 'success', 'error', 'warning', 'info'
   * @param {string} message - Message to display
   * @param {string} title - Optional title
   * @param {number} duration - Auto-dismiss duration in ms (0 = no auto-dismiss, default 5000)
   */
  function showToast(type, message, title, duration) {
    initToastContainer();
    
    const container = $('#mt_primelink-toast-container');
    const toastId = 'toast-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
    const autoDismiss = duration !== undefined ? duration : 5000;
    
    // Icon mapping
    const icons = {
      success: '✓',
      error: '✕',
      warning: '⚠',
      info: 'ℹ'
    };
    
    const icon = icons[type] || icons.info;
    
    // Create toast HTML
    const toastHtml = `
      <div class="mt_primelink-toast mt_primelink-toast-${type}" id="${toastId}" data-toast-id="${toastId}">
        <div class="mt_primelink-toast-icon">${escapeHtml(icon)}</div>
        <div class="mt_primelink-toast-content">
          ${title ? `<div class="mt_primelink-toast-title">${escapeHtml(title)}</div>` : ''}
          <div class="mt_primelink-toast-message">${escapeHtml(message)}</div>
        </div>
        <button type="button" class="mt_primelink-toast-close" aria-label="Close">×</button>
        ${autoDismiss > 0 ? '<div class="mt_primelink-toast-progress"><div class="mt_primelink-toast-progress-bar"></div></div>' : ''}
      </div>
    `;
    
    const $toast = $(toastHtml);
    container.append($toast);
    
    // Trigger animation
    setTimeout(() => {
      $toast.addClass('mt_primelink-toast-visible');
    }, 10);
    
    // Auto-dismiss progress bar
    if (autoDismiss > 0) {
      const $progressBar = $toast.find('.mt_primelink-toast-progress-bar');
      $progressBar.css('width', '100%');
      $progressBar.css('transition', `width ${autoDismiss}ms linear`);
      
      setTimeout(() => {
        $progressBar.css('width', '0%');
      }, 50);
      
      const dismissTimer = setTimeout(() => {
        dismissToast(toastId);
      }, autoDismiss);
      
      $toast.data('dismiss-timer', dismissTimer);
    }
    
    // Close button handler
    $toast.find('.mt_primelink-toast-close').on('click', function() {
      dismissToast(toastId);
    });
    
    // Pause auto-dismiss on hover
    if (autoDismiss > 0) {
      $toast.on('mouseenter', function() {
        const timer = $(this).data('dismiss-timer');
        if (timer) {
          clearTimeout(timer);
          $(this).data('dismiss-timer', null);
          const $progressBar = $(this).find('.mt_primelink-toast-progress-bar');
          const remaining = autoDismiss - (Date.now() - ($(this).data('created') || Date.now()));
          if (remaining > 0) {
            $progressBar.css('transition', 'none');
            const currentWidth = parseFloat($progressBar.css('width')) / parseFloat($progressBar.parent().css('width')) * 100;
            $progressBar.css('width', currentWidth + '%');
          }
        }
      });
      
      $toast.on('mouseleave', function() {
        const remaining = autoDismiss - (Date.now() - ($(this).data('created') || Date.now()));
        if (remaining > 0) {
          const $progressBar = $(this).find('.mt_primelink-toast-progress-bar');
          $progressBar.css('transition', `width ${remaining}ms linear`);
          setTimeout(() => {
            $progressBar.css('width', '0%');
          }, 10);
          
          const dismissTimer = setTimeout(() => {
            dismissToast(toastId);
          }, remaining);
          
          $(this).data('dismiss-timer', dismissTimer);
        }
      });
      
      $toast.data('created', Date.now());
    }
    
    return toastId;
  }
  
  /**
   * Dismiss a toast notification
   * @param {string} toastId - Toast ID to dismiss
   */
  function dismissToast(toastId) {
    const $toast = $('#' + toastId);
    if ($toast.length === 0) return;
    
    // Clear dismiss timer if exists
    const timer = $toast.data('dismiss-timer');
    if (timer) {
      clearTimeout(timer);
    }
    
    // Add exit animation class
    $toast.addClass('mt_primelink-toast-exit');
    
    // Remove after animation
    setTimeout(() => {
      $toast.remove();
    }, 300);
  }
  
  /**
   * Helper functions for different toast types
   */
  window.mtPrimeLinkToast = {
    success: function(message, title, duration) {
      return showToast('success', message, title, duration);
    },
    error: function(message, title, duration) {
      return showToast('error', message, title, duration);
    },
    warning: function(message, title, duration) {
      return showToast('warning', message, title, duration);
    },
    info: function(message, title, duration) {
      return showToast('info', message, title, duration);
    },
    dismiss: function(toastId) {
      dismissToast(toastId);
    }
  };

  /**
   * Helper function to show toast or fallback to alert
   * Use this to gradually replace alert() calls
   */
  function showToastOrAlert(type, message, title, duration) {
    if (window.mtPrimeLinkToast && typeof window.mtPrimeLinkToast[type] === 'function') {
      return window.mtPrimeLinkToast[type](message, title, duration);
    } else {
      // Fallback to alert
      if (title) {
        alert(title + ': ' + message);
      } else {
        alert(message);
      }
      return null;
    }
  }

  // ============================================
  // Keyboard Shortcuts System
  // ============================================
  
  /**
   * Initialize keyboard shortcuts based on current page context
   */
  function initKeyboardShortcuts() {
    // Don't interfere with inputs, textareas, or contenteditable elements
    $(document).on('keydown', function(e) {
      // Ignore if user is typing in an input, textarea, or contenteditable
      const $target = $(e.target);
      const isInput = $target.is('input, textarea, [contenteditable="true"]');
      const isSelect = $target.is('select');
      
      // Allow shortcuts if Ctrl/Cmd is pressed (for save shortcuts) or Esc
      if (isInput && e.key !== 'Escape' && !(e.ctrlKey || e.metaKey)) {
        return;
      }
      
      // Check for specific shortcuts
      const isCtrlOrCmd = e.ctrlKey || e.metaKey;
      
      // Ctrl/Cmd + S - Save
      if (isCtrlOrCmd && e.key === 's' || e.key === 'S') {
        e.preventDefault();
        handleSaveShortcut();
        return false;
      }
      
      // Ctrl/Cmd + N - New Import (only on dashboard/manage pages)
      if (isCtrlOrCmd && (e.key === 'n' || e.key === 'N')) {
        e.preventDefault();
        handleNewImportShortcut();
        return false;
      }
      
      // Esc - Close modal/dialog
      if (e.key === 'Escape') {
        handleEscapeShortcut();
        return false;
      }
    });
    
    // Show keyboard shortcuts hint (optional, can be toggled)
    if (typeof mtPrimeLink !== 'undefined' && mtPrimeLink.showShortcutsHint !== false) {
      setTimeout(function() {
        showShortcutsHint();
      }, 2000);
    }
  }
  
  /**
   * Handle Ctrl/Cmd + S - Save current step/settings
   */
  function handleSaveShortcut() {
    // Check for Settings page save button
    const $settingsSave = $('#mt_primelink-save-settings');
    if ($settingsSave.length && $settingsSave.is(':visible') && !$settingsSave.prop('disabled')) {
      $settingsSave.trigger('click');
      showShortcutFeedback('Settings saved', 'Ctrl+S');
      return;
    }
    
    // Check for template save button
    const $templateSave = $('#mt_primelink-save-template');
    if ($templateSave.length && $templateSave.is(':visible') && !$templateSave.prop('disabled')) {
      $templateSave.trigger('click');
      showShortcutFeedback('Template saved', 'Ctrl+S');
      return;
    }
    
    // Check for Next/Finish button in wizard
    const $next = $('#mt-primelink-next');
    if ($next.length && $next.is(':visible') && !$next.prop('disabled')) {
      // Check if it's the last step (finish)
      const $finish = $('#mt-primelink-finish');
      if ($finish.length && $finish.is(':visible')) {
        // Don't auto-finish, just show hint
        showShortcutFeedback('Press Ctrl+S to save, or click Finish to complete', 'Ctrl+S');
      } else {
        $next.trigger('click');
        showShortcutFeedback('Step saved', 'Ctrl+S');
      }
      return;
    }
    
    // No save action available
    showShortcutFeedback('No save action available on this page', 'Ctrl+S');
  }
  
  /**
   * Handle Ctrl/Cmd + N - New Import
   */
  function handleNewImportShortcut() {
    // Check if we're on a page where New Import makes sense
    const currentPage = window.location.href;
    
    if (currentPage.includes('mt-primelink') && 
        !currentPage.includes('mt-primelink-new-import') && 
        !currentPage.includes('mt-primelink-new-export')) {
      
      // Check if New Import button exists on current page
      const $newImportBtn = $('a[href*="mt-primelink-new-import"]').first();
      if ($newImportBtn.length) {
        window.location.href = $newImportBtn.attr('href');
        return;
      }
      
      // Otherwise navigate to new import select page
      if (typeof mtPrimeLink !== 'undefined' && mtPrimeLink.adminUrl) {
        window.location.href = mtPrimeLink.adminUrl + 'admin.php?page=mt-primelink-new-import';
      } else {
        // Fallback
        const adminBase = window.location.origin + '/wp-admin/';
        window.location.href = adminBase + 'admin.php?page=mt-primelink-new-import';
      }
    }
  }
  
  /**
   * Handle Esc - Close modal/dialog
   */
  function handleEscapeShortcut() {
    // Check for visible modals
    const $modal = $('.mt-primelink-modal:visible, .mt-primelink-modal__overlay:visible').closest('.mt-primelink-modal');
    if ($modal.length) {
      $modal.find('.mt-primelink-modal__close').first().trigger('click');
      return;
    }
    
    // Check for map editor (if visible)
    const $mapEditor = $('.mt_primelink-map-editor:visible');
    if ($mapEditor.length) {
      $mapEditor.find('.mt_primelink-map-editor-close').first().trigger('click');
      return;
    }
    
    // Check for any other closeable overlays
    const $overlay = $('.mt-primelink-wizard-overlay:visible');
    if ($overlay.length) {
      // Don't close wizard automatically, just show hint
      return;
    }
  }
  
  /**
   * Show visual feedback for keyboard shortcut
   */
  function showShortcutFeedback(message, shortcut) {
    if (window.mtPrimeLinkToast) {
      window.mtPrimeLinkToast.info(message, 'Keyboard Shortcut: ' + shortcut, 2000);
    }
  }
  
  /**
   * Show keyboard shortcuts hint (one-time, on page load)
   */
  function showShortcutsHint() {
    // Only show if user hasn't dismissed it before
    const dismissed = localStorage.getItem('mt_primelink_shortcuts_dismissed');
    if (dismissed === 'true') {
      return;
    }
    
    // Determine which shortcuts are available on this page
    const shortcuts = [];
    
    if ($('#mt_primelink-save-settings').length || $('#mt_primelink-save-template').length || $('#mt-primelink-next').length) {
      shortcuts.push('Ctrl+S - Save');
    }
    
    if (window.location.href.includes('mt-primelink') && !window.location.href.includes('mt-primelink-new-import')) {
      shortcuts.push('Ctrl+N - New Import');
    }
    
    if ($('.mt-primelink-modal:visible, .mt_primelink-map-editor:visible').length) {
      shortcuts.push('Esc - Close');
    }
    
    if (shortcuts.length === 0) {
      return;
    }
    
    // Show hint toast (can be dismissed)
    if (window.mtPrimeLinkToast) {
      const toastId = window.mtPrimeLinkToast.info(
        'Keyboard shortcuts: ' + shortcuts.join(', '),
        'Keyboard Shortcuts',
        8000
      );
      
      // Add dismiss button to localStorage
      setTimeout(function() {
        const $toast = $('[data-toast-id="' + toastId + '"]');
        if ($toast.length) {
          const $dismissBtn = $('<button type="button" class="button-link" style="margin-left:10px;font-size:11px;">Don\'t show again</button>');
          $dismissBtn.on('click', function(e) {
            e.stopPropagation();
            localStorage.setItem('mt_primelink_shortcuts_dismissed', 'true');
            if (window.mtPrimeLinkToast && window.mtPrimeLinkToast.dismiss) {
              window.mtPrimeLinkToast.dismiss(toastId);
            }
          });
          $toast.find('.mt_primelink-toast-content').append($dismissBtn);
        }
      }, 100);
    }
  }
  
  /**
   * Show keyboard shortcuts modal
   */
  function showShortcutsModal() {
    // Check if modal already exists
    let $modal = $('#mt-primelink-shortcuts-modal');
    
    if ($modal.length === 0) {
      // Detect if Mac (for Cmd vs Ctrl)
      const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
      const modifierKey = isMac ? 'Cmd' : 'Ctrl';
      
      // Create modal HTML
      const modalHtml = `
        <div id="mt-primelink-shortcuts-modal" class="mt_primelink-shortcuts-modal">
          <div class="mt_primelink-shortcuts-modal__content">
            <div class="mt_primelink-shortcuts-modal__header">
              <h2>Keyboard Shortcuts</h2>
              <button type="button" class="mt_primelink-shortcuts-modal__close" aria-label="Close">&times;</button>
            </div>
            <div class="mt_primelink-shortcuts-modal__body">
              <ul class="mt_primelink-shortcuts-list">
                <li class="mt_primelink-shortcuts-list__item">
                  <div class="mt_primelink-shortcuts-list__description">
                    <strong>Save</strong>
                    <span>Save settings, template, or current step</span>
                  </div>
                  <div class="mt_primelink-shortcuts-list__keys">
                    <kbd>${modifierKey}</kbd><span class="mt_primelink-shortcuts-list__separator">+</span><kbd>S</kbd>
                  </div>
                </li>
                <li class="mt_primelink-shortcuts-list__item">
                  <div class="mt_primelink-shortcuts-list__description">
                    <strong>New Import</strong>
                    <span>Navigate to New Import page</span>
                  </div>
                  <div class="mt_primelink-shortcuts-list__keys">
                    <kbd>${modifierKey}</kbd><span class="mt_primelink-shortcuts-list__separator">+</span><kbd>N</kbd>
                  </div>
                </li>
                <li class="mt_primelink-shortcuts-list__item">
                  <div class="mt_primelink-shortcuts-list__description">
                    <strong>Close Modal</strong>
                    <span>Close any open modal or dialog</span>
                  </div>
                  <div class="mt_primelink-shortcuts-list__keys">
                    <kbd>Esc</kbd>
                  </div>
                </li>
              </ul>
              <p style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #f0f0f1; font-size: 12px; color: #646970;">
                ${isMac ? 'Note: Use Cmd key on Mac' : 'Note: Use Ctrl key on Windows/Linux'}
              </p>
            </div>
          </div>
        </div>
      `;
      
      $modal = $(modalHtml);
      $('body').append($modal);
      
      // Close handlers
      $modal.find('.mt_primelink-shortcuts-modal__close').on('click', function() {
        hideShortcutsModal();
      });
      
      $modal.on('click', function(e) {
        if ($(e.target).hasClass('mt_primelink-shortcuts-modal')) {
          hideShortcutsModal();
        }
      });
      
      // Close on Esc
      $(document).on('keydown.shortcuts-modal', function(e) {
        if (e.key === 'Escape' && $modal.hasClass('is-active')) {
          hideShortcutsModal();
        }
      });
    }
    
    // Show modal
    setTimeout(function() {
      $modal.addClass('is-active');
    }, 10);
  }
  
  /**
   * Hide keyboard shortcuts modal
   */
  function hideShortcutsModal() {
    const $modal = $('#mt-primelink-shortcuts-modal');
    if ($modal.length) {
      $modal.removeClass('is-active');
      $(document).off('keydown.shortcuts-modal');
    }
  }
  
  // Handle shortcuts info button click
  $(document).on('click', '#mt-primelink-show-shortcuts', function(e) {
    e.preventDefault();
    showShortcutsModal();
  });
  
  // Initialize keyboard shortcuts on document ready
  $(document).ready(function() {
    initKeyboardShortcuts();
  });

  function currentImportId(){
    const url = new URL(window.location.href);
    let id = parseInt(url.searchParams.get('import_id') || '0', 10);
    if(!id){
      const $step = $('[data-import-id]').first();
      id = parseInt($step.data('import-id') || '0', 10);
    }
    return id || 0;
  }

  function setImportIdEverywhere(importId){
    const url = new URL(window.location.href);
    url.searchParams.set('import_id', importId);
    history.replaceState({}, '', url.toString());

    $('#mt-primelink-next, #mt-primelink-finish').data('import-id', importId);
  }

  async function restPost(path, body, isFormData=false){
    if (typeof mtPrimeLink === 'undefined') {
      throw { status: 0, json: { message: 'mtPrimeLink is not defined. Make sure the script is properly enqueued.' } };
    }
    
    const opts = {
      method: 'POST',
      headers: {
        'X-WP-Nonce': mtPrimeLink.restNonce
      }
    };
    if(isFormData){
      // For FormData, don't set Content-Type header (browser will set it with boundary)
      // But keep X-WP-Nonce header
      opts.body = body;
    } else {
      opts.headers['Content-Type'] = 'application/json';
      opts.body = JSON.stringify(body || {});
    }

    try {
      const r = await fetch(mtPrimeLink.restUrl + path, opts);
      let j = {};
      try {
        j = await r.json();
      } catch (jsonError) {
        // If JSON parsing fails, try to get text
        const text = await r.text();
        j = { message: text || 'Invalid JSON response from server', raw: text };
      }
      
      if(!r.ok) {
        const error = {status:r.status, json:j};
        console.error('REST API Error:', path, error);
        throw error;
      }
      return j;
    } catch (e) {
      // If it's already our error object, re-throw it
      if (e.status !== undefined) {
        throw e;
      }
      // Otherwise, wrap it
      console.error('Network error:', e);
      throw { status: 0, json: { message: e.message || 'Network error or server unavailable' } };
    }
  }

  async function restGet(path){
    try{
      const r = await fetch(mtPrimeLink.restUrl + path, {
        method: 'GET',
        headers: { 'X-WP-Nonce': mtPrimeLink.restNonce }
      });
      const j = await r.json().catch(()=> ({}));
      if(!r.ok){
        const error = {status:r.status, json:j};
        console.error('REST API GET Error:', path, error);
        throw error;
      }
      return j;
    }catch(e){
      if (e.status !== undefined) {
        throw e;
      }
      console.error('REST API GET Network error:', path, e);
      throw { status: 0, json: { message: e.message || 'Network error or server unavailable' } };
    }
  }

  function getStep(){
    return parseInt($('#mt-primelink-step').val(), 10) || 1;
  }

  function parseStepFromHref(href){
    try{
      const url = new URL(href, window.location.href);
      return parseInt(url.searchParams.get('step') || '0', 10) || 1;
    }catch(e){
      return getStep();
    }
  }

  // Full-page load navigation (no SPA)
  async function loadWizardStep(url){
    window.location.href = url;
  }

  function getStepData(){
    const data = {};
    $('.mt-primelink-wizard__body').find('input, select, textarea').each(function(){
      const $el = $(this);
      const name = $el.attr('name');
      if(!name) return;

      if($el.is(':radio')){
        if($el.is(':checked')) data[name] = $el.val();
      } else if($el.is(':checkbox')){
        data[name] = $el.is(':checked') ? 1 : 0;
      } else {
        data[name] = $el.val();
      }
    });
    return data;
  }

  // -----------------------------
  // Wizard Next
  // -----------------------------
  // Block clicking on steps ahead of current
  $(document).on('click', '.mt-primelink-step', function(e){
    const targetStep = parseStepFromHref($(this).attr('href'));
    const currentStep = getStep();

    // Prevent jumping ahead or backwards: enforce linear flow
    if (targetStep !== currentStep) {
      e.preventDefault();
      return false;
    }
  });

  $(document).on('click', '#mt-primelink-next', async function(e){
    e.preventDefault();

    const nextStep = parseInt($(this).data('next'), 10);
    const step     = getStep();
    let importId   = parseInt($(this).data('import-id'), 10) || currentImportId();

    // Step-specific validation before saving
    if (step === 2) {
      // Require a source file/configuration before moving on
      const source = $('input[name="source"]:checked').val();
      let valid = false;

      if (source === 'desktop') {
        // Desktop: must have uploaded file (path stored in draft step 2 or in hidden state)
        // Quick client-side check: look for any saved file info in the dropzone hint element
        // Fallback: block and show tooltip if not yet handled by AJAX.
        const hasFile = !!$('#mt-primelink-dropzone').data('file') || !!$('#mt-primelink-dropzone').data('path');
        valid = hasFile;
        if (!valid) {
          showNextTooltip('Please upload a file before continuing.');
        }
      } else if (source === 'existing') {
        valid = !!$('#mt-primelink-existing-path').val().trim();
        if (!valid) {
          showNextTooltip('Please enter an existing file path before continuing.');
        }
      } else if (source === 'url') {
        valid = !!$('#mt-primelink-url').val().trim();
        if (!valid) {
          showNextTooltip('Please enter a URL before continuing.');
        }
      } else if (source === 'ftp') {
        // For FTP we at least require host; file path can be empty for connection test
        valid = !!$('#mt-primelink-ftp-host').val().trim();
        if (!valid) {
          showNextTooltip('Please configure FTP host (and optionally file path) before continuing.');
        }
      } else if (source === 'dropbox') {
        valid = !!$('#mt-primelink-dropbox-path').val().trim();
        if (!valid) {
          showNextTooltip('Please enter a Dropbox path or link before continuing.');
        }
      } else if (source === 'gdrive') {
        valid = !!$('#mt-primelink-gdrive-file').val().trim();
        if (!valid) {
          showNextTooltip('Please enter a Google Drive file ID or link before continuing.');
        }
      } else if (source === 'onedrive') {
        valid = !!$('#mt-primelink-onedrive-file').val().trim();
        if (!valid) {
          showNextTooltip('Please enter a OneDrive item ID or link before continuing.');
        }
      } else if (source === 'platform') {
        // Platform imports: require at least one connector / configuration (server-side validated),
        // but on client we just ensure user selected this option – already true.
        valid = true;
      }

      if (!valid) {
        // Hard block moving to next step if no file/source set.
        return;
      }
    }

    // Step 5 critical field validation


    try {
      if(!importId){
        const draft = await restPost('/import/create-draft', {});
        importId = draft.import_id;
        setImportIdEverywhere(importId);
      }

      const payload = (step === 5) ? collectMappingState() : getStepData();
      if(step === 5){
        setSaveStatus('saving');
      }

      // Auto-set type for step 1 based on import_type from URL
      if(step === 1){
        const url = new URL(window.location.href);
        const importType = url.searchParams.get('import_type') || '';
        if(importType === 'orders'){
          payload.type = 'order';
        } else if(importType === 'customers'){
          payload.type = 'customer'; // Normalize: customers -> customer
        } else if(importType === 'coupons'){
          payload.type = 'coupon'; // Normalize: coupons -> coupon
        } else if(importType === 'products' || !importType){
          payload.type = 'product';
        } else {
          payload.type = importType;
        }
      }

      await restPost('/import/save-step', {
        import_id: importId,
        step: step,
        data: payload
      });
      if(step === 5){
        setSaveStatus('saved');
      }

      const url = new URL(window.location.href);
      url.searchParams.set('step', nextStep);
      url.searchParams.set('import_id', importId);
      window.location.href = url.toString();

    } catch(err){
      if(step === 5){
        setSaveStatus('error', err.json?.message || 'Save failed', true);
      }
      alert('REST error: ' + (err.json?.message || err.status || 'unknown'));
    }
  });

  // Back button (wizard) AJAX navigation
  $(document).on('click', '#mt-primelink-back', function(e){
    const prevStep = parseInt($(this).data('prev'), 10) || (getStep() - 1);
    if(prevStep > 0){
      const url = new URL($(this).attr('href'), window.location.href);
      url.searchParams.set('step', prevStep);
      // allow normal navigation; fallback set href explicitly
      window.location.href = url.toString();
    }
  });

  // -----------------------------
// Step 2 Source panels + upload (REST)
// -----------------------------
$(document).on('change','input[name="source"]', async function(){
  const val = $(this).val();
  $('.mt-panel').hide();
  $('.mt-panel[data-panel="'+val+'"]').show();
  
  // Platform connector specific handling
  if(val === 'platform'){
    await initPlatformConnector();
    // Load settings to get saved credentials (even if mt_primelinkSettings already exists but has no platform_connectors)
    try {
      if(!window.mt_primelinkSettings || !window.mt_primelinkSettings.platform_connectors || Array.isArray(window.mt_primelinkSettings.platform_connectors)){
        const settingsRes = await restGet('/settings?ts=' + Date.now());
        if(!window.mt_primelinkSettings) window.mt_primelinkSettings = {};
        let pc = settingsRes.platform_connectors || {};
        if (Array.isArray(pc)) {
          pc = {};
        }
        window.mt_primelinkSettings.platform_connectors = pc;
      }
    } catch(e){
      // Silent fail; user can still enter credentials manually
    }
  }
});

// Existing file helpers
$(document).on('click', '#mt_primelink-existing-browse', function(){
  const $input = $('#mt-primelink-existing-path');
  if(!$input.val()){
    $input.val('/wp-content/uploads/primelink/');
  }
  $input.focus();
  try{
    const el = $input.get(0);
    el.setSelectionRange($input.val().length, $input.val().length);
  }catch(e){}
});

$(document).on('change', '#mt_primelink-existing-recent', function(){
  const val = $(this).val();
  if(!val) return;
  const $input = $('#mt-primelink-existing-path');
  $input.val(val).focus();
  $input.trigger('blur');
});

$(document).on('click', '#mt_primelink-existing-refresh', function(){
  fetchExistingUploads();
});

  // Drag & Drop File Upload
  const dropzone = $('#mt-primelink-dropzone');
  const fileInput = $('#mt-primelink-upload-file');
  const dropzoneContent = $('.mt-primelink-dropzone-content');
  const dropzoneProgress = $('#mt-primelink-dropzone-progress');

  // Click on dropzone to trigger file input
  if (dropzone.length && fileInput.length) {
    dropzone.on('click', function(e) {
      // Don't trigger if clicking on the browse link (it has its own handler)
      if (!$(e.target).closest('.mt-primelink-dropzone-link').length) {
        fileInput.trigger('click');
      }
    });

    // Prevent default drag behaviors
    $(document).on('dragenter', '#mt-primelink-dropzone', function(e) {
      e.preventDefault();
      e.stopPropagation();
    });

    $(document).on('dragover', '#mt-primelink-dropzone', function(e) {
      e.preventDefault();
      e.stopPropagation();
      $(this).addClass('drag-over');
    });

    $(document).on('dragleave', '#mt-primelink-dropzone', function(e) {
      e.preventDefault();
      e.stopPropagation();
      // Only remove class if we're leaving the dropzone, not entering a child element
      if (!$(this).is(e.currentTarget)) {
        return;
      }
      const rect = this.getBoundingClientRect();
      const x = e.clientX;
      const y = e.clientY;
      if (x < rect.left || x >= rect.right || y < rect.top || y >= rect.bottom) {
        $(this).removeClass('drag-over');
      }
    });

    $(document).on('drop', '#mt-primelink-dropzone', function(e) {
      e.preventDefault();
      e.stopPropagation();
      $(this).removeClass('drag-over');

      const files = e.originalEvent.dataTransfer.files;
      if (files.length > 0) {
        handleFileSelection(files[0]);
      }
    });

    // Helper function to validate and handle file selection
    function handleFileSelection(file) {
      if (!file) return;

      // Validate file type
      const validExtensions = ['.csv', '.xml', '.xlsx', '.xls'];
      const fileName = file.name.toLowerCase();
      const isValidFile = validExtensions.some(ext => fileName.endsWith(ext));

      if (!isValidFile) {
        if (window.mtPrimeLinkToast) {
          window.mtPrimeLinkToast.error('Invalid file type. Please select a CSV, XML, XLSX, or XLS file.', 'Invalid File');
        } else {
          alert('Invalid file type. Please select a CSV, XML, XLSX, or XLS file.');
        }
        return;
      }

      // Create a DataTransfer object to set the file in the input
      const dataTransfer = new DataTransfer();
      dataTransfer.items.add(file);
      
      // Set the file in the input (this works in modern browsers)
      fileInput[0].files = dataTransfer.files;
      
      // Trigger change event to use existing AJAX upload logic
      fileInput.trigger('change');
    }
  }

  $(document).on('change', '#mt-primelink-upload-file', function(){
    const file = this.files[0];
    if(!file) return;

    let importId = currentImportId();
    const self = this;
    
    // Create draft if needed (using REST API for this)
    (async function() {
      try {
        if(!importId || importId === 0){
          const draft = await restPost('/import/create-draft', {});
          if (!draft || !draft.import_id) {
            throw { status: 0, json: { message: 'Failed to create draft' } };
          }
          importId = draft.import_id;
          setImportIdEverywhere(importId);
        }

        // Use AJAX for file upload (works with FormData and $_FILES)
        const fd = new FormData();
        fd.append('action', 'mt_primelink_import_handle_source');
        fd.append('nonce', mtPrimeLink.ajaxNonce);
        fd.append('import_id', importId.toString());
        fd.append('source', 'desktop');
        fd.append('file', file);

        // Show progress in dropzone
        const dropzoneContent = $('.mt-primelink-dropzone-content');
        const dropzoneProgress = $('#mt-primelink-dropzone-progress');
        const progressText = $('#mt-primelink-dropzone-progress-text');
        
        if (dropzoneContent.length && dropzoneProgress.length) {
          dropzoneContent.hide();
          dropzoneProgress.show();
          progressText.text('Uploading... 0%');
          $('#mt-primelink-dropzone-progress-fill').css('width', '0%');
        }

        $('#mt-primelink-source-result').show().text('Uploading...');

        $.ajax({
          url: mtPrimeLink.ajaxUrl,
          type: 'POST',
          data: fd,
          processData: false,
          contentType: false,
          xhr: function() {
            const xhr = new window.XMLHttpRequest();
            // Track upload progress
            xhr.upload.addEventListener('progress', function(e) {
              if (e.lengthComputable) {
                const percentComplete = Math.round((e.loaded / e.total) * 100);
                const progressFill = $('#mt-primelink-dropzone-progress-fill');
                const progressText = $('#mt-primelink-dropzone-progress-text');
                if (progressFill.length) {
                  progressFill.css('width', percentComplete + '%');
                }
                if (progressText.length) {
                  progressText.text('Uploading... ' + percentComplete + '%');
                }
              }
            }, false);
            return xhr;
          },
          success: function(response) {
            
            // Reset dropzone UI
            const dropzoneContent = $('.mt-primelink-dropzone-content');
            const dropzoneProgress = $('#mt-primelink-dropzone-progress');
            if (dropzoneContent.length && dropzoneProgress.length) {
              dropzoneProgress.hide();
              dropzoneContent.show();
              $('#mt-primelink-dropzone-progress-fill').css('width', '0%');
            }
            
            if (response.success && response.data && response.data.file) {
              // Mark dropzone as having a valid file so step-2 validation passes
              $('#mt-primelink-dropzone')
                .data('file', response.data.file)
                .data('path', response.data.file.path || '')
                .data('type', response.data.file.type || '');

              $('#mt-primelink-source-result')
                .html('<strong>File stored:</strong> '+escapeHtml(response.data.file.original_name)+' ('+escapeHtml(response.data.file.type)+')');
            } else {
              const errorMsg = response.data?.message || 'Upload failed';
              $('#mt-primelink-source-result').show().text(errorMsg);
            }
          },
          error: function(xhr, status, error) {
            console.error('Upload error:', xhr, status, error);
            
            // Reset dropzone UI on error
            const dropzoneContent = $('.mt-primelink-dropzone-content');
            const dropzoneProgress = $('#mt-primelink-dropzone-progress');
            if (dropzoneContent.length && dropzoneProgress.length) {
              dropzoneProgress.hide();
              dropzoneContent.show();
              $('#mt-primelink-dropzone-progress-fill').css('width', '0%');
            }
            
            let errorMsg = 'Upload failed';
            try {
              const response = JSON.parse(xhr.responseText);
              errorMsg = response.data?.message || errorMsg;
            } catch(e) {}
            $('#mt-primelink-source-result').show().text(errorMsg);
          }
        });

      } catch(err){
        console.error('Draft creation error:', err);
        
        // Reset dropzone UI on error
        const dropzoneContent = $('.mt-primelink-dropzone-content');
        const dropzoneProgress = $('#mt-primelink-dropzone-progress');
        if (dropzoneContent.length && dropzoneProgress.length) {
          dropzoneProgress.hide();
          dropzoneContent.show();
          $('#mt-primelink-dropzone-progress-fill').css('width', '0%');
        }
        
        const errorMsg = err.json?.message || err.json?.error || 'Failed to create draft';
        $('#mt-primelink-source-result').show().text(errorMsg);
      }
    })();
  });

  $(document).on('blur', '#mt-primelink-url', async function(){
    const urlVal = $(this).val();
    if(!urlVal) return;

    let importId = currentImportId();
    try {
      if(!importId){
        const draft = await restPost('/import/create-draft', {});
        importId = draft.import_id;
        setImportIdEverywhere(importId);
      }

      $('#mt-primelink-source-result').show().text('Downloading...');

      // Use AJAX for URL (works better with POST data)
      $.ajax({
        url: mtPrimeLink.ajaxUrl,
        type: 'POST',
        data: {
          action: 'mt_primelink_import_handle_source',
          nonce: mtPrimeLink.ajaxNonce,
          import_id: importId,
          source: 'url',
          url: urlVal
        },
        success: function(response) {
          
          if(response.success && response.data && response.data.file){
            const file = response.data.file;
            if(file.original_name){
              $('#mt-primelink-source-result')
                .html('<span style="color:#0a0;"><strong>File stored:</strong> '+escapeHtml(file.original_name)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
            } else if(file.path){
              const fileName = file.path.split('/').pop() || file.path.split('\\').pop() || 'file';
              $('#mt-primelink-source-result')
                .html('<span style="color:#0a0;"><strong>File stored:</strong> '+escapeHtml(fileName)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
            } else {
              $('#mt-primelink-source-result').html('<span style="color:#0a0;">File stored successfully.</span>');
            }
          } else {
            const errorMsg = response.data?.message || 'Download failed';
            $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
          }
        },
        error: function(xhr, status, error) {
          console.error('URL download error:', xhr, status, error);
          let errorMsg = 'Download failed';
          try {
            const response = JSON.parse(xhr.responseText);
            if(response.data && response.data.message){
              errorMsg = response.data.message;
            }
          } catch(e){}
          $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
        }
      });

    } catch(err){
      $('#mt-primelink-source-result').show().text(err.json?.message || 'Download failed');
    }
  });

  $(document).on('blur', '#mt-primelink-existing-path', async function(){
    const pathVal = $(this).val();
    if(!pathVal) return;

    let importId = currentImportId();
    try {
      if(!importId){
        const draft = await restPost('/import/create-draft', {});
        importId = draft.import_id;
        setImportIdEverywhere(importId);
      }

      $('#mt-primelink-source-result').show().text('Validating file...');

      // Use AJAX for existing file (works better with POST data)
      $.ajax({
        url: mtPrimeLink.ajaxUrl,
        type: 'POST',
        data: {
          action: 'mt_primelink_import_handle_source',
          nonce: mtPrimeLink.ajaxNonce,
          import_id: importId,
          source: 'existing',
          path: pathVal
        },
        success: function(response) {
          
          if(response.success && response.data && response.data.file){
            const file = response.data.file;
            if(file.original_name){
              $('#mt-primelink-source-result')
                .html('<span style="color:#0a0;"><strong>File loaded:</strong> '+escapeHtml(file.original_name)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
            } else if(file.path){
              const fileName = file.path.split('/').pop() || file.path.split('\\').pop() || 'file';
              $('#mt-primelink-source-result')
                .html('<span style="color:#0a0;"><strong>File loaded:</strong> '+escapeHtml(fileName)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
            } else {
              $('#mt-primelink-source-result').html('<span style="color:#0a0;">File loaded successfully.</span>');
            }
            try {
              addExistingRecent(pathVal);
            } catch(e){}
          } else {
            const errorMsg = response.data?.message || 'Invalid file';
            $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
          }
        },
        error: function(xhr, status, error) {
          console.error('Existing file error:', xhr, status, error);
          let errorMsg = 'Invalid file';
          try {
            const response = JSON.parse(xhr.responseText);
            if(response.data && response.data.message){
              errorMsg = response.data.message;
            }
          } catch(e){}
          $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
        }
      });

    } catch(err){
      $('#mt-primelink-source-result').show().text(err.json?.message || 'Invalid file');
    }
  });

  async function fetchDropboxFile(pathVal){
    if(!pathVal) return;
    let importId = currentImportId();
    try {
      if(!importId){
        const draft = await restPost('/import/create-draft', {});
        importId = draft.import_id;
        setImportIdEverywhere(importId);
      }

      $('#mt-primelink-source-result').show().text('Connecting to Dropbox...');

      // Use AJAX for Dropbox (works better with POST data)
      $.ajax({
        url: mtPrimeLink.ajaxUrl,
        type: 'POST',
        data: {
          action: 'mt_primelink_import_handle_source',
          nonce: mtPrimeLink.ajaxNonce,
          import_id: importId,
          source: 'dropbox',
          path: pathVal
        },
        success: function(response) {
          
          if(response.success && response.data && response.data.file){
            const file = response.data.file;
            if(file.original_name){
              $('#mt-primelink-source-result')
                .html('<span style="color:#0a0;"><strong>File loaded:</strong> '+escapeHtml(file.original_name)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
            } else if(file.path){
              const fileName = file.path.split('/').pop() || file.path.split('\\').pop() || 'file';
              $('#mt-primelink-source-result')
                .html('<span style="color:#0a0;"><strong>File loaded:</strong> '+escapeHtml(fileName)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
            } else {
              $('#mt-primelink-source-result').html('<span style="color:#0a0;">File loaded successfully.</span>');
            }
          } else {
            const errorMsg = response.data?.message || 'Dropbox download failed';
            $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
          }
        },
        error: function(xhr, status, error) {
          console.error('Dropbox fetch error:', xhr, status, error);
          let errorMsg = 'Dropbox download failed';
          try {
            const response = JSON.parse(xhr.responseText);
            if(response.data && response.data.message){
              errorMsg = response.data.message;
            }
          } catch(e){}
          $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
        }
      });

    } catch(err){
      $('#mt-primelink-source-result').show().text(err.json?.message || 'Dropbox download failed');
    }
  }

  $(document).on('click', '#mt_primelink-dropbox-fetch', function(){
    const val = $('#mt_primelink-dropbox-path').val();
    fetchDropboxFile(val);
  });

  $(document).on('blur', '#mt_primelink-dropbox-path', function(){
    const val = $(this).val();
    fetchDropboxFile(val);
  });

  async function listDropbox(pathVal){
    $('#mt_primelink-dropbox-files').html('<em>Listing files...</em>');
    
    // Use AJAX for Dropbox list (works better with POST data)
    $.ajax({
      url: mtPrimeLink.ajaxUrl,
      type: 'POST',
      data: {
        action: 'mt_primelink_dropbox_list',
        nonce: mtPrimeLink.ajaxNonce,
        path: pathVal || ''
      },
      success: function(response) {
        
        if(response.success && response.data && response.data.files){
          const files = response.data.files || [];
          if(!files.length){
            $('#mt_primelink-dropbox-files').html('<em>No files found in this folder.</em>');
            return;
          }
          let html = '<ul class="mt_primelink-dropbox-listing">';
          files.forEach(f => {
            html += '<li><a href="#" data-path="'+escapeHtml(f.path)+'">'+escapeHtml(f.name)+'</a> <small>'+escapeHtml(f.size_human||'')+'</small></li>';
          });
          html += '</ul>';
          $('#mt_primelink-dropbox-files').html(html);
        } else {
          const errorMsg = response.data?.message || 'Failed to list files';
          $('#mt_primelink-dropbox-files').html('<em>'+escapeHtml(errorMsg)+'</em>');
        }
      },
      error: function(xhr, status, error) {
        console.error('Dropbox list error:', xhr, status, error);
        let errorMsg = 'Failed to list files';
        try {
          const response = JSON.parse(xhr.responseText);
          if(response.data && response.data.message){
            errorMsg = response.data.message;
          }
        } catch(e){}
        $('#mt_primelink-dropbox-files').html('<em>'+escapeHtml(errorMsg)+'</em>');
      }
    });
  }

  $(document).on('click', '#mt_primelink-dropbox-list', function(){
    const val = $('#mt_primelink-dropbox-path').val();
    listDropbox(val);
  });

  $(document).on('click', '.mt_primelink-dropbox-listing a', function(e){
    e.preventDefault();
    const p = $(this).data('path');
    if(p){
      $('#mt_primelink-dropbox-path').val(p);
      fetchDropboxFile(p);
    }
  });

  async function testFtpConnection(){
    const protocol = $('#mt_primelink-ftp-protocol').val() || 'ftp';
    const host = $('#mt_primelink-ftp-host').val() || '';
    const portVal = $('#mt_primelink-ftp-port').val();
    const port = portVal ? parseInt(portVal, 10) : 0;
    const user = $('#mt_primelink-ftp-user').val() || '';
    const pass = $('#mt_primelink-ftp-pass').val() || '';
    const root = $('#mt_primelink-ftp-root').val() || '';
    const path = $('#mt_primelink-ftp-file').val() || '';
    const passive = $('#mt_primelink-ftp-passive').is(':checked');

    if(!host || !user || !pass){
      $('#mt-primelink-source-result').show().html('<span style="color:#f00;">Please fill host, username, and password to test connection.</span>');
      return;
    }

    let importId = currentImportId();
    
    try {
      if(!importId){
        const draft = await restPost('/import/create-draft', {});
        importId = draft.import_id;
        setImportIdEverywhere(importId);
      }

      $('#mt-primelink-source-result').show().text('Testing FTP connection...');

      $.ajax({
        url: mtPrimeLink.ajaxUrl,
        type: 'POST',
        data: {
          action: 'mt_primelink_import_handle_source',
          nonce: mtPrimeLink.ajaxNonce,
          import_id: importId,
          source: 'ftp',
          protocol: protocol,
          host: host,
          port: port,
          user: user,
          pass: pass,
          root: root,
          path: path || '',
          passive: passive ? 1 : 0,
          test_only: 1
        },
        success: function(response) {
          if(response.success){
            const message = response.data?.message || response.data?.data?.message || 'Connection successful!';
            $('#mt-primelink-source-result').html('<span style="color:#46b450;">✓ ' + escapeHtml(message) + '</span>');
          } else {
            const errorMsg = response.data?.message || response.message || 'Unknown error';
            $('#mt-primelink-source-result').html('<span style="color:#f00;">✗ Connection failed: ' + escapeHtml(errorMsg) + '</span>');
          }
        },
        error: function(xhr, status, error){
          console.error('FTP test error:', xhr, status, error);
          let errorMsg = 'FTP/SFTP connection test failed';
          try {
            const response = JSON.parse(xhr.responseText);
            errorMsg = response.data?.message || errorMsg;
          } catch(e) {}
          $('#mt-primelink-source-result').html('<span style="color:#f00;">✗ ' + escapeHtml(errorMsg) + '</span>');
        }
      });
    } catch(err){
      console.error('FTP test error:', err);
      const errorMsg = err.json?.message || err.json?.error || 'Failed to test connection';
      $('#mt-primelink-source-result').show().html('<span style="color:#f00;">✗ ' + escapeHtml(errorMsg) + '</span>');
    }
  }

  async function fetchFtpFile(){
    const protocol = $('#mt_primelink-ftp-protocol').val() || 'ftp';
    const host = $('#mt_primelink-ftp-host').val() || '';
    const portVal = $('#mt_primelink-ftp-port').val();
    const port = portVal ? parseInt(portVal, 10) : 0;
    const user = $('#mt_primelink-ftp-user').val() || '';
    const pass = $('#mt_primelink-ftp-pass').val() || '';
    const root = $('#mt_primelink-ftp-root').val() || '';
    const path = $('#mt_primelink-ftp-file').val() || '';
    const passive = $('#mt_primelink-ftp-passive').is(':checked');

    if(!host || !user || !pass){
      $('#mt-primelink-source-result').show().html('<span style="color:#f00;">Please fill host, username, and password.</span>');
      return;
    }

    if(!path){
      $('#mt-primelink-source-result').show().html('<span style="color:#f00;">Please specify file path to download.</span>');
      return;
    }

    let importId = currentImportId();
    
    // Create draft if needed (using REST API for this)
    (async function() {
      try {
        if(!importId){
          const draft = await restPost('/import/create-draft', {});
          importId = draft.import_id;
          setImportIdEverywhere(importId);
        }

        $('#mt-primelink-source-result').show().html('<span>Connecting to FTP/SFTP...</span>');

        // Use AJAX for FTP (works better with POST data)
        $.ajax({
          url: mtPrimeLink.ajaxUrl,
          type: 'POST',
          data: {
            action: 'mt_primelink_import_handle_source',
            nonce: mtPrimeLink.ajaxNonce,
            import_id: importId,
            source: 'ftp',
            protocol: protocol,
            host: host,
            port: port,
            user: user,
            pass: pass,
            root: root,
            path: path,
            passive: passive ? 1 : 0
          },
          success: function(response) {
            
            if(response.success && response.data && response.data.file){
              const file = response.data.file;
              if(file.original_name){
                $('#mt-primelink-source-result')
                  .html('<span style="color:#0a0;"><strong>File loaded:</strong> '+escapeHtml(file.original_name)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
              } else if(file.path){
                const fileName = file.path.split('/').pop() || file.path.split('\\').pop() || 'file';
                $('#mt-primelink-source-result')
                  .html('<span style="color:#0a0;"><strong>File loaded:</strong> '+escapeHtml(fileName)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
              } else {
                $('#mt-primelink-source-result').html('<span style="color:#0a0;">File loaded successfully.</span>');
              }
            } else {
              const errorMsg = response.data?.message || 'FTP/SFTP download failed';
              $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
            }
          },
          error: function(xhr, status, error) {
            console.error('FTP fetch error:', xhr, status, error);
            let errorMsg = 'FTP/SFTP download failed';
            try {
              const response = JSON.parse(xhr.responseText);
              errorMsg = response.data?.message || errorMsg;
            } catch(e) {}
            $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
          }
        });

      } catch(err){
        console.error('Draft creation error:', err);
        const errorMsg = err.json?.message || err.json?.error || 'Failed to create draft';
        $('#mt-primelink-source-result').show().html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
      }
    })();
  }

  $(document).on('click', '#mt_primelink-ftp-test', function(){
    testFtpConnection();
  });

  $(document).on('click', '#mt_primelink-ftp-fetch', function(){
    fetchFtpFile();
  });

  async function fetchGdriveFile(){
    const file = $('#mt_primelink-gdrive-file').val();
    if(!file){
      $('#mt-primelink-source-result').show().text('Please add a Google Drive file ID or link.');
      return;
    }
    let importId = currentImportId();
    try {
      if(!importId){
        const draft = await restPost('/import/create-draft', {});
        importId = draft.import_id;
        setImportIdEverywhere(importId);
      }

      $('#mt-primelink-source-result').show().text('Fetching from Google Drive...');

      // Use AJAX for Google Drive (works better with POST data)
      $.ajax({
        url: mtPrimeLink.ajaxUrl,
        type: 'POST',
        data: {
          action: 'mt_primelink_import_handle_source',
          nonce: mtPrimeLink.ajaxNonce,
          import_id: importId,
          source: 'gdrive',
          path: file
        },
        success: function(response) {
          
          if(response.success && response.data && response.data.file){
            const file = response.data.file;
            if(file.original_name){
              $('#mt-primelink-source-result')
                .html('<span style="color:#0a0;"><strong>File loaded:</strong> '+escapeHtml(file.original_name)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
            } else if(file.path){
              const fileName = file.path.split('/').pop() || file.path.split('\\').pop() || 'file';
              $('#mt-primelink-source-result')
                .html('<span style="color:#0a0;"><strong>File loaded:</strong> '+escapeHtml(fileName)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
            } else {
              $('#mt-primelink-source-result').html('<span style="color:#0a0;">File loaded successfully.</span>');
            }
          } else {
            const errorMsg = response.data?.message || 'Google Drive download failed';
            $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
          }
        },
        error: function(xhr, status, error) {
          console.error('Google Drive fetch error:', xhr, status, error);
          let errorMsg = 'Google Drive download failed';
          try {
            const response = JSON.parse(xhr.responseText);
            if(response.data && response.data.message){
              errorMsg = response.data.message;
            }
          } catch(e){}
          $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
        }
      });

    } catch(err){
      $('#mt-primelink-source-result').show().text(err.json?.message || 'Google Drive download failed');
    }
  }

  $(document).on('click', '#mt_primelink-gdrive-fetch', function(){
    fetchGdriveFile();
  });

  async function fetchOneDriveFile(){
    const file = $('#mt_primelink-onedrive-file').val();
    if(!file){
      $('#mt-primelink-source-result').show().text('Please add a OneDrive item ID or link.');
      return;
    }
    let importId = currentImportId();
    try {
      if(!importId){
        const draft = await restPost('/import/create-draft', {});
        importId = draft.import_id;
        setImportIdEverywhere(importId);
      }

      $('#mt-primelink-source-result').show().text('Fetching from OneDrive...');

      // Use AJAX for OneDrive (works better with POST data)
      $.ajax({
        url: mtPrimeLink.ajaxUrl,
        type: 'POST',
        data: {
          action: 'mt_primelink_import_handle_source',
          nonce: mtPrimeLink.ajaxNonce,
          import_id: importId,
          source: 'onedrive',
          path: file
        },
        success: function(response) {
          
          if(response.success && response.data && response.data.file){
            const file = response.data.file;
            if(file.original_name){
              $('#mt-primelink-source-result')
                .html('<span style="color:#0a0;"><strong>File loaded:</strong> '+escapeHtml(file.original_name)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
            } else if(file.path){
              const fileName = file.path.split('/').pop() || file.path.split('\\').pop() || 'file';
              $('#mt-primelink-source-result')
                .html('<span style="color:#0a0;"><strong>File loaded:</strong> '+escapeHtml(fileName)+' ('+escapeHtml(file.type || 'unknown')+')</span>');
            } else {
              $('#mt-primelink-source-result').html('<span style="color:#0a0;">File loaded successfully.</span>');
            }
          } else {
            const errorMsg = response.data?.message || 'OneDrive download failed';
            $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
          }
        },
        error: function(xhr, status, error) {
          console.error('OneDrive fetch error:', xhr, status, error);
          let errorMsg = 'OneDrive download failed';
          try {
            const response = JSON.parse(xhr.responseText);
            if(response.data && response.data.message){
              errorMsg = response.data.message;
            }
          } catch(e){}
          $('#mt-primelink-source-result').html('<span style="color:#f00;">'+escapeHtml(errorMsg)+'</span>');
        }
      });

    } catch(err){
      $('#mt-primelink-source-result').show().text(err.json?.message || 'OneDrive download failed');
    }
  }

  $(document).on('click', '#mt_primelink-onedrive-fetch', function(){
    fetchOneDriveFile();
  });

  $(document).on('click', '.mt_primelink-import-back', function(){
    const url = $(this).data('url');
    if(url){
      window.location.href = url;
    } else {
      history.back();
    }
  });

  $(document).on('click', '#mt_primelink-schedule-import', async function(){
    const importId = currentImportId();
    try{
      const res = await restPost('/import/schedule', { import_id: importId });
      const when = res.run_at || 'scheduled';
      const recur = res.recurring ? (' ('+res.recurring+')') : '';
      if (window.mtPrimeLinkToast) {
        window.mtPrimeLinkToast.success('Import scheduled at ' + when + recur + '. You can manage it in Manage Imports.', 'Import Scheduled');
      } else {
      alert('Import scheduled at ' + when + recur + '. You can manage it in Manage Imports.');
      }
      window.location.href = mtPrimeLink.manageImportsUrl || (window.location.origin + '/wp-admin/admin.php?page=mt-primelink-manage-import');
    }catch(e){
      if (window.mtPrimeLinkToast) {
        window.mtPrimeLinkToast.error(e.json?.message || 'Failed to schedule import.', 'Scheduling Failed');
      } else {
      alert(e.json?.message || 'Failed to schedule import.');
      }
    }
  });

  // -----------------------------
// Step 4 Preview (REST) -> VERTICAL + ROW NAVIGATOR
// -----------------------------
let mt_primelinkPreviewIndex = 0;
let mt_primelinkPreviewTotal = 0;
let mt_primelinkPreviewHeaders = [];
let mt_primelinkPreviewRows = [];
let mt_primelinkPreviewPage = 1;
let mt_primelinkPreviewPages = 1;
let mt_primelinkPreviewPerPage = 20;
let mt_primelinkMapFields = [];
let mt_primelinkPrevFields = [];
let mt_primelinkCurrentMapIndex = 0;
let mt_primelinkSelectedProductType = 'simple';
let mt_primelinkStep5SaveTimer = null;
let mt_primelinkStep5LastSaveFailed = false;

function renderAliasRow(target, aliases){
  target = target || '';
  aliases = aliases || '';
  return ''
    + '<div class="mt_primelink-alias-row">'
    + '  <input type="text" class="mt_primelink-alias-target" placeholder="Target (e.g. post_title)" value="'+escapeHtml(target)+'" />'
    + '  <input type="text" class="mt_primelink-alias-values" placeholder="Comma separated synonyms" value="'+escapeHtml(aliases)+'" />'
    + '  <button type="button" class="button-link-delete mt_primelink-alias-remove">Remove</button>'
    + '</div>';
}

function filterFileFields(){
  const q = ($('#mt_primelink-field-search').val() || '').toLowerCase().trim();
  // Handle both import and export file fields (same class now)
  $('.mt_primelink-file-field').each(function(){
    const $field = $(this);
    const fieldKey = ($field.data('field') || '').toString().toLowerCase();
    const fieldName = ($field.find('.mt_primelink-file-field__name').text() || '').toLowerCase();
    const searchText = fieldKey + ' ' + fieldName;
    const visible = !q || searchText.indexOf(q) !== -1;
    $field.toggleClass('mt_primelink-field-hidden', !visible);
  });
}

function filterTargetSlots(){
  const q = ($('#mt_primelink-target-search').val() || '').toLowerCase().trim();
  $('.mt_primelink-map-slot').each(function(){
    const name = ($(this).find('.mt_primelink-map-label__text').text() || '').toLowerCase();
    const visible = !q || name.indexOf(q) !== -1;
    $(this).toggleClass('mt_primelink-slot-hidden', !visible);
  });
}

function markUnmappedSlots(){
  let unmapped = 0;
  $('.mt_primelink-map-slot').each(function(){
    const hasSource = !!($(this).find('.mt_primelink-map-input').val() || '').trim();
    $(this).toggleClass('unmapped', !hasSource);
    if(!hasSource){ unmapped++; }
  });
  const $pill = $('#mt_primelink-unmapped-count');
  if($pill.length){
    if(unmapped > 0){
      $pill.text(unmapped + ' unmapped');
      $pill.show();
    } else {
      $pill.hide();
    }
  }
  renderRequiredChecklist();
}

function autoMapSuggestions(){
  const sources = mt_primelinkMapFields || [];
  if(!sources.length){
    showToastOrAlert('warning', 'No source fields detected yet.', 'Mapping');
    return;
  }

  const norm = s => (s || '').toString().toLowerCase().replace(/[^a-z0-9]+/g, '');

  // Aliases cover multiple languages/variations for targets
  const targetAliases = {
    post_title:   ['title','name','titlu','titel','productname','produktname'],
    post_content: ['description','descriere','beschreibung','desc','content','beschreibunglang','longdescription'],
    post_excerpt: ['shortdescription','short_desc','kurzbeschreibung','descriere scurta','excerpt'],
    sku:          ['sku','cod','code','artikelnummer','artnr','productcode'],
    price:        ['price','pret','preis','cost','amount','valor','betrag'],
    regular_price:['regularprice','pretstandard','listenpreis','preisregular'],
    sale_price:   ['saleprice','pretpromo','angebotspreis','discountprice'],
    stock:        ['stock','stoc','lagerbestand','qty','quantity','cantitate'],
    image:        ['image','imagine','bild','photo','mainimage'],
    images:       ['images','imagesimage','image','imagine','bilder','photos','gallery','galerie','imagini'],
    gallery:      ['gallery','galerie','bilder','imagini','images']
  };
  // Merge custom aliases
  $('.mt_primelink-alias-row').each(function(){
    const target = ($(this).find('.mt_primelink-alias-target').val() || '').trim();
    const vals = ($(this).find('.mt_primelink-alias-values').val() || '').split(',').map(v=>v.trim()).filter(Boolean);
    if(!target || !vals.length) return;
    if(!targetAliases[target]) targetAliases[target] = [];
    targetAliases[target] = targetAliases[target].concat(vals.map(v=>norm(v)));
  });

  const normalizedSources = sources.map(s => ({raw:s, n:norm(s)}));

  function similarity(a,b){
    // Levenshtein distance normalized
    const la = a.length, lb = b.length;
    if(!la || !lb) return 0;
    const dp = Array.from({length: la+1}, () => new Array(lb+1).fill(0));
    for(let i=0;i<=la;i++) dp[i][0]=i;
    for(let j=0;j<=lb;j++) dp[0][j]=j;
    for(let i=1;i<=la;i++){
      for(let j=1;j<=lb;j++){
        const cost = a[i-1] === b[j-1] ? 0 : 1;
        dp[i][j] = Math.min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+cost);
      }
    }
    const dist = dp[la][lb];
    return 1 - (dist / Math.max(la, lb));
  }

  function findBestMatch(target){
    const nTarget = norm(target);
    let best = { score: 0, source: null };

    // Special handling for images - prefer images.image[] if available
    if (target === 'images') {
      // First try to find images.image[] field
      const imagesArrayField = sources.find(s => s === 'images.image[]' || s.indexOf('images.image[]') === 0);
      if (imagesArrayField) {
        return { score: 1, source: imagesArrayField };
      }
      // Then try images field
      const imagesField = sources.find(s => s === 'images');
      if (imagesField) {
        return { score: 0.95, source: imagesField };
      }
      // Then try any images.image.* field
      const imageIndexedFields = sources.filter(s => s.indexOf('images.image.') === 0);
      if (imageIndexedFields.length > 0) {
        // Use images.image[] as the source (will be collected automatically)
        return { score: 0.9, source: 'images.image[]' };
      }
    }

    normalizedSources.forEach(({raw,n}) => {
      // Exact match first
      if(n === nTarget && best.score < 1){
        best = { score: 1, source: raw };
        return;
      }
    });
    if(best.source) return best;

    // Alias-based
    const aliases = targetAliases[target] || [];
    normalizedSources.forEach(({raw,n}) => {
      if(aliases.includes(n)){
        best = { score: 0.99, source: raw };
      }
    });
    if(best.source) return best;

    // Fuzzy match
    normalizedSources.forEach(({raw,n}) => {
      const score = similarity(n, nTarget);
      if(score > best.score){
        best = { score, source: raw };
      }
    });
    if(best.score >= 0.65){
      return best;
    }
    return { score:0, source:null };
  }

  let mappedCount = 0;
  $('.mt_primelink-map-slot').each(function(){
    const $slot = $(this);
    const target = $slot.data('target') || '';
    const $input = $slot.find('.mt_primelink-map-input');
    if(($input.val() || '').trim()){
      return; // already mapped
    }

    const match = findBestMatch(target);
    if(match.source){
      $slot.find('.mt-map-slot__drop').html(buildChip(match.source));
      $input.val(match.source);
      setSlotBadge($slot, 'auto');
      $slot.find('.mt_primelink-map-edit').prop('disabled', false).addClass('is-visible');
      mappedCount++;
    }
  });

  if(mappedCount){
    saveStep5Mapping(true);
    markUnmappedSlots();
    loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
    showToastOrAlert('success', 'Auto-map applied to ' + mappedCount + ' slots.', 'Auto-Map Applied');
  } else {
    showToastOrAlert('info', 'No auto-map matches found.', 'Auto-Map');
  }
}

function renderVerticalPreview($preview){
  const headers = mt_primelinkPreviewHeaders;
  const rows = mt_primelinkPreviewRows;
  const totalPage = rows.length;
  const totalAll = mt_primelinkPreviewTotal;

  if (!headers.length || totalPage < 1) {
    $preview.html('<div class="mt-empty">No preview data.</div>');
    return;
  }

  if (mt_primelinkPreviewIndex < 0) mt_primelinkPreviewIndex = 0;
  if (mt_primelinkPreviewIndex > totalPage - 1) mt_primelinkPreviewIndex = totalPage - 1;

  const row = rows[mt_primelinkPreviewIndex] || [];
  const absoluteIndex = ((mt_primelinkPreviewPage - 1) * mt_primelinkPreviewPerPage) + mt_primelinkPreviewIndex + 1;

  let html = '';
  html += '<div class="mt-preview-meta"><strong>Type:</strong> ' + escapeHtml($preview.data('type') || '') + '</div>';

  // Navigator
  html += '<div class="mt-preview-nav">';
  html += '  <button type="button" class="button mt-preview-prev" ' + (mt_primelinkPreviewIndex <= 0 ? 'disabled' : '') + '>&lt; Prev</button>';
  html += '  <span class="mt-preview-counter">Row ' + absoluteIndex + ' / ' + totalAll + '</span>';
  html += '  <button type="button" class="button button-primary mt-preview-next" ' + (mt_primelinkPreviewIndex >= totalPage - 1 ? 'disabled' : '') + '>Next &gt;</button>';
  html += '</div>';

  // Vertical table
  html += '<div class="mt-preview-vertical-wrap">';
  html += '<table class="mt-preview-vertical">';
  html += '<thead><tr><th>Field</th><th>Value</th></tr></thead><tbody>';

  headers.forEach((field, i) => {
    // Ensure field is a string
    const fieldName = (field !== null && field !== undefined) ? String(field) : '';
    if (!fieldName) return; // Skip invalid fields
    
    // Rows are now indexed arrays (converted from associative arrays in PHP)
    // Values are in the same order as headers
    let value = (row[i] !== undefined && row[i] !== null) ? String(row[i]) : '';
    
    // Special handling for images fields - show as image gallery
    if (fieldName.indexOf('images.image') === 0 || fieldName === 'images' || fieldName === 'images.image[]') {
      // Check if there are multiple image fields (images.image.0, images.image.1, etc.)
      const imageUrls = [];
      if (fieldName === 'images' || fieldName === 'images.image[]') {
        // Try to collect all images.image.* fields
        let idx = 0;
        const fieldIndex = headers.indexOf('images.image.' + idx);
        while (fieldIndex >= 0 || idx === 0) {
          const imgField = 'images.image.' + idx;
          const imgIndex = headers.indexOf(imgField);
          if (imgIndex >= 0 && row[imgIndex]) {
            const imgUrl = String(row[imgIndex]).trim();
            if (imgUrl) imageUrls.push(imgUrl);
          }
          idx++;
          if (idx > 20) break; // Safety limit
          if (headers.indexOf('images.image.' + idx) < 0 && idx > 0) break;
        }
        // If no indexed fields found, use the main field value
        if (imageUrls.length === 0 && value) {
          // Split by comma if it's a comma-separated string
          const urls = value.split(',').map(u => u.trim()).filter(u => u);
          imageUrls.push(...urls);
        }
      } else if (value) {
        // Single image field
        imageUrls.push(value);
      }
      
      // Render images as gallery
      if (imageUrls.length > 0) {
        let imgHtml = '<div class="mt_primelink-preview-images" style="display:flex;flex-wrap:wrap;gap:8px;margin-top:4px;">';
        imageUrls.forEach(url => {
          const cleanUrl = url.trim();
          if (cleanUrl) {
            imgHtml += '<div class="mt_primelink-preview-image" style="position:relative;width:80px;height:80px;border:1px solid rgba(255,255,255,0.2);border-radius:4px;overflow:hidden;background:#f0f0f0;">';
            imgHtml += '<img src="' + escapeHtml(cleanUrl) + '" style="width:100%;height:100%;object-fit:cover;" onerror="this.style.display=\'none\';this.parentElement.innerHTML=\'<div style=\\\'padding:8px;text-align:center;font-size:10px;color:#999\\\'>Image<br/>Error</div>\';" />';
            imgHtml += '</div>';
          }
        });
        imgHtml += '</div>';
        if (imageUrls.length > 1) {
          imgHtml += '<small class="muted" style="display:block;margin-top:4px;">' + imageUrls.length + ' images</small>';
        }
        value = imgHtml;
      } else {
        value = '<span class="muted">No images</span>';
      }
    }
    
    html += '<tr>';
    html += '<td class="mt-preview-field">' + escapeHtml(fieldName) + '</td>';
    html += '<td class="mt-preview-value">' + value + '</td>';
    html += '</tr>';
  });

  html += '</tbody></table></div>';

  $preview.html(html);
}

function updatePreviewPaginationUI(){
  $('#mt_primelink-preview-page-label').text(mt_primelinkPreviewPage + ' / ' + mt_primelinkPreviewPages);
  $('#mt_primelink-preview-page-prev').prop('disabled', mt_primelinkPreviewPage <= 1);
  $('#mt_primelink-preview-page-next').prop('disabled', mt_primelinkPreviewPage >= mt_primelinkPreviewPages);
}

async function loadPreview(){
  const $preview = $('#mt-primelink-preview');
  if(!$preview.length) return;

  const importId = parseInt($preview.data('import-id'), 10) || currentImportId();
  const xpathVal = $('#mt-primelink-xpath').val() || '';
  mt_primelinkPreviewPerPage = parseInt($('#mt_primelink-preview-limit').val(), 10) || 20;
  if(mt_primelinkPreviewPerPage < 1) mt_primelinkPreviewPerPage = 1;

  try {
    const res = await restPost('/import/preview', {
      import_id: importId,
      xpath: xpathVal,
      filters: collectFilterRowsData(),
      page: mt_primelinkPreviewPage,
      per_page: mt_primelinkPreviewPerPage
    });

    // Handle both direct preview response and nested preview structure
    const p = res.preview || res || {};
    const headers = p.headers || [];
    const rows = p.rows || [];
    

    mt_primelinkPreviewHeaders = headers;
    mt_primelinkPreviewRows = rows;
    mt_primelinkPreviewTotal = p.total_filtered || p.total || rows.length || 0;
    mt_primelinkPreviewPages = Math.max(1, Math.ceil(mt_primelinkPreviewTotal / mt_primelinkPreviewPerPage));
    
    // Check if preview_index is in URL (for navigation from anomalies modal)
    const urlParams = new URLSearchParams(window.location.search);
    const previewIndexParam = urlParams.get('preview_index');
    if (previewIndexParam !== null && !isNaN(previewIndexParam)) {
      const targetIndex = parseInt(previewIndexParam, 10);
      // Calculate which page this index is on (0-based index)
      const targetPage = Math.floor(targetIndex / mt_primelinkPreviewPerPage) + 1;
      if (targetPage <= mt_primelinkPreviewPages) {
        mt_primelinkPreviewPage = targetPage;
        mt_primelinkPreviewIndex = targetIndex % mt_primelinkPreviewPerPage;
        // Remove the parameter from URL to avoid reapplying on refresh
        urlParams.delete('preview_index');
        const newUrl = window.location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : '') + window.location.hash;
        window.history.replaceState({}, '', newUrl);
      } else {
        mt_primelinkPreviewIndex = 0;
      }
    } else {
      mt_primelinkPreviewIndex = 0;
    }
    
    if(mt_primelinkPreviewPage > mt_primelinkPreviewPages){
      mt_primelinkPreviewPage = mt_primelinkPreviewPages;
      return loadPreview();
    }

    $preview.data('type', res.type || '');

    if (!mt_primelinkPreviewTotal) {
      $preview.html('<div class="mt-empty">No rows found.</div>');
      updatePreviewPaginationUI();
      return;
    }

    renderVerticalPreview($preview);
    updatePreviewPaginationUI();

    // If XML, try to fetch roots/tags for filter builder
    if((res.type || '').toLowerCase() === 'xml'){
      fetchXmlRoots(importId);
    } else {
      $('#mt_primelink-xml-tags').empty();
    }

  } catch(err){
    let errMsg = 'Unknown error';
    if(err && typeof err === 'object'){
      if(err.json && err.json.message){
        errMsg = err.json.message;
      } else if(err.json && typeof err.json === 'object'){
        errMsg = JSON.stringify(err.json, null, 2);
      } else if(err.message){
        errMsg = err.message;
      } else if(err.status){
        errMsg = `HTTP ${err.status}: ${err.json ? JSON.stringify(err.json) : 'Request failed'}`;
      }
    } else if(err){
      errMsg = String(err);
    }
    $preview.html('Preview failed.<br><pre>'+escapeHtml(errMsg)+'</pre>');
    console.error('Preview error:', err);
  }
}

async function fetchXmlRoots(importId){
  const $root = $('#mt_primelink-xml-root');
  if(!$root.length) return;
  try{
    const res = await restPost('/import/xml-roots', { import_id: importId });
    const roots = res.roots || [];
    let html = '<option value=\"\">Select root...</option>';
    roots.slice(0,50).forEach(r=>{
      const path = r.path || '';
      const label = path + (r.count ? ' ('+r.count+')' : '');
      html += '<option value=\"'+escapeHtml(path)+'\">'+escapeHtml(label)+'</option>';
    });
    $root.html(html);
    // auto-select if xpath matches
    const current = $('#mt-primelink-xpath').val();
    if(current){
      $root.val(current);
    }
  } catch(e){
    // ignore
  }
}

async function fetchXmlTags(importId, root){
  const $tags = $('#mt_primelink-xml-tags');
  if(!$tags.length || !root) { $tags.empty(); return; }
  try{
    const res = await restPost('/import/xml-tags', { import_id: importId, root });
    const tags = res.tags || [];
    if(!tags.length){
      $tags.html('<div class=\"mt_primelink-empty\">No tags detected under this root.</div>');
      return;
    }
    let html = '<div class=\"mt_primelink-summary-subtitle\">'+escapeHtml('Available tags')+'</div>';
    html += '<ul class=\"mt_primelink-summary-list mt_primelink-xml-tags-list\">';
    tags.slice(0,50).forEach(t=>{
      html += '<li>';
      const label = (t.tag || '') + (t.count ? ' ('+t.count+')' : '');
      html += '<button type=\"button\" class=\"button mt_primelink-xml-tag-btn\" data-tag=\"'+escapeHtml(t.tag || '')+'\">'+escapeHtml(label)+'</button>';
      html += '</li>';
    });
    html += '</ul>';
    $tags.html(html);
    updateFilterUI();
  } catch(e){
    $tags.html('<div class=\"mt_primelink-empty\">Tags could not be loaded.</div>');
  }
}

// Navigator events
$(document).on('click', '.mt-preview-prev', function(){
  const $preview = $('#mt-primelink-preview');
  if (mt_primelinkPreviewIndex > 0) {
    mt_primelinkPreviewIndex--;
    renderVerticalPreview($preview);
  }
});

$(document).on('click', '.mt-preview-next', function(){
  const $preview = $('#mt-primelink-preview');
  if (mt_primelinkPreviewIndex < mt_primelinkPreviewTotal - 1) {
    mt_primelinkPreviewIndex++;
    renderVerticalPreview($preview);
  }
});

$(document).on('click', '#mt_primelink-preview-page-prev', function(){
  if(mt_primelinkPreviewPage > 1){
    mt_primelinkPreviewPage--;
    mt_primelinkPreviewIndex = 0;
    loadPreview();
  }
});

$(document).on('click', '#mt_primelink-preview-page-next', function(){
  if(mt_primelinkPreviewPage < mt_primelinkPreviewPages){
    mt_primelinkPreviewPage++;
    mt_primelinkPreviewIndex = 0;
    loadPreview();
  }
});

$(document).on('change', '#mt_primelink-preview-limit', function(){
  mt_primelinkPreviewPage = 1;
  mt_primelinkPreviewIndex = 0;
  loadPreview();
});


$(document).on('input', '#mt-primelink-xpath', function(){
  clearTimeout(window.mt_primelinkXPathTimer);
  window.mt_primelinkXPathTimer = setTimeout(loadPreview, 500);
});

// Detect roots
$(document).on('click', '#mt_primelink-detect-xml-roots', function(){
  const importId = currentImportId();
  fetchXmlRoots(importId);
});

// On root change, set xpath field and load tags
$(document).on('change', '#mt_primelink-xml-root', function(){
  const val = $(this).val();
  if(val){
    $('#mt-primelink-xpath').val(val);
    const importId = currentImportId();
    fetchXmlTags(importId, val);
    loadPreview();
  }
});

// Add filter rows
let mt_primelinkFilterIdx = 0;
function addFilterRow(field='', op='=', value=''){
  const idx = mt_primelinkFilterIdx++;
  const actions = [
    {v:'contains', l:'Contains', op:'contains'},
    {v:'not_contains', l:'Does not contain', op:'not_contains'},
    {v:'equals', l:'Equals', op:'='},
    {v:'not_equals', l:'Not equals', op:'!='},
    {v:'gt', l:'Greater than', op:'>'},
    {v:'lt', l:'Less than', op:'<'},
    {v:'empty', l:'Is empty', op:'='},
    {v:'not_empty', l:'Is not empty', op:'!='}
  ];
  const actionFromOp = (opVal, val) => {
    if(opVal === '=' && val === '') return 'empty';
    if(opVal === '!=' && val === '') return 'not_empty';
    if(opVal === 'contains') return 'contains';
    if(opVal === 'not_contains') return 'not_contains';
    if(opVal === '>') return 'gt';
    if(opVal === '<') return 'lt';
    if(opVal === '!=') return 'not_equals';
    return 'equals';
  };
  const act = actionFromOp(op, value);
  let html = '<div class="mt_primelink-filter-row" data-idx="'+idx+'">';
  html += '<div class="mt_primelink-filter-drop mt-map-slot__drop">'+(field ? buildChip(field) : '<span class="mt_primelink-muted">Drop field</span>')+'</div>';
  html += '<input type="hidden" class="mt_primelink-filter-field" name="filters['+idx+'][field]" value="'+escapeHtml(field)+'" />';
  html += '<select class="mt_primelink-filter-action" data-idx="'+idx+'">';
  actions.forEach(a=>{ html += '<option value="'+a.v+'" '+(a.v===act?'selected':'')+'>'+a.l+'</option>'; });
  html += '</select>';
  html += '<select name="filters['+idx+'][op]" class="mt_primelink-filter-op" style="display:none;">';
  actions.forEach(a=>{ html += '<option value="'+a.op+'" '+(a.op===op?'selected':'')+'>'+a.op+'</option>'; });
  html += '</select>';
  html += '<div class="mt_primelink-filter-inline">';
  html += '<input type="text" class="widefat mt_primelink-filter-value" name="filters['+idx+'][value]" placeholder="value" value="'+escapeHtml(value)+'" />';
  html += '<button type="button" class="button mt_primelink-filter-remove">x</button>';
  html += '</div>';
  html += '<div class="mt_primelink-filter-outcome">Rows are kept only when the condition is TRUE; others are skipped.</div>';
  html += '</div>';
  $("#mt_primelink-filter-rows").append(html);
  applyFilterAction($("#mt_primelink-filter-rows .mt_primelink-filter-row").last(), act, value);
}

function applyFilterAction($row, action, currentVal){
  const $op = $row.find('.mt_primelink-filter-op');
  const $val = $row.find('.mt_primelink-filter-value');
  let opVal = '=';
  let needsVal = true;
  switch(action){
    case 'contains': opVal='contains'; break;
    case 'not_contains': opVal='not_contains'; break;
    case 'gt': opVal='>'; break;
    case 'lt': opVal='<'; break;
    case 'not_equals': opVal='!='; break;
    case 'empty': opVal='='; needsVal=false; currentVal=''; break;
    case 'not_empty': opVal='!='; needsVal=false; currentVal=''; break;
    default: opVal='='; break;
  }
  $op.val(opVal);
  if(needsVal){
    $val.prop('disabled', false).removeClass('is-disabled');
    if(currentVal !== undefined){ $val.val(currentVal); }
  } else {
    $val.val('');
    $val.prop('disabled', true).addClass('is-disabled');
  }
}

$(document).on('click', '#mt_primelink-add-filter-row', function(){
  addFilterRow();
  updateFilterUI();
});

// Change action
$(document).on('change', '.mt_primelink-filter-action', function(){
  const $row = $(this).closest('.mt_primelink-filter-row');
  const action = $(this).val();
  const val = $row.find('.mt_primelink-filter-value').val();
  applyFilterAction($row, action, val);
  updateFilterUI();
  if(typeof loadMappingPreview === 'function'){
    loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
  }
});

$(document).on('click', '.mt_primelink-filter-remove', function(){
  $(this).closest('.mt_primelink-filter-row').remove();
  updateFilterUI();
});

// Clicking a tag adds a row prefilled
$(document).on('click', '.mt_primelink-xml-tag-btn', function(){
  const tag = $(this).data('tag') || '';
  addFilterRow(tag, 'contains', '');
  updateFilterUI();
});

// Drag/drop for filter field
$(document).on('dragover dragenter', '.mt_primelink-filter-drop', function(ev){
  ev.preventDefault();
  $(this).addClass('is-over');
});
$(document).on('dragleave', '.mt_primelink-filter-drop', function(){
  $(this).removeClass('is-over');
});
$(document).on('drop', '.mt_primelink-filter-drop', function(ev){
  ev.preventDefault();
  $(this).removeClass('is-over');
  const field = ev.originalEvent.dataTransfer.getData('text/plain');
  if(!field) return;
  $(this).html(buildChip(field));
  $(this).closest('.mt_primelink-filter-row').find('.mt_primelink-filter-field').val(field);
  updateFilterUI();
  if(typeof loadMappingPreview === 'function'){
    loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
  }
});

function collectFilterFields(){
  const fields = [];
  $('.mt_primelink-filter-row').each(function(){
    const field = ($(this).find('input[name*=\"[field]\"]').val() || '').trim();
    if(field){
      fields.push(field);
    }
  });
  return fields;
}

function collectFilterRowsData(){
  const filters = [];
  $('.mt_primelink-filter-row').each(function(){
    const field = ($(this).find('input[name*=\"[field]\"]').val() || '').trim();
    const op    = ($(this).find('select[name*=\"[op]\"]').val() || '').trim();
    const value = ($(this).find('input[name*=\"[value]\"]').val() || '').trim();
    if(field || value){
      filters.push({ field, op, value });
    }
  });
  return filters;
}

function updateFilterUI(){
  const fields = collectFilterFields();
  const $badge = $('#mt_primelink-filter-active-count');
  const active = fields.length;

  if(active > 0){
    $badge.text(active + ' active');
    $badge.show();
  } else {
    $badge.hide();
  }

  const fieldSet = new Set(fields.map(f => f.toLowerCase()));
  $('.mt_primelink-xml-tag-btn').each(function(){
    const tag = ($(this).data('tag') || '').toString().toLowerCase();
    if(fieldSet.has(tag)){
      $(this).addClass('is-filtered');
    } else {
      $(this).removeClass('is-filtered');
    }
  });

  const $notice = $('#mt_primelink-filter-notice');
  let warn = '';
  $('.mt_primelink-filter-row').each(function(){
    const field = ($(this).find('input[name*=\"[field]\"]').val() || '').trim();
    const value = ($(this).find('input[name*=\"[value]\"]').val() || '').trim();
    if(!field && value){
      warn = 'Complete the tag field for filters with a value.';
    }
  });
  if(warn){
    $notice.text(warn).show();
  } else {
    $notice.hide();
  }
  if(typeof loadMappingPreview === 'function'){
    loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
  }
}

$(document).on('input change', '.mt_primelink-filter-row input, .mt_primelink-filter-row select', function(){
  updateFilterUI();
});

// Filter presets
async function fetchFilterPresets(){
  try{
    const res = await restGet('/import/filter-presets');
    const list = res.presets || [];
    const $sel = $('#mt_primelink-filter-presets');
    if(!$sel.length) return;
    let html = '<option value="">Presets</option>';
    list.forEach(name => {
      html += '<option value="'+escapeHtml(name)+'">'+escapeHtml(name)+'</option>';
    });
    $sel.html(html);
  }catch(e){
    // silent
  }
}

async function loadFilterPreset(name){
  if(!name) return;
  try{
    const res = await restPost('/import/filter-presets/load', { name });
    const filters = res.filters || [];
    $('#mt_primelink-filter-rows').empty();
    mt_primelinkFilterIdx = 0;
    filters.forEach(f => addFilterRow(f.field || '', f.op || '=', f.value || ''));
    if(!filters.length){
      addFilterRow();
    }
    updateFilterUI();
  }catch(e){
    alert(e.json?.message || 'Could not load preset');
  }
}

async function saveFilterPreset(){
  const name = prompt('Preset name?');
  if(!name) return;
  const filters = collectFilterRowsData();
  try{
    await restPost('/import/filter-presets/save', { name, filters });
    fetchFilterPresets();
    alert('Preset saved');
  }catch(e){
    alert(e.json?.message || 'Could not save preset');
  }
}

async function deleteFilterPreset(){
  const $sel = $('#mt_primelink-filter-presets');
  const name = $sel.val();
  if(!name) return;
  if(!confirm('Delete preset "'+name+'"?')) return;
  try{
    await restPost('/import/filter-presets/delete', { name });
    fetchFilterPresets();
    alert('Preset deleted');
  }catch(e){
    alert(e.json?.message || 'Could not delete preset');
  }
}

$(document).on('click', '#mt_primelink-filter-preset-load', function(){
  const name = $('#mt_primelink-filter-presets').val();
  loadFilterPreset(name);
});

$(document).on('click', '#mt_primelink-filter-preset-save', function(){
  saveFilterPreset();
});

$(document).on('click', '#mt_primelink-filter-preset-delete', function(){
  deleteFilterPreset();
});

// Auto-map button (Step 5 for import, Step 2 for export)
$(document).on('click', '#mt_primelink-auto-map', function(){
  // Check if we're in export step 2 or import step 5
  if($('.mt_primelink-export-step-2').length){
    autoMapExportSuggestions();
  } else {
    autoMapSuggestions();
  }
});

// Clear all mapping slots
$(document).on('click', '#mt_primelink-clear-mapping', function(){
  if(!confirm('Clear all mapped fields?')) return;
  
  // Check if we're in export step 2
  const isExport = $('.mt_primelink-export-step-2').length > 0;
  
  $('.mt_primelink-map-slot').each(function(){
    $(this).find('.mt-map-slot__drop').html('<span class="mt_primelink-muted">Drop field here</span>');
    $(this).find('.mt_primelink-map-input').val('');
    $(this).find('.mt_primelink-map-config').val('');
    $(this).find('.mt_primelink-map-edit').prop('disabled', true).removeClass('is-visible');
    if(typeof setSlotBadge === 'function'){
      setSlotBadge($(this), '');
    }
  });
  $('.mt_primelink-attr-row').remove();
  $('#mt_primelink-custom-fields-wrap').empty();
  
  if(isExport){
    saveExportStep2Mapping();
    setTimeout(() => {
      loadExportPreview();
    }, 300);
  } else {
    saveStep5Mapping(true);
    markUnmappedSlots();
    if(typeof loadMappingPreview === 'function'){
      loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
    }
  }
});
  // -----------------------------
  // Step 5 Mapping preview (REST)
  // -----------------------------
  function bindDnD(){
    $('.mt-field, .mt_primelink-file-field').off('dragstart').on('dragstart', function(ev){
      const field = $(this).data('field');
      const label = $(this).text();
      ev.originalEvent.dataTransfer.setData('text/plain', field || label || '');
    });

    // Use event delegation for drop zones to support dynamically added elements
    $(document).off('dragover.dropzone drop.dropzone dragleave.dropzone', '.mt-map-slot__drop')
      .on('dragover.dropzone', '.mt-map-slot__drop', function(ev){ ev.preventDefault(); $(this).addClass('is-over'); })
      .on('dragleave.dropzone', '.mt-map-slot__drop', function(){ $(this).removeClass('is-over'); })
      .on('drop.dropzone', '.mt-map-slot__drop', function(ev){
      ev.preventDefault();
      $(this).removeClass('is-over');

      const dt = ev.originalEvent.dataTransfer;
      let field = dt ? dt.getData('text/plain') : '';
      if(!field || field === 'undefined'){
        const maybe = $(ev.originalEvent.target).closest('[data-field]');
        field = maybe.data('field') || maybe.text() || '';
      }
      field = String(field || '').trim();
      if (!field || field === 'undefined') {
        return;
      }

      const $dropZone = $(this);
      // Check if this is inside an attribute row (attributes have .mt_primelink-attr-row parent)
      const $attr = $dropZone.closest('.mt_primelink-attr-row');
      // Check if this is inside a custom field (custom fields have .mt_primelink-custom-field parent)
      const $customField = $dropZone.closest('.mt_primelink-custom-field');
      // Check if this is inside custom export columns wrap
      const $customExportWrap = $dropZone.closest('#mt_primelink-custom-export-columns-wrap');
      // Check if this is inside a regular map slot (slots have .mt_primelink-map-slot parent)
      // For attributes, the drop zone is inside .mt_primelink-map-slot, but we need to check if it's inside .mt_primelink-attr-row
      const $slot = $dropZone.closest('.mt_primelink-map-slot');
      
      // Handle custom fields first
      if($customField.length){
        // Check if this slot is inside a custom field (not a regular slot or attribute)
        const isCustomFieldSlot = $customField.find('.mt_primelink-map-slot').is($slot) || $slot.closest('.mt_primelink-custom-field').length > 0;
        
        if(isCustomFieldSlot && !$attr.length){
          // Save the field to the hidden input
          const $customVal = $customField.find('.mt_primelink-custom-val');
          if($customVal.length){
            $customVal.val(field);
          }
          
          // Update the drop zone display with chip
          $dropZone.html(buildChip(field));
          // Remove unmapped class
          $slot.removeClass('unmapped');
          pushMapHistory();
          saveStep5Mapping();
          // Reload preview to show the mapped value
          loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
          return; // Exit early for custom fields
        }
      }
      
      // Handle attribute rows - check if drop zone is inside an attribute row
      // For attributes, the drop zone is inside .mt_primelink-map-slot which is inside .mt_primelink-attr-row
      if($attr.length){
        // Check if this slot is inside an attribute row (not a regular slot)
        const isAttributeSlot = $attr.find('.mt_primelink-map-slot').is($slot) || $slot.closest('.mt_primelink-attr-row').length > 0;
        
        if(isAttributeSlot){
        // Save the field to the hidden input
        const $attrSource = $attr.find('.mt_primelink-attr-source');
        if($attrSource.length){
          $attrSource.val(field);
        }
        
        // Update the drop zone display with chip
        $dropZone.html(buildChip(field));
        // Remove unmapped class and enable Edit button
        const $attrSlot = $attr.find('.mt_primelink-map-slot');
        $attrSlot.removeClass('unmapped');
        $attr.find('.mt_primelink-attr-edit').prop('disabled', false).addClass('is-visible');
        pushMapHistory();
        saveStep5Mapping();
        // Reload preview to show the mapped value
        loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
        return; // Exit early for attributes
        }
      }
      
      // Handle custom export columns
      if($customExportWrap.length && $slot.length){
        // Save the field to the hidden input
        const $input = $slot.find('.mt_primelink-map-input');
        if($input.length){
          $input.val(field);
        }
        
        // Update the drop zone display with chip
        $dropZone.html(buildChip(field));
        // Remove unmapped class
        $slot.removeClass('unmapped');
        
        // Save export mapping
        saveExportStep2Mapping();
        // Reload preview
        loadExportPreview();
        return; // Exit early for custom export columns
      }
      
      const target = $slot.length ? $slot.data('target') || '' : '';

      if($slot.length){
        const existing = ($slot.find('.mt_primelink-map-input').val() || '').trim();
        const cfg = getSlotConfig($slot) || {};
        const isGallery = (target === 'images' || target === 'variation_gallery');

        if(existing && isGallery && existing !== field){
          let extras = Array.isArray(cfg.extra_sources) ? cfg.extra_sources.slice() : [];
          const all = [existing].concat(extras || []);
          if(all.indexOf(field) === -1){
            all.push(field);
          }
          $slot.find('.mt_primelink-map-input').val(all[0]);
          cfg.extra_sources = all.slice(1);
          setSlotConfig($slot, cfg);

          const chips = all.map((f, idx) => buildChip(f)).join(' ');
          $dropZone.html(chips);
        } else {
          $dropZone.html(buildChip(field));
          $slot.find('.mt_primelink-map-input').val(field);
          cfg.source_mode = 'manual';
          setSlotConfig($slot, cfg);
          setSlotBadge($slot, 'manual');
        }

        $slot.find('.mt_primelink-map-edit').prop('disabled', false).addClass('is-visible');

        pushMapHistory();
        saveStep5Mapping();
        markUnmappedSlots();
        loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
      }
    });

    // remove chip
  $(document).off('click', '.mt_primelink-chip-remove').on('click', '.mt_primelink-chip-remove', function(e){
    e.preventDefault();
    const $slot = $(this).closest('.mt_primelink-map-slot');
    const $attr = $(this).closest('.mt_primelink-attr-row');
    const $drop = $slot.length ? $slot.find('.mt-map-slot__drop') : $(this).closest('.mt-map-slot__drop');
    const isExport = $slot.closest('.mt_primelink-export-step-2').length > 0;

    if($slot.length){
      $drop.html('<span class="mt_primelink-muted">Drop field here</span>');
      $slot.find('.mt_primelink-map-input').val('');
      setSlotConfig($slot, {});
      setSlotBadge($slot, '');

      // Add unmapped class for custom export columns when source is removed
      const $customExportWrap = $slot.closest('#mt_primelink-custom-export-columns-wrap');
      if($customExportWrap.length){
        $slot.addClass('unmapped');
      }

      // Disable Edit again
      $slot.find('.mt_primelink-map-edit').prop('disabled', true);
      $slot.find('.mt_primelink-map-edit').removeClass('is-visible');

      if(isExport){
        saveExportStep2Mapping();
        loadExportPreview();
      } else {
        pushMapHistory();
        saveStep5Mapping();
        markUnmappedSlots();
        loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
      }
    } else if($attr.length){
      $drop.html('<span class="mt_primelink-muted">Drop field here</span>');
      $attr.find('.mt_primelink-attr-source').val('');
      // Add unmapped class and disable Edit button
      const $attrSlot = $attr.find('.mt_primelink-map-slot');
      $attrSlot.addClass('unmapped');
      $attr.find('.mt_primelink-attr-edit').prop('disabled', true).removeClass('is-visible');
      if(isExport){
        saveExportStep2Mapping();
      } else {
        pushMapHistory();
        saveStep5Mapping();
      }
    } else if($customField.length){
      $drop.html('<span class="mt_primelink-muted">Drop field here</span>');
      $customField.find('.mt_primelink-custom-val').val('');
      $customField.find('.mt_primelink-map-config').val(''); // Clear config
      // Add unmapped class
      const $customSlot = $customField.find('.mt_primelink-map-slot');
      $customSlot.addClass('unmapped');
      if(isExport){
        saveExportStep2Mapping();
      } else {
        pushMapHistory();
        saveStep5Mapping();
        loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
      }
    }
  });

  // Open slot editor when clicking the "edit" label on chip
  $(document).on('click', '.mt_primelink-chip-edit-label', function(e){
    e.preventDefault();
    const $slot = $(this).closest('.mt_primelink-map-slot');
    if($slot.length && typeof openEditor === 'function'){
      openEditor($slot);
    }
  });

  // Apply suggestion pill
  $(document).on('click', '.mt_primelink-suggestion-action', function(){
    const target = $(this).data('target');
    const source = $(this).data('source');
    if(target && source){
      applyMapping(target, source);
      pushMapHistory();
      saveStep5Mapping();
      markUnmappedSlots();
      loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
    }
  });
  // Edit specific chip
  $(document).on('click', '.mt_primelink-chip-edit-label', function(e){
    e.preventDefault();
    const $slot = $(this).closest('.mt_primelink-map-slot');
    const src   = $(this).closest('.mt_primelink-chip').data('source');
    if($slot.length && typeof openEditor === 'function'){
      openEditor($slot, src);
    }
  });

  // Clear mapping from suggestion pill
  $(document).on('click', '.mt_primelink-suggestion-clear', function(e){
    e.preventDefault();
    const target = $(this).data('target');
    const $slot = $('.mt_primelink-map-slot[data-target="'+target+'"]');
    if($slot.length){
      $slot.find('.mt_primelink-map-input').val('');
      $slot.find('.mt_primelink-map-drop').html('<span class="mt_primelink-muted">Drop field here</span>');
      $slot.find('.mt_primelink-map-edit').prop('disabled', true).removeClass('is-visible');
      setSlotBadge($slot, '');
      pushMapHistory();
      saveStep5Mapping();
      markUnmappedSlots();
      loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
    }
  });

  // Toggle nested field groups
  $(document).on('click', '.mt_primelink-field-group-header', function(){
    const $children = $(this).next('.mt_primelink-field-group-children');
    $(this).toggleClass('is-open');
    $children.slideToggle(120);
  });
}
async function loadMappingPreview(index){
  const $fieldsWrap = $('#mt-primelink-fields');
  if(!$fieldsWrap.length) return;

  const importId = parseInt($fieldsWrap.data('import-id'), 10) || currentImportId();
  index = index || 0;

  // Don't make request if no valid import_id
  if(!importId || importId === 0){
    return;
  }

  // keep current index for refresh-after-save
  window.mt_primelinkCurrentMapIndex = index;

  try {
    const filters = collectFilterRowsData();
    const res = await restPost('/import/mapping-preview', {
      import_id: importId,
      index: index,
      filters: filters
    });

    // Left list (render only if changed to avoid flicker)
    const newFieldsRaw = res.fields || [];
    const newFields = newFieldsRaw.filter(f => {
      if(typeof f !== 'string') return false;
      const trimmed = f.trim();
      if(!trimmed) return false;
      if(trimmed.toLowerCase() === 'undefined') return false;
      return true;
    });
    let tree = res.fields_tree || null;

    // Sanitize tree nodes to avoid undefined labels
    const sanitizeTree = (nodes, parentFull) => {
      if(!Array.isArray(nodes)) return [];
      return nodes.map(n => {
        const rawName = typeof n.name === 'string' ? n.name : '';
        const rawFull = typeof n.full === 'string' ? n.full : '';
        const full = rawFull || (parentFull ? parentFull + '.' + rawName : rawName);
        const name = rawName || full || '';
        if(!full || full.toLowerCase() === 'undefined' || name.toLowerCase() === 'undefined'){
          return null;
        }
        const children = sanitizeTree(n.children || [], full);
        return { full, name, is_field: !!n.is_field, children };
      }).filter(n => n && n.full);
    };
    if(tree) tree = sanitizeTree(tree, '');

    const changed = true; // force rebuild to clear stale "undefined"
    if(changed || tree){
        let leftHtml = '';
        const hadPrev = mt_primelinkPrevFields.length > 0;

        function treeIsValid(nodes){
          if(!nodes || !nodes.length) return false;
          for(const n of nodes){
            if(!n || !(n.full || n.name)) return false;
            if(n.children && n.children.length && !treeIsValid(n.children)) return false;
          }
          return true;
        }

        function renderTree(nodes, depth, parentIsLast = false){
          if(!nodes || !nodes.length) return '';
          let html = '';
          nodes.forEach((node, index) => {
            const hasChildren = node.children && node.children.length;
          const isField = !!node.is_field;
          const full = node.full || node.name || '';
          if(!full) return;
          const indent = depth * 12;
          const isLast = index === nodes.length - 1;
          
          if(hasChildren){
            html += '<div class="mt_primelink-file-field mt_primelink-file-field--group" style="padding-left:'+indent+'px;position:relative;">';
            // Vertical connector line (only if not root level)
            if(depth > 0){
              html += '<div class="mt_primelink-tree-connector" style="position:absolute;left:'+(indent-6)+'px;top:0;bottom:0;width:1px;background:rgba(255,255,255,0.15);pointer-events:none;"></div>';
            }
            html += '  <div class="mt_primelink-field-group-header is-open" data-node="'+escapeHtml(full)+'" style="position:relative;padding-left:18px;">';
            // Tree branch indicator
            if(depth > 0){
              html += '<span class="mt_primelink-tree-branch" style="position:absolute;left:0;top:2px;color:rgba(255,255,255,0.5);font-size:14px;line-height:1;font-family:monospace;">' + (isLast ? 'â””' : 'â”œ') + '</span>';
            }
            html += escapeHtml(node.name || full);
            html += '</div>';
            html += '  <div class="mt_primelink-field-group-children" style="position:relative;padding-left:'+(depth > 0 ? '18' : '0')+'px;">';
            // If this node is also a field, render it inside the group (before children)
            if(isField){
              const isNew = hadPrev && mt_primelinkPrevFields.indexOf(node.full) === -1;
              const childrenCount = node.children.length;
              html += '<div class="mt_primelink-file-field'+(isNew?' is-new-field':'')+'" draggable="true" data-field="'+escapeHtml(full)+'" style="padding-left:0px;margin-bottom:4px;margin-top:2px;position:relative;">';
              if(childrenCount > 0){
                html += '<span class="mt_primelink-tree-branch" style="position:absolute;left:-18px;top:8px;color:rgba(255,255,255,0.5);font-size:14px;line-height:1;font-family:monospace;">â”œ</span>';
              }
              html += '<span class="mt_primelink-file-field__name">'+escapeHtml(full)+'</span>';
              html += '</div>';
            }
            // Render children recursively
            html += renderTree(node.children, depth+1, isLast);
            html += '  </div>';
            html += '</div>';
          } else {
            // Leaf node (no children) - render as regular field
            const isNew = hadPrev && mt_primelinkPrevFields.indexOf(node.full) === -1;
            html += '<div class="mt_primelink-file-field'+(isNew?' is-new-field':'')+'" draggable="true" data-field="'+escapeHtml(full)+'" style="padding-left:'+indent+'px;position:relative;">';
            // Tree branch indicator for leaf nodes
            if(depth > 0){
              html += '<span class="mt_primelink-tree-branch" style="position:absolute;left:'+(indent-18)+'px;top:8px;color:rgba(255,255,255,0.5);font-size:14px;line-height:1;font-family:monospace;">' + (isLast ? 'â””' : 'â”œ') + '</span>';
            }
            html += '<span class="mt_primelink-file-field__name">'+escapeHtml(full)+'</span>';
            html += '</div>';
          }
        });
        return html;
        }

        if(tree && tree.length && treeIsValid(tree)){
          leftHtml = renderTree(tree, 0);
        } else {
          newFields.forEach(f=>{
            const isNew = hadPrev && mt_primelinkPrevFields.indexOf(f) === -1;
            leftHtml += '<div class="mt_primelink-file-field'+(isNew?' is-new-field':'')+'" draggable="true" data-field="'+escapeHtml(f)+'">'
                   +  '<span class="mt_primelink-file-field__name">'+escapeHtml(f)+'</span>'
                   + '</div>';
        });
      }

      $fieldsWrap.html(leftHtml || '<div class="mt_primelink-empty">No fields found.</div>');
      filterFileFields();
      filterTargetSlots();
    }
    mt_primelinkMapFields = newFields;
    window.mt_primelinkMapFields = newFields; // Also set on window for AI mapping
    mt_primelinkPrevFields = newFields;
    renderSuggestions(newFields, res.item || {});

    // Right preview: mapped output (with separator/transforms/conditions/default)
    const item  = res.item  || {};
    const total = res.total || 0;
    const idx   = res.index || 0;

    const state = readCurrentMapping();
    const mapped = {};

    Object.keys(state.mapping || {}).forEach(target=>{
      mapped[target] = computeMappedValue(item, state.mapping[target]);
    });

  const mappedCustom = (state.customFields || []).map(cf=>{
    return {
      key: cf.key,
      value: computeMappedValue(item, cf)
    };
  });

    let vhtml = '';
    vhtml += '<div class="mt-preview-meta"><strong>Type:</strong> ' + escapeHtml(res.type) + '</div>';

    vhtml += '<div class="mt-preview-nav">';
    vhtml += '  <button type="button" class="button mt-map-prev" ' + (idx <= 0 ? 'disabled' : '') + ' data-index="' + Math.max(0, idx-1) + '">&lsaquo; Prev</button>';
    vhtml += '  <span class="mt-preview-counter">Row ' + (idx + 1) + ' / ' + total + '</span>';
    vhtml += '  <button type="button" class="button button-primary mt-map-next" ' + (idx >= total-1 ? 'disabled' : '') + ' data-index="' + Math.min(total-1, idx+1) + '">Next &rsaquo;</button>';
    vhtml += '</div>';

    vhtml += '<div class="mt-preview-vertical-wrap">';
    vhtml += '<table class="mt-preview-vertical">';
    vhtml += '<thead><tr><th>Target Field</th><th>Mapped Value</th></tr></thead><tbody>';

    // Add attributes to preview
    if(state.attributes && Array.isArray(state.attributes) && state.attributes.length > 0){
      state.attributes.forEach((attr, idx) => {
        if(attr && attr.name){
          // Show attribute even if source is not set yet
          if(!attr.source || !attr.source.trim()){
            vhtml += '<tr>';
            vhtml += '  <td class="mt-preview-field">' + escapeHtml(attr.name) + ' <span class="mt_primelink-map-expected">(Attribute)</span></td>';
            vhtml += '  <td class="mt-preview-value"><pre style="margin:0;white-space:pre-wrap;color:#999;">(not mapped)</pre></td>';
            vhtml += '</tr>';
            return;
          }
          // Get config from hidden input if available
          const $attrRow = $('.mt_primelink-attr-row').filter(function(){
            return $(this).find('.mt_primelink-attr-name').val().trim() === attr.name;
          }).first();
          let attrCfg = { source: attr.source };
          if($attrRow.length){
            const $configInput = $attrRow.find('.mt_primelink-attr-config');
            if($configInput.length && $configInput.val()){
              try {
                const parsedCfg = JSON.parse($configInput.val());
                attrCfg = { ...attrCfg, ...parsedCfg };
              } catch(e) {
                // Use default config
              }
            }
          }
          
          // Compute mapped value - use the same logic as regular fields
          const attrVal = computeMappedValue(item, attrCfg);
          
          // Format value for display
          let displayValue = '';
          if(Array.isArray(attrVal)){
            if(attrVal.length === 0){
              displayValue = '(empty)';
            } else if(attrVal.length === 1){
              displayValue = String(attrVal[0] || '(empty)');
            } else {
              displayValue = attrVal.map(v => "- " + String(v || '')).join("\n");
            }
          } else if(attrVal === undefined || attrVal === null || attrVal === ''){
            displayValue = '(empty)';
          } else {
            displayValue = String(attrVal);
          }

          vhtml += '<tr>';
          vhtml += '  <td class="mt-preview-field">' + escapeHtml(attr.name) + ' <span class="mt_primelink-map-expected">(Attribute)</span></td>';
          
          // Special handling for images
          if (Array.isArray(attrVal) && attrVal.length > 0) {
            const imageUrls = attrVal.filter(v => v && String(v).trim() && (String(v).startsWith('http') || String(v).startsWith('//')));
            if(imageUrls.length > 0){
              vhtml += '  <td class="mt-preview-value"><div class="mt-preview-gallery">';
              imageUrls.forEach(url => {
                vhtml += '<img src="' + escapeHtml(url) + '" alt="Preview" style="max-width:60px;max-height:60px;margin:2px;border-radius:4px;" />';
              });
              vhtml += '</div></td>';
            } else {
              vhtml += '  <td class="mt-preview-value"><pre style="margin:0;white-space:pre-wrap;">' + escapeHtml(displayValue) + '</pre></td>';
            }
          } else if (typeof attrVal === 'string' && attrVal.trim() && (attrVal.startsWith('http') || attrVal.startsWith('//'))) {
            vhtml += '  <td class="mt-preview-value"><img src="' + escapeHtml(attrVal) + '" alt="Preview" style="max-width:60px;max-height:60px;margin:2px;border-radius:4px;" /></td>';
          } else {
            // Always show value
            vhtml += '  <td class="mt-preview-value"><pre style="margin:0;white-space:pre-wrap;">' + escapeHtml(displayValue) + '</pre></td>';
          }
          vhtml += '</tr>';
        }
      });
    }

    Object.keys(mapped).forEach(target=>{
      let val = mapped[target];
      const rawVal = val;

      if(Array.isArray(val)){
        val = val.map(v => "- " + v).join("\n");
      } else {
        val = (val === undefined || val === null) ? "" : String(val);
      }

      const expected = expectedTypeForTarget(target);
      const actual   = detectValueType(rawVal);
      const warn     = validateType(expected, actual, val);

      vhtml += '<tr>';
      vhtml += '  <td class="mt-preview-field">' + escapeHtml(target) + (expected ? '<div class="mt_primelink-map-expected">'+escapeHtml(expected)+' expected</div>' : '') + '</td>';
      
      // Special handling for images fields - show as gallery
      if ((target === 'images' || target === 'featured_image') && (Array.isArray(rawVal) || (typeof rawVal === 'string' && rawVal.trim()))) {
        const imageUrls = Array.isArray(rawVal) ? rawVal : (rawVal ? [rawVal] : []);
        const validUrls = imageUrls.filter(url => url && String(url).trim() && (String(url).startsWith('http') || String(url).startsWith('//')));
        
        if (validUrls.length > 0) {
          let imgHtml = '<div class="mt_primelink-preview-images" style="display:flex;flex-wrap:wrap;gap:8px;margin-top:4px;">';
          validUrls.forEach(url => {
            const cleanUrl = String(url).trim();
            imgHtml += '<div class="mt_primelink-preview-image" style="position:relative;width:80px;height:80px;border:1px solid rgba(255,255,255,0.2);border-radius:4px;overflow:hidden;background:#f0f0f0;">';
            imgHtml += '<img src="' + escapeHtml(cleanUrl) + '" style="width:100%;height:100%;object-fit:cover;" onerror="this.style.display=\'none\';this.parentElement.innerHTML=\'<div style=\\\'padding:8px;text-align:center;font-size:10px;color:#999\\\'>Image<br/>Error</div>\';" />';
            imgHtml += '</div>';
          });
          imgHtml += '</div>';
          if (validUrls.length > 1) {
            imgHtml += '<small class="muted" style="display:block;margin-top:4px;">' + validUrls.length + ' images</small>';
          }
          vhtml += '  <td class="mt-preview-value' + (warn ? ' has-warning' : '') + '">' + imgHtml + (warn ? '<div class="mt_primelink-map-warning">'+escapeHtml(warn)+'</div>' : '') + '</td>';
        } else {
          vhtml += '  <td class="mt-preview-value' + (warn ? ' has-warning' : '') + '"><pre style="margin:0;white-space:pre-wrap;">' + escapeHtml(val) + '</pre>' + (warn ? '<div class="mt_primelink-map-warning">'+escapeHtml(warn)+'</div>' : '') + '</td>';
        }
      } else if(Array.isArray(rawVal)){
        const list = rawVal.map(v => '<span class="mt_primelink-chip">'+escapeHtml(String(v))+'</span>').join(' ');
        vhtml += '  <td class="mt-preview-value' + (warn ? ' has-warning' : '') + '"><div class="mt_primelink-chip-stack">'+list+'</div>' + (warn ? '<div class="mt_primelink-map-warning">'+escapeHtml(warn)+'</div>' : '') + '</td>';
      } else {
        vhtml += '  <td class="mt-preview-value' + (warn ? ' has-warning' : '') + '"><pre style="margin:0;white-space:pre-wrap;">' + escapeHtml(val) + '</pre>' + (warn ? '<div class="mt_primelink-map-warning">'+escapeHtml(warn)+'</div>' : '') + '</td>';
      }
      vhtml += '</tr>';
    });

    if(mappedCustom.length){
      vhtml += '<tr><td colspan="2" style="font-weight:700;padding-top:10px;">Custom Fields</td></tr>';
      mappedCustom.forEach(cf=>{
        let val = cf.value;

        if(Array.isArray(val)){
        val = val.map(v => "- " + v).join("\\n");
      } else {
        val = (val === undefined || val === null) ? "" : String(val);
      }

        vhtml += '<tr>';
        vhtml += '  <td class="mt-preview-field">' + escapeHtml(cf.key) + '</td>';
        vhtml += '  <td class="mt-preview-value"><pre style="margin:0;white-space:pre-wrap;">' + escapeHtml(val) + '</pre></td>';
        vhtml += '</tr>';
      });
    }

    // Linked products preview
    const linkedKeys = ['upsell_refs','cross_sell_refs','grouped_children'];
    const linkedRows = linkedKeys
      .map(k => ({ key:k, val: mapped[k] }))
      .filter(r => r.val !== undefined && r.val !== null && String(r.val).trim() !== '');
    if(linkedRows.length){
      vhtml += '<tr><td colspan="2" style="font-weight:700;padding-top:10px;">Linked Products</td></tr>';
      linkedRows.forEach(r=>{
        vhtml += '<tr>';
        vhtml += '  <td class="mt-preview-field">'+escapeHtml(r.key)+'</td>';
        vhtml += '  <td class="mt-preview-value"><pre style="margin:0;white-space:pre-wrap;">'+escapeHtml(String(r.val))+'</pre></td>';
        vhtml += '</tr>';
      });
    }

    vhtml += '</tbody></table></div>';

    $('#mt-primelink-item-preview').html(vhtml);

    bindDnD();
    markUnmappedSlots();
    if(typeof syncSlotBadges === 'function'){
      syncSlotBadges();
    }

  } catch(err){
    const msg = err?.json?.message || err?.message || 'Unknown error';
    $fieldsWrap.html('Mapping preview failed.<br><pre>'+escapeHtml(msg)+'</pre>');
  }
}


function applyTransforms(value, cfg){
  let v = (value === undefined || value === null) ? '' : String(value);

  if(cfg?.transforms?.trim){
    v = v.trim();
  }
  if(cfg?.transforms?.lowercase){
    v = v.toLowerCase();
  }
  if(cfg?.transforms?.uppercase){
    v = v.toUpperCase();
  }
  if(cfg?.transforms?.capitalize){
    v = v.charAt(0).toUpperCase() + v.slice(1).toLowerCase();
  }
  if(cfg?.transforms?.title_case){
    v = v.replace(/\w\S*/g, (txt) => {
      return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
    });
  }
  if(cfg?.transforms?.normalize_html){
    v = normalizeHtml(v);
  }
  if(cfg?.transforms?.remove_accents){
    v = v.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
  }
  if(cfg?.transforms?.slugify){
    v = v.toLowerCase()
      .normalize('NFD').replace(/[\u0300-\u036f]/g, '')
      .replace(/[^a-z0-9]+/g, '-')
      .replace(/^-+|-+$/g, '');
  }
  if(cfg?.transforms?.extract_numbers){
    v = v.replace(/[^\d.-]/g, '');
  }
  if(cfg?.transforms?.extract_text){
    v = v.replace(/[\d.-]/g, '');
  }
  if(cfg?.transforms?.url_encode){
    v = encodeURIComponent(v);
  }
  if(cfg?.transforms?.url_decode){
    try { v = decodeURIComponent(v); } catch(e) {}
  }
  
  // Number transforms
  if(cfg?.transforms?.round || cfg?.transforms?.ceil || cfg?.transforms?.floor){
    const num = parseFloat(v);
    if(!isNaN(num)){
      if(cfg.transforms.round){
        const decimals = parseInt(cfg.transforms.round_decimals) || 2;
        v = num.toFixed(decimals);
      } else if(cfg.transforms.ceil){
        v = Math.ceil(num).toString();
      } else if(cfg.transforms.floor){
        v = Math.floor(num).toString();
      }
    }
  }
  if(cfg?.transforms?.number_format && cfg.transforms.number_format !== ''){
    const num = parseFloat(v);
    if(!isNaN(num)){
      const parts = num.toFixed(2).split('.');
      if(cfg.transforms.number_format === 'comma'){
        v = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',') + '.' + parts[1];
      } else if(cfg.transforms.number_format === 'dot'){
        v = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, '.') + ',' + parts[1];
      } else if(cfg.transforms.number_format === 'space'){
        v = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ' ') + '.' + parts[1];
      }
    }
  }
  
  // String operations
  if(cfg?.transforms?.substring_start !== undefined && cfg.transforms.substring_start !== ''){
    const start = parseInt(cfg.transforms.substring_start) || 0;
    const length = cfg.transforms.substring_length ? parseInt(cfg.transforms.substring_length) : undefined;
    v = v.substring(start, length !== undefined ? start + length : undefined);
  }
  if(cfg?.transforms?.pad_side && cfg.transforms.pad_length){
    const length = parseInt(cfg.transforms.pad_length) || 0;
    const char = cfg.transforms.pad_char || ' ';
    if(cfg.transforms.pad_side === 'left'){
      v = v.padStart(length, char);
    } else if(cfg.transforms.pad_side === 'right'){
      v = v.padEnd(length, char);
    }
  }
  
  // Date transforms
  if(cfg?.transforms?.date_format && cfg.transforms.date_output){
    try {
      // Try to parse date with input format
      const date = parseDate(v, cfg.transforms.date_format);
      if(date && !isNaN(date.getTime())){
        v = formatDate(date, cfg.transforms.date_output);
      }
    } catch(e) {}
  }
  
  // Regex replace
  if(cfg?.transforms?.regex_pattern && cfg.transforms.regex_pattern !== ''){
    try {
      const pattern = new RegExp(cfg.transforms.regex_pattern, 'g');
      const replacement = cfg.transforms.regex_replacement || '';
      v = v.replace(pattern, replacement);
    } catch(e) {}
  }
  
  // Replace rules (after other transforms)
  if(Array.isArray(cfg?.transforms?.replace)){
    cfg.transforms.replace.forEach(r=>{
      if(!r || r.from === undefined) return;
      const from = String(r.from);
      const to   = String(r.to ?? '');
      if(from === '') return;
      v = v.split(from).join(to);
    });
  }

  return v;
}

// Helper functions for date parsing/formatting
function parseDate(dateString, format){
  if(!dateString || !format) return null;
  
  // Simple date parsing - supports common formats
  const formatMap = {
    'Y-m-d': (s) => {
      const parts = s.split('-');
      return new Date(parseInt(parts[0]), parseInt(parts[1])-1, parseInt(parts[2]));
    },
    'd/m/Y': (s) => {
      const parts = s.split('/');
      return new Date(parseInt(parts[2]), parseInt(parts[1])-1, parseInt(parts[0]));
    },
    'm/d/Y': (s) => {
      const parts = s.split('/');
      return new Date(parseInt(parts[2]), parseInt(parts[1])-1, parseInt(parts[0]));
    },
    'Y-m-d H:i:s': (s) => {
      const [date, time] = s.split(' ');
      const [y, m, d] = date.split('-');
      const [h, i, sec] = time.split(':');
      return new Date(parseInt(y), parseInt(m)-1, parseInt(d), parseInt(h), parseInt(i), parseInt(sec));
    }
  };
  
  if(formatMap[format]){
    try {
      return formatMap[format](dateString);
    } catch(e) {
      return null;
    }
  }
  
  // Fallback to Date.parse
  const parsed = Date.parse(dateString);
  return isNaN(parsed) ? null : new Date(parsed);
}

function formatDate(date, format){
  if(!date || !format) return '';
  
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');
  
  return format
    .replace('Y', year)
    .replace('m', month)
    .replace('d', day)
    .replace('H', hours)
    .replace('i', minutes)
    .replace('s', seconds);
}

function adjustPrice(value, adj){
  const num = parseFloat(value);
  const amt = parseFloat(adj?.amount);
  if(isNaN(num) || isNaN(amt)) return value;
  let out = num;
  switch(adj?.type){
    case 'percent_plus':
      out = num + num * (amt/100);
      break;
    case 'percent_minus':
      out = num - num * (amt/100);
      break;
    case 'fixed_plus':
      out = num + amt;
      break;
    case 'fixed_minus':
      out = num - amt;
      break;
    default:
      return value;
  }
  return out;
}

function applySeparator(value, sep){
  if(!sep) return value;
  const parts = String(value).split(sep).map(s=>s.trim()).filter(Boolean);
  return parts;
}

function normalizeHtml(str){
  if(!str) return '';
  let cleaned = str.replace(/<[^>]+>/g, ' ');
  // decode entities using textarea trick
  const div = document.createElement('textarea');
  div.innerHTML = cleaned;
  cleaned = div.value;
  cleaned = cleaned.replace(/\s+/g, ' ').trim();
  return cleaned;
}

function checkConditions(item, conditions){
  if(!Array.isArray(conditions) || !conditions.length) return true;

  return conditions.every(c=>{
    const left = item[c.field] !== undefined ? String(item[c.field]) : '';
    const right = String(c.value ?? '');

    switch(c.op){
      case '=': return left === right;
      case '!=': return left !== right;
      case '>': return parseFloat(left) > parseFloat(right);
      case '<': return parseFloat(left) < parseFloat(right);
      case 'contains': return left.includes(right);
      default: return true;
    }
  });
}

function expectedTypeForTarget(target){
  const t = (target || '').toLowerCase();
  if(/price|cost|amount|total|qty|quantity|stock|weight|length|width|height|tax/.test(t)){
    return 'number';
  }
  if(/date|time/.test(t)){
    return 'date';
  }
  if(/url|link|image|img/.test(t)){
    return 'url';
  }
  return '';
}

function detectValueType(val){
  if(Array.isArray(val) && val.length){
    return detectValueType(val[0]);
  }
  const v = (val === undefined || val === null) ? '' : String(val).trim();
  if(v === '') return 'empty';
  if(/^https?:\/\//i.test(v)) return 'url';
  const num = parseFloat(v);
  if(!isNaN(num) && isFinite(num)) return 'number';
  const ts = Date.parse(v);
  if(!isNaN(ts)) return 'date';
  return 'text';
}

function arraysEqual(a, b){
  if(!Array.isArray(a) || !Array.isArray(b)) return false;
  if(a.length !== b.length) return false;
  for(let i=0;i<a.length;i++){
    if(a[i] !== b[i]) return false;
  }
  return true;
}

function validateType(expected, actual, displayVal){
  if(!expected) return '';
  if(actual === 'empty') return '';
  if(expected === 'number' && actual !== 'number') return 'Expected number';
  if(expected === 'date' && actual !== 'date') return 'Expected date';
  if(expected === 'url' && actual !== 'url') return 'Expected URL';
  return '';
}

function validateCriticalMapping(){
  const status = calcRequiredStatus();
  renderRequiredChecklist(status);
  return status.ok;
}

function calcRequiredStatus(){
  // Skip required field validation for orders
  if(document.body.classList.contains('mt_primelink-import-orders')){
    const state = readCurrentMapping();
    const m = state.mapping || {};
    const hasOrderId = !!(m['order_id'] && m['order_id'].source);
    const hasCustomerEmail = !!(m['customer_email'] && m['customer_email'].source);
    return {
      hasTitle: true,
      hasSku: true,
      hasPrice: true,
      ok: hasOrderId || hasCustomerEmail // At least one identifier for orders
    };
  }
  // Required field validation for customers
  if(document.body.classList.contains('mt_primelink-import-customers')){
    const state = readCurrentMapping();
    const m = state.mapping || {};
    const hasEmail = !!(m['email'] && m['email'].source);
    return {
      hasTitle: true,
      hasSku: true,
      hasPrice: true,
      ok: hasEmail // Email is required for customers
    };
  }
  // Required field validation for coupons
  if(document.body.classList.contains('mt_primelink-import-coupons')){
    const state = readCurrentMapping();
    const m = state.mapping || {};
    const hasCode = !!(m['code'] && m['code'].source);
    return {
      hasTitle: true,
      hasSku: true,
      hasPrice: true,
      ok: hasCode // Code is required for coupons
    };
  }
  const state = readCurrentMapping();
  const m = state.mapping || {};
  const hasTitle = !!(m['post_title'] && m['post_title'].source);
  const hasSku   = !!(m['sku'] && m['sku'].source);
  const hasPrice = !!(
    (m['price'] && m['price'].source) ||
    (m['regular_price'] && m['regular_price'].source) ||
    (m['sale_price'] && m['sale_price'].source)
  );
  return {
    hasTitle,
    hasSku,
    hasPrice,
    ok: hasPrice && (hasTitle || hasSku)
  };
}

function showNextTooltip(msg){
  let $tip = $('#mt_primelink-next-tooltip');
  if(!$tip.length){
    const $btn = $('#mt-primelink-next');
    $tip = $('<div id="mt_primelink-next-tooltip" class="mt_primelink-next-tooltip"></div>');
    $btn.after($tip);
  }
  $tip.text(msg).fadeIn(120);
  clearTimeout(window.mt_primelinkNextTipTimer);
  window.mt_primelinkNextTipTimer = setTimeout(()=> $tip.fadeOut(200), 3000);
}

// Build final mapped value for a target slot
function computeMappedValue(item, slotCfg){
  if(!slotCfg) return '';
  if(slotCfg.constant !== undefined) return slotCfg.constant;
  if(!slotCfg.source) return '';

  let raw = item[slotCfg.source];
  // Fallbacks for list-style keys
  if(raw === undefined || raw === null || raw === ''){
    const s = slotCfg.source;
    if(s.endsWith('[]') && item[s.slice(0, -2)] !== undefined){
      raw = item[s.slice(0, -2)];
    } else if(item[s + '.0'] !== undefined){
      raw = item[s + '.0'];
    }
  }
  raw = raw ?? '';
  if(!checkConditions(item, slotCfg.conditions)) return '';

  const rawValues = [];
  rawValues.push(raw);
  if(Array.isArray(slotCfg.extra_sources)){
    slotCfg.extra_sources.forEach(f=>{
      if(f){
        rawValues.push(item[f] ?? '');
      }
    });
  }

  let results = [];
  rawValues.forEach(rv=>{
    let v = applyTransforms(rv, slotCfg);

    if((v === '' || v === null) && slotCfg.default){
      v = slotCfg.default;
    }

    // Price adjustment for price targets
    if(slotCfg.price_adjust){
      v = adjustPrice(v, slotCfg.price_adjust);
    }

    if(slotCfg.separator){
      const arr = applySeparator(v, slotCfg.separator);
      if(Array.isArray(arr)){
        arr.forEach(a=> results.push(a));
        return;
      }
    }
    results.push(v);
  });

  const mode = slotCfg.template_mode || 'before';

  results = results
    .map(val => {
      let v = (val === undefined || val === null) ? '' : String(val);

      if(slotCfg.template){
        if(slotCfg.template.includes('{value}')){
          v = slotCfg.template.replace(/\{value\}/g, v);
        } else {
          if(mode === 'before'){
            v = slotCfg.template + v;
          } else if(mode === 'after'){
            v = v + slotCfg.template;
          } else if(mode === 'replace'){
            v = slotCfg.template;
          }
        }
      }

      if(slotCfg.prefix){
        v = slotCfg.prefix + v;
      }
      if(slotCfg.suffix){
        v = v + slotCfg.suffix;
      }
      return v;
    })
    .filter(v => v !== '');

  if(results.length > 1){
    return results;
  }
  return results[0] ?? '';
}

function renderRequiredChecklist(status){
  status = status || calcRequiredStatus();
  const $list = $('#mt_primelink-required-list');
  const $stat = $('#mt_primelink-required-status');
  if(!$list.length) return status.ok;
  
  // For orders, show order-specific required fields
  if(document.body.classList.contains('mt_primelink-import-orders')){
    const m = collectMappingState().mapping || {};
    const hasOrderId = Object.keys(m).some(k => ['order_id'].includes(k.toLowerCase()) && m[k].source);
    const hasCustomerEmail = Object.keys(m).some(k => ['customer_email'].includes(k.toLowerCase()) && m[k].source);
    const rows = [
      { key: 'order_id', label: 'Order ID or Customer Email', ok: (hasOrderId || hasCustomerEmail), detail: hasOrderId ? 'Order ID mapped' : (hasCustomerEmail ? 'Customer Email mapped' : 'Missing both') },
    ];
    $list.empty();
    rows.forEach(r=>{
      const pill = $('<li class="mt_primelink-helper-pill"></li>').addClass(r.ok ? 'ok' : 'missing');
      pill.append('<span>'+escapeHtml(r.label)+'</span>');
      pill.append('<span class="muted">'+escapeHtml(r.detail)+'</span>');
      $list.append(pill);
    });
    if($stat.length){
      $stat.text(status.ok ? 'Ready to run' : 'Missing required fields');
      $stat.toggleClass('error', !status.ok);
    }
    return status.ok;
  }
  // For customers, show customer-specific required fields
  if(document.body.classList.contains('mt_primelink-import-customers')){
    const m = collectMappingState().mapping || {};
    const hasEmail = Object.keys(m).some(k => ['email'].includes(k.toLowerCase()) && m[k].source);
    const rows = [
      { key: 'email', label: 'Email', ok: hasEmail, detail: hasEmail ? 'Email mapped' : 'Missing' },
    ];
    $list.empty();
    rows.forEach(r=>{
      const pill = $('<li class="mt_primelink-helper-pill"></li>').addClass(r.ok ? 'ok' : 'missing');
      pill.append('<span>'+escapeHtml(r.label)+'</span>');
      pill.append('<span class="muted">'+escapeHtml(r.detail)+'</span>');
      $list.append(pill);
    });
    if($stat.length){
      $stat.text(status.ok ? 'Ready to run' : 'Missing required fields');
      $stat.toggleClass('error', !status.ok);
    }
    return status.ok;
  }
  
  // For products, show product-specific required fields
  const rows = [
    { key: 'title', label: 'Title or SKU', ok: (status.hasTitle || status.hasSku), detail: status.hasTitle ? 'Title mapped' : (status.hasSku ? 'SKU mapped' : 'Missing both') },
    { key: 'price', label: 'Price', ok: status.hasPrice, detail: status.hasPrice ? 'Price mapped' : 'Missing price (regular/sale/price)' },
  ];
  $list.empty();
  rows.forEach(r=>{
    const pill = $('<li class="mt_primelink-helper-pill"></li>').addClass(r.ok ? 'ok' : 'missing');
    pill.append('<span>'+escapeHtml(r.label)+'</span>');
    pill.append('<span class="muted">'+escapeHtml(r.detail)+'</span>');
    $list.append(pill);
  });
  if($stat.length){
    $stat.text(status.ok ? 'Ready to run' : 'Missing required fields');
    $stat.toggleClass('error', !status.ok);
  }
  return status.ok;
}

function buildSuggestions(fields, item){
  const list = Array.isArray(fields) ? fields : [];
  const lower = list.map(f => ({ name: f, key: f.toLowerCase() }));
  const getVal = (f) => item && Object.prototype.hasOwnProperty.call(item, f) ? item[f] : '';

  const pick = (keywords = [], type) => {
    let best = null;
    lower.forEach(entry => {
      let score = 0;
      keywords.forEach(kw => { if(entry.key.indexOf(kw) !== -1) score += 3; });
      if(type){
        const t = detectValueType(getVal(entry.name));
        if(type === t) score += 2;
      }
      if(score > (best?.score || 0)){
        best = { field: entry.name, score };
      }
    });
    return best ? best.field : '';
  };

  return [
    { target: 'post_title', source: pick(['title','name','productname','nume']), label: 'Title' },
    { target: 'post_content', source: pick(['description','descr','content','longdesc']), label: 'Description' },
    { target: 'sku', source: pick(['sku','code','cod','productcode','item'], 'text'), label: 'SKU' },
    { target: 'price', source: pick(['price','pret','amount','cost','value'], 'number'), label: 'Price' },
    { target: 'regular_price', source: pick(['regular_price','list','standard','pretstandard'], 'number'), label: 'Regular price' },
    { target: 'sale_price', source: pick(['sale','promo','discount'], 'number'), label: 'Sale price' },
    { target: 'avatar', source: pick(['image','img','avatar','thumb','thumbnail','main'], 'url'), label: 'Main image' }
  ].filter(s => s.source);
}

function renderSuggestions(fields, item){
  const $box = $('#mt_primelink-suggestion-list');
  if(!$box.length) return;
  const sugg = buildSuggestions(fields, item);
  if(!sugg.length){
    $box.html('<div class="mt_primelink-helper-pill missing">No suggestions found.</div>');
    return;
  }
  $box.empty();
  sugg.forEach(s => {
    const pill = $('<div class="mt_primelink-helper-pill"></div>');
    pill.append('<span>'+escapeHtml(s.label)+':</span>');
    pill.append('<code>'+escapeHtml(s.source)+'</code>');
    const btn = $('<button type="button" class="button button-small mt_primelink-suggestion-action">Apply</button>');
    btn.data('target', s.target).data('source', s.source);
    pill.append(btn);
    const clr = $('<a href="#" class="mt_primelink-suggestion-clear" aria-label="Clear mapping">&times;</a>');
    clr.data('target', s.target);
    pill.append(clr);
    $box.append(pill);
  });
}

function applyMapping(target, source){
  const $slot = $('.mt_primelink-map-slot[data-target="'+target+'"]');
  if(!$slot.length) return false;
  $slot.find('.mt_primelink-map-input').val(source);
  $slot.find('.mt_primelink-map-drop').html(buildChip(source));
  $slot.find('.mt_primelink-map-edit').prop('disabled', false).addClass('is-visible');
  setSlotBadge($slot, '');
  return true;
}

function buildChip(source){
  const safe = (source === undefined || source === null || source === '') ? '(unknown)' : source;
  return '<span class="mt_primelink-chip" data-source="'+escapeHtml(safe)+'">'+escapeHtml(safe)+' <a href="#" class="mt_primelink-chip-remove" aria-label="Remove">x</a><span class="mt_primelink-chip-edit-label">edit</span></span>';
}

// Read current mapping state from DOM into normalized object
function readCurrentMapping(){
  const mapping = {};

  $('.mt_primelink-map-slot').each(function(){
    const target = $(this).data('target');
    const source = ($(this).find('.mt_primelink-map-input').val() || '').trim();
    let cfg = {};
    try {
      cfg = JSON.parse($(this).find('.mt_primelink-map-config').val() || '{}');
    } catch(e){ cfg = {}; }

    // Only save to mapping if there's actually a source mapped
    // This prevents saving empty mappings that will fail to load later
    if(target && source){
      mapping[target] = { source, ...(cfg || {}) };
    }
  });

  // Attributes
  const attributes = [];
  $('.mt_primelink-attr-row').each(function(){
    const $row = $(this);
    const name = ($row.find('.mt_primelink-attr-name').val() || '').trim();
    const $sourceInput = $row.find('.mt_primelink-attr-source');
    const source = ($sourceInput.val() || '').trim();
    const variation = $row.find('.mt_primelink-attr-variation-toggle').is(':checked');
    const visible   = $row.find('.mt_primelink-attr-visible-toggle').is(':checked');
    
    if(name){
      mapping['attribute:' + name] = { source, variation, visible };
      attributes.push({ name, source, variation, visible });
    }
  });

  // Custom fields
  const customFields = [];
  $('.mt_primelink-custom-field').each(function(){
    const key = $(this).find('.mt_primelink-custom-key').val() || '';
    const field = $(this).find('.mt_primelink-custom-val').val() || '';
    let cfg = {};
    try {
      cfg = JSON.parse($(this).find('.mt_primelink-map-config').val() || '{}');
    } catch(e){ cfg = {}; }
    if(key){
      customFields.push({ key, source: field, ...(cfg || {}) });
    }
  });

  // ACF fields (treated as custom meta; kept separate in state as acf_fields)
  const acfFields = [];
  $('.mt_primelink-acf-field').each(function(){
    const $row = $(this);
    const label = $row.find('.mt_primelink-acf-label').val() || '';
    const key = $row.find('.mt_primelink-acf-key').val() || '';
    const $slot = $row.find('.mt_primelink-map-slot');
    const source = $slot.find('.mt_primelink-map-input').val() || '';
    let cfg = {};
    try {
      cfg = JSON.parse($row.find('.mt_primelink-map-config').val() || '{}');
    } catch(e){ cfg = {}; }
    if(key){
      acfFields.push({ label, key, source, ...(cfg || {}) });
      // Also push into customFields so backend treats them as meta
      customFields.push({ key, source, ...(cfg || {}) });
    }
  });

  return {
    mapping,
    attributes,
    customFields,
    acfFields,
    createVariations: $('#mt_primelink-create-variations').is(':checked'),
    productType: mt_primelinkSelectedProductType
  };
}

function collectMappingState(){
  const state = readCurrentMapping();
  return {
    mapping: state.mapping,
    attributes: state.attributes,
    custom_fields: state.customFields,
    acf_fields: state.acfFields,
    create_variations: state.createVariations,
    product_type: state.productType,
    row_filters: collectFilterRowsData(),
    custom_aliases: collectAliasState(),
    other_options: collectOtherOptions()
  };
}

function setSaveStatus(state, message, withRetry){
  const $status = $('#mt_primelink-save-status');
  if(!$status.length) return;

  $status.removeClass('is-saving is-saved is-error');
  const now = new Date();
  const stamp = now.toLocaleTimeString();

  if(state === 'saving'){
    $status.addClass('is-saving').html('<span class="mt_primelink-save-spinner" aria-hidden="true"></span><span>'+escapeHtml(message || 'Saving...')+'</span>');
    $status.attr('data-tooltip', '');
    return;
  }

  if(state === 'saved'){
    mt_primelinkStep5LastSaveFailed = false;
    $status.addClass('is-saved').text(message || 'Saved');
    $status.attr('data-tooltip', 'Saved at ' + stamp);
    return;
  }

  if(state === 'error'){
    mt_primelinkStep5LastSaveFailed = true;
    $status.addClass('is-error');
    if(withRetry){
      const label = message || 'Save failed';
      $status.html(label + ' <button type="button" class="button-link" id="mt_primelink-save-retry">Retry</button>');
    } else {
      $status.text(message || 'Save failed');
    }
    $status.attr('data-tooltip', '');
    return;
  }

  $status.text('');
  $status.attr('data-tooltip', '');
}

function pushMapHistory(){ /* undo/redo disabled */ }

// Manage recent existing paths (local storage, keep last 3) and server files
function addExistingRecent(path){
  if(!path) return;
  try{
    const key = 'mt_primelink-existing-paths';
    let arr = JSON.parse(localStorage.getItem(key) || '[]');
    arr = arr.filter(p => p !== path);
    arr.unshift(path);
    arr = arr.slice(0,3);
    localStorage.setItem(key, JSON.stringify(arr));
    populateExistingRecent(window._mt_primelinkExistingServerList || []);
  }catch(e){}
}
function populateExistingRecent(serverPaths){
  const $sel = $('#mt_primelink-existing-recent');
  if(!$sel.length) return;
  let arr = [];
  try{
    arr = JSON.parse(localStorage.getItem('mt_primelink-existing-paths') || '[]');
  }catch(e){ arr = []; }
  window._mt_primelinkExistingServerList = Array.isArray(serverPaths) ? serverPaths : (window._mt_primelinkExistingServerList || []);

  let html = '<option value="">Recent...</option>';
  arr.forEach(p=>{
    html += '<option value="'+escapeHtml(p)+'">'+escapeHtml(p)+'</option>';
  });
  if(window._mt_primelinkExistingServerList.length){
    html += '<optgroup label="Uploads">';
    window._mt_primelinkExistingServerList.forEach(item=>{
      const label = (item.path || item).toString();
      const extra = item.size ? ' ('+Math.round(item.size/1024)+' KB, '+(new Date(item.mtime*1000)).toLocaleString()+')' : '';
      html += '<option value="'+escapeHtml(label)+'">'+escapeHtml(label+extra)+'</option>';
    });
    html += '</optgroup>';
  }
  $sel.html(html);
}

async function fetchExistingUploads(){
  try{
    const res = await restGet('/import/uploads?ts=' + Date.now());
    const list = res.files || [];
    populateExistingRecent(list);
  }catch(e){
    populateExistingRecent([]);
  }
}

// Persist step 5 mapping to draft (debounced)
function saveStep5Mapping(immediate){
  if(mt_primelinkStep5SaveTimer){
    clearTimeout(mt_primelinkStep5SaveTimer);
  }

  setSaveStatus('saving');

  const runner = async () => {
    let importId = currentImportId() || parseInt($('.mt_primelink-import-step-5').data('import-id'), 10) || 0;
    if(!importId){
      try{
        const draft = await restPost('/import/create-draft', {});
        importId = draft.import_id || 0;
        if(importId){
          setImportIdEverywhere(importId);
          $('.mt_primelink-import-step-5').attr('data-import-id', importId);
        }
      }catch(e){
        setSaveStatus('error','Import ID missing', true);
        return;
      }
    }
    const payload = collectMappingState();
    try{
      await restPost('/import/save-step', {
        import_id: importId,
        step: 5,
        data: payload
      });
      setSaveStatus('saved');
    } catch(err){
      setSaveStatus('error', err?.json?.message || 'Save failed', true);
    }
  };

  if(immediate){
    return runner();
  }

  mt_primelinkStep5SaveTimer = setTimeout(runner, 100);
}

function renderAttributeRow(name, source, variation){
  name = name || '';
  source = source || '';
  const dropHtml = source
    ? buildChip(source)
    : '<span class="mt_primelink-muted">Drop field here</span>';
  const unmappedClass = source ? '' : ' unmapped';
  return ''
    + '<div class="mt_primelink-attr-row">'
    + '  <div class="mt_primelink-attr-row__header">'
    + '    <input type="text" class="mt_primelink-attr-name" placeholder="Attribute name (e.g. Color)" value="'+escapeHtml(name)+'" />'
    + '    <label class="mt_primelink-attr-variation"><input type="checkbox" class="mt_primelink-attr-visible-toggle" '+(variation?'checked':'')+' /> Visible</label>'
    + '    <label class="mt_primelink-attr-variation"><input type="checkbox" class="mt_primelink-attr-variation-toggle" '+(variation?'checked':'')+' /> Use for variations</label>'
    + '    <button type="button" class="button-link-delete mt_primelink-attr-remove">Remove</button>'
    + '  </div>'
    + '  <div class="mt_primelink-map-slot'+unmappedClass+'">'
    + '    <div class="mt_primelink-map-label">'
    + '      <span class="mt_primelink-map-label__text">'+(name || 'Attribute Values')+'</span>'
    + '      <button type="button" class="button button-small mt_primelink-map-edit mt_primelink-map-edit--inline mt_primelink-attr-edit" '+(source ? '' : 'disabled')+'>Edit</button>'
    + '    </div>'
    + '    <div class="mt_primelink-map-drop mt-map-slot__drop">'+dropHtml+'</div>'
    + '  </div>'
    + '  <input type="hidden" class="mt_primelink-attr-source" value="'+escapeHtml(source)+'" />'
    + '  <input type="hidden" class="mt_primelink-attr-config" value="" />'
    + '</div>';
}


// Step 5 navigator
$(document).on('click', '.mt-map-prev, .mt-map-next', function(e){
  e.preventDefault();
  const idx = parseInt($(this).data('index'), 10) || 0;
  loadMappingPreview(idx);
});

// Field search (Step 5 left list)
$(document).on('input', '#mt_primelink-field-search', function(){
  filterFileFields();
});

// Target search (right side)
$(document).on('input', '#mt_primelink-target-search', function(){
  filterTargetSlots();
});
// Custom fields add/remove
// Add gallery slot
let gallerySlotCounter = 1;

function initGallerySlotsCounter(){
  // Find highest counter from existing slots
  let max = 0;
  $('#mt_primelink-gallery-slots .mt_primelink-map-slot[data-target^="images_"]').each(function(){
    const target = $(this).data('target');
    const match = target.match(/^images_(\d+)$/);
    if(match){
      const num = parseInt(match[1], 10);
      if(num > max) max = num;
    }
  });
  gallerySlotCounter = max + 1;
}

function renderGallerySlot(slotId, index, source, config){
  const $slot = $(`
    <div class="mt_primelink-map-slot" data-target="${slotId}">
      <div class="mt_primelink-map-label">
        <span class="mt_primelink-map-label__text">Images (Gallery) ${index > 0 ? index : ''}</span>
        <button type="button" class="button button-small mt_primelink-map-edit mt_primelink-map-edit--inline" ${source ? '' : 'disabled'}>Edit</button>
        ${index > 0 ? '<button type="button" class="button button-small button-link-delete mt_primelink-remove-gallery-slot" style="margin-left:4px;">Remove</button>' : ''}
      </div>
      <div class="mt_primelink-map-drop mt-map-slot__drop">
        ${source ? `<span class="mt_primelink-mapped-field">${escapeHtml(source)}</span>` : '<span class="mt_primelink-muted">Drop field here</span>'}
      </div>
      <input type="hidden" class="mt_primelink-map-input" name="mapping[${slotId}][source]" value="${escapeHtml(source || '')}" />
      <input type="hidden" class="mt_primelink-map-config" name="mapping[${slotId}][config]" value="${escapeHtml(config || '')}" />
    </div>
  `);
  
  if(source){
    const cfg = config ? JSON.parse(config) : {};
    setSlotConfig($slot, cfg);
    setSlotBadge($slot, cfg.source_mode || 'manual');
    $slot.find('.mt_primelink-map-edit').addClass('is-visible').prop('disabled', false);
  }
  
  return $slot;
}

$(document).on('click', '#mt_primelink-add-gallery-slot', function(){
  const slotId = 'images_' + gallerySlotCounter;
  const index = gallerySlotCounter;
  gallerySlotCounter++;
  
  const $slot = renderGallerySlot(slotId, index, '', '');
  $('#mt_primelink-gallery-slots').append($slot);
  bindDnD();
  saveStep5Mapping();
});

$(document).on('click', '.mt_primelink-remove-gallery-slot', function(){
  if(!confirm('Remove this gallery field?')) return;
  $(this).closest('.mt_primelink-map-slot').remove();
  saveStep5Mapping();
});

// Initialize counter and load existing gallery slots on page load
$(document).ready(function(){
  initGallerySlotsCounter();
  loadExistingGallerySlots();
});

function loadExistingGallerySlots(){
  // Wait for mapping to be loaded
  setTimeout(function(){
    const mapping = collectStep5Mapping();
    if(!mapping) return;
    
    // Find all images_* slots in mapping
    const gallerySlots = [];
    Object.keys(mapping).forEach(target => {
      if(target === 'images' || (target.startsWith('images_') && target !== 'images')){
        const match = target.match(/^images_(\d+)$/);
        const index = match ? parseInt(match[1], 10) : 0;
        gallerySlots.push({ target, index, cfg: mapping[target] });
      }
    });
    
    // Sort by index
    gallerySlots.sort((a, b) => a.index - b.index);
    
    // Remove the default "images" slot if it exists and we have additional slots
    if(gallerySlots.length > 1){
      const defaultSlot = gallerySlots.find(s => s.target === 'images');
      if(defaultSlot){
        const $defaultSlot = $('#mt_primelink-gallery-slots .mt_primelink-map-slot[data-target="images"]');
        if($defaultSlot.length){
          // Keep it, just update label
          $defaultSlot.find('.mt_primelink-map-label__text').text('Images (Gallery)');
        }
      }
    }
    
    // Add additional slots
    gallerySlots.forEach(slot => {
      if(slot.target !== 'images'){
        const $existing = $('#mt_primelink-gallery-slots .mt_primelink-map-slot[data-target="' + slot.target + '"]');
        if(!$existing.length){
          const source = slot.cfg?.source || '';
          const config = slot.cfg ? JSON.stringify(slot.cfg) : '';
          const $slot = renderGallerySlot(slot.target, slot.index, source, config);
          $('#mt_primelink-gallery-slots').append($slot);
          bindDnD();
        }
      }
    });
    
    initGallerySlotsCounter();
  }, 500);
}

function collectStep5Mapping(){
  const mapping = {};
  $('.mt_primelink-map-slot').each(function(){
    const target = $(this).data('target');
    const source = $(this).find('.mt_primelink-map-input').val() || '';
    let cfg = {};
    try {
      cfg = JSON.parse($(this).find('.mt_primelink-map-config').val() || '{}');
    } catch(e){ cfg = {}; }

    if(target && source){
      mapping[target] = { source, ...(cfg || {}) };
    }
  });
  return mapping;
}

$(document).on('click', '#mt_primelink-add-custom-field', function(){
  const i = $('.mt_primelink-custom-field').length;
  const html =
    '<div class="mt_primelink-custom-field" data-index="'+i+'">' +
      '<input type="text" class="mt_primelink-custom-key" placeholder="Meta key" />' +
      '<div class="mt_primelink-map-slot unmapped">' +
        '<div class="mt_primelink-map-drop mt-map-slot__drop"><span class="mt_primelink-muted">Drop field here</span></div>' +
      '</div>' +
      '<input type="hidden" class="mt_primelink-custom-val" value="" />' +
      '<input type="hidden" class="mt_primelink-map-config" value="" />' +
      '<button type="button" class="button-link-delete mt_primelink-custom-remove">Remove</button>' +
    '</div>';
  $('#mt_primelink-custom-fields-wrap').append(html);
  bindDnD();
});

// ACF dynamic fields: label + meta key + drag slot
$(document).on('click', '#mt_primelink-add-acf-field', function(){
  const i = $('.mt_primelink-acf-field').length;
  const html =
    '<div class="mt_primelink-acf-field" data-index="'+i+'">' +
      '<div class="mt_primelink-acf-row">' +
        '<input type="text" class="mt_primelink-acf-label" placeholder="ACF Field Label" />' +
        '<input type="text" class="mt_primelink-acf-key" placeholder="ACF meta key (e.g. field_XXXX or my_field)" />' +
      '</div>' +
      '<div class="mt_primelink-map-slot unmapped" data-target="">' +
        '<div class="mt_primelink-map-drop mt-map-slot__drop"><span class="mt_primelink-muted">Drop field here</span></div>' +
      '</div>' +
      '<input type="hidden" class="mt_primelink-map-input" value="" />' +
      '<input type="hidden" class="mt_primelink-acf-source" value="" />' +
      '<input type="hidden" class="mt_primelink-map-config" value="" />' +
      '<button type="button" class="button-link-delete mt_primelink-acf-remove">Remove</button>' +
    '</div>';
  $('#mt_primelink-acf-fields-wrap').append(html);
  bindDnD();
});

$(document).on('click', '.mt_primelink-acf-remove', function(){
  $(this).closest('.mt_primelink-acf-field').remove();
  pushMapHistory();
  saveStep5Mapping();
});

$(document).on('click', '.mt_primelink-custom-remove', function(){
  $(this).closest('.mt_primelink-custom-field').remove();
  pushMapHistory();
  saveStep5Mapping();
});

// Attribute rows add/remove/toggles
$(document).on('click', '#mt_primelink-add-attribute', function(){
  $('#mt_primelink-attributes-wrap').append(renderAttributeRow('', '', false));
  bindDnD();
  pushMapHistory();
  saveStep5Mapping();
});

$(document).on('click', '.mt_primelink-attr-remove', function(){
  $(this).closest('.mt_primelink-attr-row').remove();
  pushMapHistory();
  saveStep5Mapping();
});

$(document).on('input change', '.mt_primelink-attr-name, .mt_primelink-attr-variation-toggle, #mt_primelink-create-variations', function(){
  // Update label text when attribute name changes
  if($(this).hasClass('mt_primelink-attr-name')){
    const $attrRow = $(this).closest('.mt_primelink-attr-row');
    const name = $(this).val().trim() || 'Attribute Values';
    $attrRow.find('.mt_primelink-map-label__text').text(name);
  }
  saveStep5Mapping();
});

// Product type selector (static vs mapped)
$(document).on('change', '#mt_primelink-product-type-select', function(){
  mt_primelinkSelectedProductType = $(this).val() || 'mapped';
  toggleVariationPanel();
  pushMapHistory();
  saveStep5Mapping();
});

// Product data tabs
$(document).on('click', '.mt_primelink-pd-tab', function(){
  const tab = $(this).data('tab');
  $('.mt_primelink-pd-tab').removeClass('is-active');
  $(this).addClass('is-active');
  $('.mt_primelink-pd-panel').removeClass('is-active');
  $('.mt_primelink-pd-panel[data-panel="'+tab+'"]').addClass('is-active');
});

function toggleVariationPanel(){
  const type = mt_primelinkSelectedProductType;
  const $tab = $('.mt_primelink-pd-tab[data-tab="variations"]');
  const $panel = $('.mt_primelink-pd-panel[data-panel="variations"]');
  const allow = (type === 'variable' || type === 'grouped' || type === 'mapped');
  $tab.toggle(allow);
  $panel.toggle(allow);
  if(!allow && $tab.hasClass('is-active')){
    $('.mt_primelink-pd-tab[data-tab="general"]').trigger('click');
  }
}

// Auto-save when leaving inputs
$(document).on('change blur', '.mt_primelink-map-input, .mt_primelink-custom-key', function(){
  pushMapHistory();
  saveStep5Mapping();
});

// Retry save (step 5)
$(document).on('click', '#mt_primelink-save-retry', function(e){
  e.preventDefault();
  setSaveStatus('saving');
  saveStep5Mapping(true);
});

// Other options autosave
$(document).on('input change', '#mt_primelink-opt-global-prefix, #mt_primelink-opt-global-suffix, #mt_primelink-opt-global-trim, #mt_primelink-opt-slugify, #mt_primelink-opt-fallback-image, #mt_primelink-opt-skip-field', function(){
  saveStep5Mapping();
});


  // Step 5 navigator (vertical preview)
  $(document).on('click', '.mt-map-prev, .mt-map-next', function(e){
    e.preventDefault();
    const idx = parseInt($(this).data('index'), 10) || 0;
    loadMappingPreview(idx);
  });

  // -----------------------------
// Step 5 Advanced Field Editor
// -----------------------------

function getSlotConfig($slot){
  const raw = $slot.find('.mt_primelink-map-config').val();
  if(!raw) return {};
  try { return JSON.parse(raw); } catch(e){ return {}; }
}

function applySeparator(value, separator){
  if(!separator) return value;
  const parts = String(value).split(separator).map(v => v.trim()).filter(Boolean);
  return parts.length > 1 ? parts : value;
}


function setSlotConfig($slot, cfg){
  $slot.find('.mt_primelink-map-config').val(JSON.stringify(cfg || {}));
}

function setSlotBadge($slot, mode){
  $slot.removeClass('is-auto is-manual');
  let $badge = $slot.find('.mt_primelink-map-badge');
  if(!mode){
    $badge.remove();
    return;
  }
  if(!$badge.length){
    $badge = $('<span class="mt_primelink-map-badge"></span>');
    $slot.prepend($badge);
  }
  const label = mode === 'auto' ? 'Auto' : 'Manual';
  $badge.text(label);
  $slot.addClass(mode === 'auto' ? 'is-auto' : 'is-manual');
}

function syncSlotBadges(){
  $('.mt_primelink-map-slot').each(function(){
    const cfg = getSlotConfig($(this));
    const source = $(this).find('.mt_primelink-map-input').val();
    const mode = cfg.source_mode || (source ? 'manual' : '');
    setSlotBadge($(this), mode);
  });
}

function openEditor($slot, selectedSource){
  const target = $slot.data('target');
  let source = $slot.find('.mt_primelink-map-input').val() || '';
  let cfg    = getSlotConfig($slot);

  // If a specific chip was clicked (gallery), set it as primary in the editor
  if(selectedSource){
    const extras = Array.isArray(cfg.extra_sources) ? cfg.extra_sources.slice() : [];
    const all = [source].concat(extras).filter(Boolean);
    if(all.includes(selectedSource)){
      const others = all.filter(f => f !== selectedSource);
      source = selectedSource;
      cfg.extra_sources = others;
    }
  }

  $('#mt_primelink-editor-target').val(target);
  $('#mt_primelink-editor-source').val(source);
  $('#mt_primelink-editor-column-header').val(cfg.column_header || '');
  $('#mt_primelink-editor-prefix').val(cfg.prefix || '');
  $('#mt_primelink-editor-suffix').val(cfg.suffix || '');

  $('#mt_primelink-editor-separator').val(cfg.separator || '');
  $('#mt_primelink-editor-default').val(cfg.default || '');
  $('#mt_primelink-editor-template').val(cfg.template || '');
  const mode = cfg.template_mode || 'before';
  $('input[name="mt_primelink-editor-template-mode"][value="'+mode+'"]').prop('checked', true);

  // Basic transforms
  $('#mt_primelink-editor-trim').prop('checked', cfg.transforms?.trim !== false);
  $('#mt_primelink-editor-lowercase').prop('checked', !!cfg.transforms?.lowercase);
  $('#mt_primelink-editor-uppercase').prop('checked', !!cfg.transforms?.uppercase);
  $('#mt_primelink-editor-capitalize').prop('checked', !!cfg.transforms?.capitalize);
  $('#mt_primelink-editor-title-case').prop('checked', !!cfg.transforms?.title_case);
  $('#mt_primelink-editor-normalize-html').prop('checked', !!cfg.transforms?.normalize_html);
  
  // Advanced transforms
  $('#mt_primelink-editor-remove-accents').prop('checked', !!cfg.transforms?.remove_accents);
  $('#mt_primelink-editor-slugify').prop('checked', !!cfg.transforms?.slugify);
  $('#mt_primelink-editor-extract-numbers').prop('checked', !!cfg.transforms?.extract_numbers);
  $('#mt_primelink-editor-extract-text').prop('checked', !!cfg.transforms?.extract_text);
  $('#mt_primelink-editor-url-encode').prop('checked', !!cfg.transforms?.url_encode);
  $('#mt_primelink-editor-url-decode').prop('checked', !!cfg.transforms?.url_decode);
  
  // Number transforms
  $('#mt_primelink-editor-round').prop('checked', !!cfg.transforms?.round);
  $('#mt_primelink-editor-round-decimals').val(cfg.transforms?.round_decimals ?? 2);
  $('#mt_primelink-editor-ceil').prop('checked', !!cfg.transforms?.ceil);
  $('#mt_primelink-editor-floor').prop('checked', !!cfg.transforms?.floor);
  $('#mt_primelink-editor-number-format').val(cfg.transforms?.number_format || '');
  
  // String operations
  $('#mt_primelink-editor-substring-start').val(cfg.transforms?.substring_start ?? '');
  $('#mt_primelink-editor-substring-length').val(cfg.transforms?.substring_length ?? '');
  $('#mt_primelink-editor-pad-side').val(cfg.transforms?.pad_side || '');
  $('#mt_primelink-editor-pad-length').val(cfg.transforms?.pad_length ?? '');
  $('#mt_primelink-editor-pad-char').val(cfg.transforms?.pad_char || '');
  
  // Date transforms
  $('#mt_primelink-editor-date-format').val(cfg.transforms?.date_format || '');
  $('#mt_primelink-editor-date-output').val(cfg.transforms?.date_output || '');
  
  // Regex
  $('#mt_primelink-editor-regex-pattern').val(cfg.transforms?.regex_pattern || '');
  $('#mt_primelink-editor-regex-replacement').val(cfg.transforms?.regex_replacement || '');

  // Replace rules
  const repWrap = $('#mt_primelink-editor-replace-wrap').empty();
  (cfg.transforms?.replace || []).forEach((r)=>{
    repWrap.append(renderReplaceRow(r.from || '', r.to || ''));
  });

  // Price adjust (only for price targets)
  const isPriceTarget = ['price','regular_price','sale_price'].includes((target||'').toLowerCase());
  if(isPriceTarget){
    $('.mt_primelink-price-adjust-row').show();
    const pa = cfg.price_adjust || {};
    $('#mt_primelink-price-adjust-type').val(pa.type || '');
    $('#mt_primelink-price-adjust-amount').val(pa.amount !== undefined ? pa.amount : '');
  } else {
    $('.mt_primelink-price-adjust-row').hide();
  }

  // Conditions
  const condWrap = $('#mt_primelink-editor-conditions-wrap').empty();
  (cfg.conditions || []).forEach((c)=>{
    condWrap.append(renderConditionRow(c.field || '', c.op || '=', c.value || ''));
  });

  // Gallery extra sources are now handled automatically via drag & drop
  // Removed manual input field

  const $editor = $('#mt_primelink-map-editor');
  $('body').append($editor);
  $editor.addClass('is-open').fadeIn(120);
  $('body').addClass('mt_primelink-editor-open');
}

function closeEditor(){
  $('#mt_primelink-map-editor').removeClass('is-open').fadeOut(120);
  $('body').removeClass('mt_primelink-editor-open');
}

function renderReplaceRow(from, to){
  return `
    <div class="mt_primelink-editor-row mt_primelink-replace-row">
      <input type="text" class="mt_primelink-replace-from" placeholder="from" value="${escapeHtml(from)}" />
      <input type="text" class="mt_primelink-replace-to" placeholder="to" value="${escapeHtml(to)}" />
      <button type="button" class="button-link-delete mt_primelink-replace-remove">Remove</button>
    </div>
  `;
}

function renderConditionRow(field, op, value){
  return `
    <div class="mt_primelink-editor-row mt_primelink-condition-row">
      <input type="text" class="mt_primelink-cond-field" placeholder="field" value="${escapeHtml(field)}" />
      <select class="mt_primelink-cond-op">
        <option value="=" ${op==='='?'selected':''}>=</option>
        <option value="!=" ${op==='!='?'selected':''}>!=</option>
        <option value=">" ${op==='>'?'selected':''}>&gt;</option>
        <option value="<" ${op==='<'?'selected':''}>&lt;</option>
        <option value="contains" ${op==='contains'?'selected':''}>contains</option>
      </select>
      <input type="text" class="mt_primelink-cond-value" placeholder="value" value="${escapeHtml(value)}" />
      <button type="button" class="button-link-delete mt_primelink-cond-remove">Remove</button>
    </div>
  `;
}

// Enable edit after drop
function enableEditButton($slot){
  $slot.find('.mt_primelink-map-edit').prop('disabled', false);
}

// Hook into your existing drop handler:
$(document).on('drop', '.mt-map-slot__drop', function(){
  enableEditButton($(this).closest('.mt_primelink-map-slot'));
});

// Edit click
$(document).on('click', '.mt_primelink-map-edit', function(){
  const $slot = $(this).closest('.mt_primelink-map-slot');
  openEditor($slot);
});

// Handle Edit button for attributes
$(document).on('click', '.mt_primelink-attr-edit', function(){
  const $attr = $(this).closest('.mt_primelink-attr-row');
  if($attr.length){
    openAttributeEditor($attr);
  }
});

$(document).on('click', '.mt_primelink-map-editor-close', closeEditor);

// Add replace / condition rows
$(document).on('click', '#mt_primelink-editor-add-replace', function(){
  $('#mt_primelink-editor-replace-wrap').append(renderReplaceRow('', ''));
});
$(document).on('click', '.mt_primelink-replace-remove', function(){
  $(this).closest('.mt_primelink-replace-row').remove();
});

$(document).on('click', '#mt_primelink-editor-add-condition', function(){
  $('#mt_primelink-editor-conditions-wrap').append(renderConditionRow('', '=', ''));
});
$(document).on('click', '.mt_primelink-cond-remove', function(){
  $(this).closest('.mt_primelink-condition-row').remove();
});

// Save editor state into slot + autosave step5
$(document).on('click', '#mt_primelink-editor-save', function(){
  const target = $('#mt_primelink-editor-target').val();
  const $slot  = $('.mt_primelink-map-slot[data-target="'+target+'"]');
  const $attr  = $('#mt_primelink-map-editor').data('attr-row');

  // Handle attribute rows
  if($attr && $attr.length){
    const newSource = $('#mt_primelink-editor-source').val().trim();
    if(newSource){
      $attr.find('.mt_primelink-attr-source').val(newSource);
      // Update the drop zone display
      const $drop = $attr.find('.mt-map-slot__drop');
      $drop.html(buildChip(newSource));
      // Enable Edit button
      $attr.find('.mt_primelink-attr-edit').prop('disabled', false).addClass('is-visible');
    }

    const cfg = {
      column_header: ($('#mt_primelink-editor-column-header').val() || '').trim(),
      separator: ($('#mt_primelink-editor-separator').val() || '').trim(),
      default: ($('#mt_primelink-editor-default').val() || '').trim(),
      prefix: ($('#mt_primelink-editor-prefix').val() || '').trim(),
      suffix: ($('#mt_primelink-editor-suffix').val() || '').trim(),
      template: $('#mt_primelink-editor-template').val(),
      template_mode: $('input[name="mt_primelink-editor-template-mode"]:checked').val() || 'before',
      transforms: {
        trim: $('#mt_primelink-editor-trim').is(':checked'),
        lowercase: $('#mt_primelink-editor-lowercase').is(':checked'),
        uppercase: $('#mt_primelink-editor-uppercase').is(':checked'),
        capitalize: $('#mt_primelink-editor-capitalize').is(':checked'),
        title_case: $('#mt_primelink-editor-title-case').is(':checked'),
        normalize_html: $('#mt_primelink-editor-normalize-html').is(':checked'),
        remove_accents: $('#mt_primelink-editor-remove-accents').is(':checked'),
        slugify: $('#mt_primelink-editor-slugify').is(':checked'),
        extract_numbers: $('#mt_primelink-editor-extract-numbers').is(':checked'),
        extract_text: $('#mt_primelink-editor-extract-text').is(':checked'),
        url_encode: $('#mt_primelink-editor-url-encode').is(':checked'),
        url_decode: $('#mt_primelink-editor-url-decode').is(':checked'),
        round: $('#mt_primelink-editor-round').is(':checked'),
        round_decimals: parseInt($('#mt_primelink-editor-round-decimals').val()) || 2,
        ceil: $('#mt_primelink-editor-ceil').is(':checked'),
        floor: $('#mt_primelink-editor-floor').is(':checked'),
        number_format: $('#mt_primelink-editor-number-format').val() || '',
        substring_start: $('#mt_primelink-editor-substring-start').val() || '',
        substring_length: $('#mt_primelink-editor-substring-length').val() || '',
        pad_side: $('#mt_primelink-editor-pad-side').val() || '',
        pad_length: parseInt($('#mt_primelink-editor-pad-length').val()) || 0,
        pad_char: $('#mt_primelink-editor-pad-char').val() || '',
        date_format: $('#mt_primelink-editor-date-format').val() || '',
        date_output: $('#mt_primelink-editor-date-output').val() || '',
        regex_pattern: $('#mt_primelink-editor-regex-pattern').val() || '',
        regex_replacement: $('#mt_primelink-editor-regex-replacement').val() || '',
        replace: []
      },
      conditions: []
    };

    // Collect replace rules
    $('#mt_primelink-editor-replace-wrap .mt_primelink-replace-row').each(function(){
      const from = $(this).find('.mt_primelink-replace-from').val().trim();
      const to = $(this).find('.mt_primelink-replace-to').val().trim();
      if(from || to){
        cfg.transforms.replace.push({from, to});
      }
    });

    // Collect conditions
    $('#mt_primelink-editor-conditions-wrap .mt_primelink-condition-row').each(function(){
      const field = $(this).find('.mt_primelink-cond-field').val().trim();
      const op = $(this).find('.mt_primelink-cond-op').val();
      const value = $(this).find('.mt_primelink-cond-value').val().trim();
      if(field){
        cfg.conditions.push({field, op, value});
      }
    });

    $attr.find('.mt_primelink-attr-config').val(JSON.stringify(cfg));
    pushMapHistory();
    saveStep5Mapping();
    closeEditor();
    return;
  }

  if(!$slot.length){
    closeEditor();
    return;
  }

  const newSource = $('#mt_primelink-editor-source').val().trim();
  if(newSource){
    $slot.find('.mt_primelink-map-input').val(newSource);
  }

  const cfg = {
    column_header: ($('#mt_primelink-editor-column-header').val() || '').trim(),
    separator: ($('#mt_primelink-editor-separator').val() || '').trim(),
    default: ($('#mt_primelink-editor-default').val() || '').trim(),
    prefix: ($('#mt_primelink-editor-prefix').val() || '').trim(),
    suffix: ($('#mt_primelink-editor-suffix').val() || '').trim(),
    template: $('#mt_primelink-editor-template').val(),
    template_mode: $('input[name="mt_primelink-editor-template-mode"]:checked').val() || 'before',
    transforms: {
      trim: $('#mt_primelink-editor-trim').is(':checked'),
      lowercase: $('#mt_primelink-editor-lowercase').is(':checked'),
      uppercase: $('#mt_primelink-editor-uppercase').is(':checked'),
      capitalize: $('#mt_primelink-editor-capitalize').is(':checked'),
      title_case: $('#mt_primelink-editor-title-case').is(':checked'),
      normalize_html: $('#mt_primelink-editor-normalize-html').is(':checked'),
      remove_accents: $('#mt_primelink-editor-remove-accents').is(':checked'),
      slugify: $('#mt_primelink-editor-slugify').is(':checked'),
      extract_numbers: $('#mt_primelink-editor-extract-numbers').is(':checked'),
      extract_text: $('#mt_primelink-editor-extract-text').is(':checked'),
      url_encode: $('#mt_primelink-editor-url-encode').is(':checked'),
      url_decode: $('#mt_primelink-editor-url-decode').is(':checked'),
      round: $('#mt_primelink-editor-round').is(':checked'),
      round_decimals: parseInt($('#mt_primelink-editor-round-decimals').val()) || 2,
      ceil: $('#mt_primelink-editor-ceil').is(':checked'),
      floor: $('#mt_primelink-editor-floor').is(':checked'),
      number_format: $('#mt_primelink-editor-number-format').val() || '',
      substring_start: $('#mt_primelink-editor-substring-start').val() || '',
      substring_length: $('#mt_primelink-editor-substring-length').val() || '',
      pad_side: $('#mt_primelink-editor-pad-side').val() || '',
      pad_length: parseInt($('#mt_primelink-editor-pad-length').val()) || 0,
      pad_char: $('#mt_primelink-editor-pad-char').val() || '',
      date_format: $('#mt_primelink-editor-date-format').val() || '',
      date_output: $('#mt_primelink-editor-date-output').val() || '',
      regex_pattern: $('#mt_primelink-editor-regex-pattern').val() || '',
      regex_replacement: $('#mt_primelink-editor-regex-replacement').val() || '',
      replace: []
    },
    conditions: []
  };

  const paType = $('#mt_primelink-price-adjust-type').val() || '';
  const paAmount = parseFloat($('#mt_primelink-price-adjust-amount').val());
  if(paType && !isNaN(paAmount)){
    cfg.price_adjust = { type: paType, amount: paAmount };
  }

  // Collect replace rules
  $('#mt_primelink-editor-replace-wrap .mt_primelink-replace-row').each(function(){
    const from = $(this).find('.mt_primelink-replace-from').val();
    const to   = $(this).find('.mt_primelink-replace-to').val();
    if(from !== '') cfg.transforms.replace.push({from, to});
  });

  // Collect conditions
  $('#mt_primelink-editor-conditions-wrap .mt_primelink-condition-row').each(function(){
    const field = $(this).find('.mt_primelink-cond-field').val().trim();
    const op    = $(this).find('.mt_primelink-cond-op').val();
    const value = $(this).find('.mt_primelink-cond-value').val().trim();
    if(field !== '') cfg.conditions.push({field, op, value});
  });

  // Gallery extra sources are now handled automatically via drag & drop
  // No need to read from manual input field - extra_sources are set when dragging multiple fields to gallery slot
  const existingCfg = getSlotConfig($slot);
  cfg.source_mode = existingCfg.source_mode || 'manual';

  setSlotConfig($slot, cfg);
  setSlotBadge($slot, cfg.source_mode || "manual");
  
  // Update custom column name display if this is a custom column
  if(target && target.startsWith('custom_column_')){
    const columnName = cfg.column_header || target;
    const $labelText = $slot.find('.mt_primelink-map-label__text[data-editable="true"]');
    if($labelText.length){
      $labelText.text(columnName);
      $slot.find('.mt_primelink-custom-column-name').val(columnName);
    }
  }
  
  // Save mapping (works for both import and export)
  if(typeof saveStep5Mapping === 'function'){
    saveStep5Mapping();
  }
  if(typeof saveExportStep2Mapping === 'function'){
    saveExportStep2Mapping();
  }
  
  if(typeof loadMappingPreview === 'function'){
    loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
  }
  if(typeof loadExportPreview === 'function'){
    loadExportPreview();
  }
  closeEditor();
});

// -----------------------------
// Step 5 Templates (Save/Load/List/Delete)
// -----------------------------

/**
 * Get import type from draft, URL, or body class (in that order of priority)
 * @returns {Promise<string>} Import type: 'product', 'order', 'customer', or 'coupon'
 */
async function getImportType(){
  const importId = currentImportId();
  
  // First, try to get from draft (most reliable)
  if(importId && importId > 0){
    try {
      const draft = await restPost('/import/get-draft', { import_id: importId });
      if(draft && draft.draft){
        let type = draft.draft.type || (draft.draft.step_data && draft.draft.step_data[1] && draft.draft.step_data[1].type);
        if(type){
          // Normalize plural to singular
          if(type === 'orders') type = 'order';
          else if(type === 'customers') type = 'customer';
          else if(type === 'coupons') type = 'coupon';
          else if(type === 'products') type = 'product';
          else if(type === 'categories') type = 'category';
          else if(type === 'tags') type = 'tag';
          if(['product', 'order', 'customer', 'coupon', 'category', 'tag'].includes(type)){
            return type;
          }
        }
      }
    } catch(e){
      // Draft fetch failed (404 or other error), continue to fallbacks silently
      // Don't log or show error - this is expected when draft doesn't exist yet
    }
  }
  
  // Fallback to URL parameter
  const url = new URL(window.location.href);
  let importType = url.searchParams.get('import_type') || '';
  
  // Normalize plural to singular (orders -> order, customers -> customer, coupons -> coupon, products -> product, categories -> category)
  if(importType === 'orders'){
    importType = 'order';
  } else if(importType === 'customers'){
    importType = 'customer';
  } else if(importType === 'coupons'){
    importType = 'coupon';
  } else if(importType === 'products'){
    importType = 'product';
  } else if(importType === 'categories'){
    importType = 'category';
  } else if(importType === 'tags'){
    importType = 'tag';
  } else if(importType === 'attributes'){
    importType = 'attribute';
        } else if(importType === 'variations'){
          importType = 'variation';
        } else if(importType === 'reviews'){
          importType = 'review';
        }

        if(['product', 'order', 'customer', 'coupon', 'category', 'tag', 'attribute', 'variation', 'review'].includes(importType)){
    return importType;
  }
  
  // Fallback to body class
  if(document.body.classList.contains('mt_primelink-import-orders')){
    return 'order';
  } else if(document.body.classList.contains('mt_primelink-import-customers')){
    return 'customer';
  } else if(document.body.classList.contains('mt_primelink-import-coupons')){
    return 'coupon';
  } else if(document.body.classList.contains('mt_primelink-import-categories')){
    return 'category';
  } else if(document.body.classList.contains('mt_primelink-import-tags')){
    return 'tag';
  }
  
  // Default to product
  return 'product';
}

async function getExportType(){
  // First, try URL parameter (most immediate)
  const url = new URL(window.location.href);
  let exportType = url.searchParams.get('export_type') || '';
  
  // Normalize plural to singular (orders -> order, customers -> customer, coupons -> coupon, products -> product, categories -> category, tags -> tag, etc.)
  if(exportType === 'orders'){
    exportType = 'order';
  } else if(exportType === 'customers'){
    exportType = 'customer';
  } else if(exportType === 'coupons'){
    exportType = 'coupon';
  } else if(exportType === 'products'){
    exportType = 'product';
  } else if(exportType === 'categories'){
    exportType = 'category';
  } else if(exportType === 'tags'){
    exportType = 'tag';
  } else if(exportType === 'attributes'){
    exportType = 'attribute';
  } else if(exportType === 'variations'){
    exportType = 'variation';
  } else if(exportType === 'reviews'){
    exportType = 'review';
  } else if(exportType === 'downloads'){
    exportType = 'download';
  }
  
  if(['product', 'order', 'customer', 'coupon', 'category', 'tag', 'attribute', 'variation', 'review', 'download'].includes(exportType)){
    return exportType;
  }
  
  // Second, try to get from draft
  const exportId = currentExportId();
  if(exportId){
    try {
      const draft = await restPost('/export/get-draft', { export_id: exportId });
      if(draft && draft.draft){
        let type = draft.draft.type || (draft.draft.step_data && draft.draft.step_data[1] && draft.draft.step_data[1].export_type);
        if(type){
          // Normalize plural to singular
          if(type === 'orders') type = 'order';
          else if(type === 'customers') type = 'customer';
          else if(type === 'coupons') type = 'coupon';
          else if(type === 'products') type = 'product';
          else if(type === 'categories') type = 'category';
          else if(type === 'tags') type = 'tag';
          else if(type === 'attributes') type = 'attribute';
          else if(type === 'variations') type = 'variation';
          else if(type === 'reviews') type = 'review';
          else if(type === 'downloads') type = 'download';

          if(['product', 'order', 'customer', 'coupon', 'category', 'tag', 'attribute', 'variation', 'review', 'download'].includes(type)){
            return type;
          }
        }
      }
    } catch(e){
      // Draft fetch failed, continue to fallbacks
    }
  }
  
  // Fallback to hidden input field (from step-1.php templates)
  const $typeInput = $('#mt-primelink-export-type');
  if($typeInput.length){
    let type = ($typeInput.val() || '').trim();
    if(type){
      // Normalize plural to singular
      if(type === 'orders') type = 'order';
      else if(type === 'customers') type = 'customer';
      else if(type === 'coupons') type = 'coupon';
      else if(type === 'products') type = 'product';
      else if(type === 'categories') type = 'category';
      else if(type === 'tags') type = 'tag';
      else if(type === 'attributes') type = 'attribute';
      else if(type === 'variations') type = 'variation';
      else if(type === 'reviews') type = 'review';
      else if(type === 'downloads') type = 'download';

      if(['product', 'order', 'customer', 'coupon', 'category', 'tag', 'attribute', 'variation', 'review', 'download'].includes(type)){
        return type;
      }
    }
  }
  
  // Fallback to body class
  if(document.body.classList.contains('mt_primelink-export-orders')){
    return 'order';
  } else if(document.body.classList.contains('mt_primelink-export-customers')){
    return 'customer';
  } else if(document.body.classList.contains('mt_primelink-export-coupons')){
    return 'coupon';
  } else if(document.body.classList.contains('mt_primelink-export-categories')){
    return 'category';
  } else if(document.body.classList.contains('mt_primelink-export-tags')){
    return 'tag';
  } else if(document.body.classList.contains('mt_primelink-export-attributes')){
    return 'attribute';
  } else if(document.body.classList.contains('mt_primelink-export-variations')){
    return 'variation';
  } else if(document.body.classList.contains('mt_primelink-export-reviews')){
    return 'review';
  } else if(document.body.classList.contains('mt_primelink-export-downloads')){
    return 'download';
  }
  
  // Fallback to data attribute from wizard
  const $dataAttr = $('[data-export-type]');
  if($dataAttr.length){
    let type = $dataAttr.data('export-type') || $dataAttr.attr('data-export-type') || '';
    if(type){
      // Normalize plural to singular
      if(type === 'orders') type = 'order';
      else if(type === 'customers') type = 'customer';
      else if(type === 'coupons') type = 'coupon';
      else if(type === 'products') type = 'product';
      else if(type === 'categories') type = 'category';
      else if(type === 'tags') type = 'tag';
      if(['product', 'order', 'customer', 'coupon', 'category', 'tag'].includes(type)){
        return type;
      }
    }
  }
  
  // Default to product
  return 'product';
}

// Prevent multiple simultaneous calls to refreshTemplateList
let refreshTemplateListInProgress = false;

async function refreshTemplateList(selectNameToKeep){
  const $select = $('#mt_primelink-load-template');
  if(!$select.length) {
    return;
  }

  // Prevent concurrent calls
  if(refreshTemplateListInProgress){
    return;
  }

  refreshTemplateListInProgress = true;

  try {
    // Get import type to filter templates
    const importType = await getImportType();
    
    // If importType is undefined or empty, don't make the request (would return all templates)
    if(!importType || importType === ''){
      refreshTemplateListInProgress = false;
      return;
    }

    // Request both templates and imports filtered by type
    const [templatesRes, importsRes] = await Promise.all([
      restGet('/import/templates?type=' + encodeURIComponent(importType) + '&ts=' + Date.now()).catch(() => ({ templates: [] })),
      restGet('/import/list?type=' + encodeURIComponent(importType) + '&ts=' + Date.now()).catch(() => ({ imports: [] }))
    ]);
    
    const templateNames = templatesRes.templates || [];
    const imports = importsRes.imports || [];

    let html = '<option value="">Load existing template or import...</option>';
    
    // Add templates section
    if(templateNames.length > 0){
      html += '<optgroup label="Templates">';
      templateNames.forEach(n=>{
        // Remove prefix for display (support all types)
        const displayName = n.replace(/^(order|product|customer|coupon|category|tag|attribute|variation|review|download):/, '');
        html += '<option value="template:'+escapeHtml(n)+'">📋 '+escapeHtml(displayName)+'</option>';
      });
      html += '</optgroup>';
    }
    
    // Add imports section
    if(imports.length > 0){
      html += '<optgroup label="Imports">';
      imports.forEach(imp=>{
        html += '<option value="import:'+escapeHtml(imp.id)+'">🔄 '+escapeHtml(imp.display_name)+'</option>';
      });
      html += '</optgroup>';
    }

    $select.html(html);

    if(selectNameToKeep){
      $select.val(selectNameToKeep);
    }
  } catch(e){
    // If list fails, keep current options
  } finally {
    refreshTemplateListInProgress = false;
  }
}

function applyTemplateToUI(data){
  if(!data || typeof data !== 'object') {
    return;
  }

  const mapping = data.mapping || {};
  const other = data.other_options || {};

  // CRITICAL: Open all accordions and tabs BEFORE applying mapping
  // This ensures all slots are in DOM and visible when we apply the template
  $('details.mt_primelink-accordion').attr('open', true);
  
  // Open all product data tabs
  $('.mt_primelink-pd-tab').each(function(){
    const tabName = $(this).data('tab');
    if(tabName){
      $(this).addClass('is-active').trigger('click');
      $('.mt_primelink-pd-panel[data-panel="' + tabName + '"]').addClass('is-active');
    }
  });
  
  // Force all panels to be visible
  $('.mt_primelink-pd-panel').addClass('is-active');

  // Apply normal slots - use a more robust selector that finds ALL slots, even in closed accordions
  const allSlots = $('.mt_primelink-map-slot');
  
  allSlots.each(function(){
    const $slot = $(this);
    const target = $slot.data('target');
    
    if(!target) {
      return; // Skip slots without target (like ACF fields)
    }
    
    const cfg = mapping[target] || null;

    const $drop  = $slot.find('.mt-map-slot__drop');
    const $input = $slot.find('.mt_primelink-map-input');
    const $conf  = $slot.find('.mt_primelink-map-config');
    const $edit  = $slot.find('.mt_primelink-map-edit');

    if(cfg && cfg.source){
      const chips = [cfg.source].concat(Array.isArray(cfg.extra_sources) ? cfg.extra_sources : []).filter(Boolean).map(buildChip).join(' ');
      $drop.html(chips || buildChip(cfg.source));
      $input.val(cfg.source);
      $conf.val(JSON.stringify(cfg));
      $edit.prop('disabled', false).addClass('is-visible');
      $slot.removeClass('unmapped');
      setSlotBadge($slot, cfg.source_mode || 'manual');
    } else {
      // Only clear if we have mapping data but this target is not in it
      // Don't clear if mapping is empty (might be loading)
      if(Object.keys(mapping).length > 0){
        $drop.html('<span class="mt_primelink-muted">Drop field here</span>');
        $input.val('');
        $conf.val('');
        $edit.prop('disabled', true).removeClass('is-visible');
        setSlotBadge($slot, '');
      }
    }
  });

  // Attributes (rebuild from mapping keys)
  const attrWrap = $('#mt_primelink-attributes-wrap').empty();
  let attrCount = 0;
  Object.keys(mapping || {}).forEach(key => {
    if(key.indexOf('attribute:') === 0){
      const name = key.substring(10);
      const cfg  = mapping[key] || {};
      attrWrap.append(renderAttributeRow(name, cfg.source || '', !!cfg.variation));
      attrCount++;
    }
  });
  if(!attrCount && Array.isArray(data.attributes)){
    data.attributes.forEach(a=>{
      attrWrap.append(renderAttributeRow(a.name || '', a.source || '', !!a.variation));
    });
  }
  $('#mt_primelink-create-variations').prop('checked', !!data.create_variations);
  // Product type select
  const pt = data.product_type || (mapping.product_type && mapping.product_type.constant ? mapping.product_type.constant : 'simple');
  mt_primelinkSelectedProductType = pt || 'simple';
  $('#mt_primelink-product-type-select').val(mt_primelinkSelectedProductType);

  // Gallery slots (rebuild additional slots)
  const gallerySlotsWrap = $('#mt_primelink-gallery-slots');
  if(gallerySlotsWrap.length){
    // Find all images_* slots in mapping
    Object.keys(mapping || {}).forEach(target => {
      if(target.startsWith('images_') && target !== 'images'){
        const match = target.match(/^images_(\d+)$/);
        if(match){
          const index = parseInt(match[1], 10);
          const cfg = mapping[target] || {};
          const $existing = gallerySlotsWrap.find('.mt_primelink-map-slot[data-target="' + target + '"]');
          if(!$existing.length){
            const $slot = renderGallerySlot(target, index, cfg.source || '', cfg ? JSON.stringify(cfg) : '');
            gallerySlotsWrap.append($slot);
            bindDnD();
          }
        }
      }
    });
    initGallerySlotsCounter();
  }

  // Custom fields (rebuild)
  const customWrap = $('#mt_primelink-custom-fields-wrap').empty();
  (data.custom_fields || []).forEach(cf=>{
    const hasSource = cf.source && cf.source.trim();
    const unmappedClass = hasSource ? '' : ' unmapped';
    const dropHtml = hasSource
      ? buildChip(cf.source)
      : '<span class="mt_primelink-muted">Drop field here</span>';
    const html =
      '<div class="mt_primelink-custom-field">' +
        '<input type="text" class="mt_primelink-custom-key" placeholder="Meta key" value="'+escapeHtml(cf.key || '')+'" />' +
        '<div class="mt_primelink-map-slot'+unmappedClass+'">' +
          '<div class="mt_primelink-map-drop mt-map-slot__drop">' + dropHtml + '</div>' +
        '</div>' +
        '<input type="hidden" class="mt_primelink-map-input" value="'+escapeHtml(cf.source || '')+'" />' +
        '<input type="hidden" class="mt_primelink-custom-val" value="'+escapeHtml(cf.source || '')+'" />' +
        '<input type="hidden" class="mt_primelink-map-config" value="'+escapeHtml(JSON.stringify(cf || {}))+'" />' +
        '<button type="button" class="button-link-delete mt_primelink-custom-remove">Remove</button>' +
      '</div>';
    customWrap.append(html);
  });

// ACF fields (rebuild)
const acfWrap = $('#mt_primelink-acf-fields-wrap').empty();
(data.acf_fields || []).forEach((acf, index)=>{
  const hasSource = acf.source && acf.source.trim();
  const unmappedClass = hasSource ? '' : ' unmapped';
  const dropHtml = hasSource
    ? buildChip(acf.source)
    : '<span class="mt_primelink-muted">Drop field here</span>';
  // Use acf directly for config, not acf.config (since collectMappingState saves the whole object)
  const acfConfig = acf.config || acf;
  const html =
    '<div class="mt_primelink-acf-field" data-index="'+index+'">' +
      '<div class="mt_primelink-acf-row">' +
        '<input type="text" class="mt_primelink-acf-label" placeholder="ACF Field Label" value="'+escapeHtml(acf.label || '')+'" />' +
        '<input type="text" class="mt_primelink-acf-key" placeholder="ACF meta key (e.g. field_XXXX or my_field)" value="'+escapeHtml(acf.key || '')+'" />' +
      '</div>' +
      '<div class="mt_primelink-map-slot'+unmappedClass+'" data-target="">' +
        '<div class="mt_primelink-map-drop mt-map-slot__drop">' + dropHtml + '</div>' +
      '</div>' +
      '<input type="hidden" class="mt_primelink-map-input" value="'+escapeHtml(acf.source || '')+'" />' +
      '<input type="hidden" class="mt_primelink-acf-source" value="'+escapeHtml(acf.source || '')+'" />' +
      '<input type="hidden" class="mt_primelink-map-config" value="'+escapeHtml(JSON.stringify(acfConfig || {}))+'" />' +
      '<button type="button" class="button-link-delete mt_primelink-acf-remove">Remove</button>' +
    '</div>';
  acfWrap.append(html);
});

if((data.acf_fields || []).length || (data.custom_fields || []).length){
  bindDnD();
}

  bindDnD();
  
  // Row filters (rebuild)
  const filters = data.row_filters || [];
  if(Array.isArray(filters)){
    $('#mt_primelink-filter-rows').empty();
    mt_primelinkFilterIdx = 0;
    if(filters.length > 0){
      filters.forEach(f => {
        if(f && (f.field || f.value)){
          addFilterRow(f.field || '', f.op || '=', f.value || '');
        }
      });
    } else {
      addFilterRow();
    }
    updateFilterUI();
  }
  
  // Mark unmapped slots AFTER applying template
  markUnmappedSlots();
  
  // CRITICAL: Save mapping to draft FIRST, then load preview
  // This ensures the backend has the mapping before we request preview
  const importId = currentImportId();
  
  if(importId && importId > 0){
    // Save mapping to draft first (with a small delay to ensure DOM is ready)
    setTimeout(function(){
      saveStep5Mapping(true); // immediate=true to save right away
      
      // Then load preview after mapping is saved
      setTimeout(function(){
        loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
      }, 500); // Wait 500ms for save to complete
    }, 500); // Wait 500ms for DOM to settle
  }

  // Aliases
  const aliasWrap = $('#mt_primelink-alias-wrap').empty();
  const aliases = data.custom_aliases || [];
  if(aliases.length){
    aliases.forEach(a=>{
      aliasWrap.append(renderAliasRow(a.target || '', (a.aliases || []).join(', ')));
    });
  } else {
    aliasWrap.html('<div class="mt_primelink-empty">No custom aliases yet.</div>');
  }

  // Other options
  $('#mt_primelink-opt-global-prefix').val(other.global_prefix || '');
  $('#mt_primelink-opt-global-suffix').val(other.global_suffix || '');
  $('#mt_primelink-opt-global-trim').prop('checked', !!other.global_trim);
  $('#mt_primelink-opt-slugify').prop('checked', !!other.slugify);
  $('#mt_primelink-opt-fallback-image').val(other.fallback_image || '');
  $('#mt_primelink-opt-skip-field').val(other.skip_if_empty || '');
}

// Save template (IMPORT side) – support both old/new IDs (underscore vs hyphen)
$(document).on('click', '#mt_primelink-save-template, #mt-primelink-save-template', async function(e){
  // Determine context: import vs export
  const isExportPage = $('.mt_primelink-export-step-2').length > 0 || $('body').hasClass('mt_primelink-export-wizard');
  const isImportPage = $('.mt_primelink-import-step-5').length > 0 || $('body').hasClass('mt_primelink-import-wizard') || $('.mt_primelink-import-step-5').length > 0;

  // If we are clearly on export and not on import, let the export handler manage this button
  if (isExportPage && !isImportPage) {
    return;
  }

  const name = ($('#mt_primelink-template-name').val() || '').trim();
  if(!name){
    showToastOrAlert('warning', 'Please enter a template name.', 'Template');
    return;
  }

  // Get import type using helper function
  const importType = await getImportType();

  const payload = collectMappingState();

  try {
    const saved = await restPost('/import/templates/save', {
      name: name,
      data: payload,
      type: importType
    });

    // Clear input
    $('#mt_primelink-template-name').val('');

    // Then do a real refresh from server (will include the prefixed name)
    // Add small delay to ensure server has saved the template
    await new Promise(resolve => setTimeout(resolve, 100));
    await refreshTemplateList(saved.name || saved.saved?.name);

    showToastOrAlert('success', 'Template saved.', 'Template');
  } catch(e){
    showToastOrAlert('error', 'Template save failed.', 'Template');
  }
});

// Load template via button (IMPORT): load directly via REST API, no page refresh
// Support both old/new IDs (underscore vs hyphen) just in case.
// Use higher priority to ensure this runs before export handler
$(document).on('click', '#mt_primelink-load-template-btn, #mt-primelink-load-template-btn', async function(e){
  // Check if we're on export page FIRST - if so, let export handler take over
  const isExportPage = $('.mt_primelink-export-step-2').length > 0 || $('body').hasClass('mt_primelink-export-wizard');
  const isImportPage = $('.mt_primelink-import-step-5').length > 0 || $('body').hasClass('mt_primelink-import-wizard');
  
  if(isExportPage && !isImportPage){
    return; // Let export handler manage it
  }

  // We're on import page - handle it here
  e.preventDefault();
  e.stopPropagation();
  
  const selected = $('#mt_primelink-load-template').val();
  
  if(!selected){
    showToastOrAlert('warning', 'Select a template or import first.', 'Load');
    return;
  }
  
  try {
    let templateData;
    
    // Check if it's an import (format: "import:123") or template (format: "template:name" or just "name")
    if(selected.startsWith('import:')){
      const importId = selected.replace('import:', '');
      const res = await restPost('/import/templates/load', { import_id: parseInt(importId, 10) });
      templateData = res.data || res || {};
      showToastOrAlert('success', 'Import mapping loaded.', 'Load');
    } else {
      // It's a template
      const templateName = selected.startsWith('template:') ? selected.replace('template:', '') : selected;
      const res = await restPost('/import/templates/load', { name: templateName });
      // Response structure: { name, data, is_import } where 'data' is the mapping
      templateData = res.data || res || {};
      // Don't show toast here - will be handled by auto-load or user action
    }
    
    // Apply template/import data to UI
    if (templateData && (templateData.mapping || Object.keys(templateData).length > 0)) {
      applyTemplateToUI(templateData);
      // Only show success if we're not auto-loading from URL
      if (!url.searchParams.get('template')) {
        showToastOrAlert('success', 'Template loaded.', 'Load');
      }
    } else {
      showToastOrAlert('warning', 'Template data is empty or invalid.', 'Load');
    }
    
  } catch(e){
    showToastOrAlert('error', 'Load failed: ' + (e.json?.message || e.message || 'Unknown error'), 'Load');
  }
  
  return false; // Prevent any other handlers
});

// (Optional) If you prefer auto-load on change, we can later hook change event
// to also redirect. For now we keep it manual via the Load button to avoid
// surprising the user.

// Duplicate template (save current state under a new name)
$(document).on('click', '#mt_primelink-duplicate-template', async function(){
  const current = $('#mt_primelink-load-template').val() || '';
  // Remove prefix for prompt (support all types)
  const currentDisplay = current.replace(/^(order|product|customer|coupon|category|tag|attribute|variation|review|download):/, '');
  const newName = prompt('New template name:', currentDisplay ? currentDisplay + ' copy' : '');
  if(!newName) return;

  // Get import type using helper function
  const importType = await getImportType();

  const payload = collectMappingState();
  try {
    const saved = await restPost('/import/templates/save', {
      name: newName,
      data: payload,
      type: importType
    });
    await refreshTemplateList(saved.name);
    if (window.mtPrimeLinkToast) {
      window.mtPrimeLinkToast.success('Template duplicated.', 'Template');
    } else {
    alert('Template duplicated.');
    }
  } catch(e){
    showToastOrAlert('error', 'Could not duplicate template.', 'Template');
  }
});

// Alias add/remove
$(document).on('click', '#mt_primelink-add-alias', function(){
  const $wrap = $('#mt_primelink-alias-wrap');
  if($wrap.find('.mt_primelink-alias-row').length === 0){
    $wrap.empty();
  }
  $wrap.append(renderAliasRow('', ''));
});

$(document).on('click', '.mt_primelink-alias-remove', function(){
  $(this).closest('.mt_primelink-alias-row').remove();
  if($('#mt_primelink-alias-wrap .mt_primelink-alias-row').length === 0){
    $('#mt_primelink-alias-wrap').html('<div class="mt_primelink-empty">No custom aliases yet.</div>');
  }
});

// Refresh list when entering step 5 (import)
$(document).on('mt_primelink_step_changed', function(e, step){
  if(parseInt(step,10) === 5){
    refreshTemplateList();
  }
  // Refresh export templates when entering step 2 (export)
  if(parseInt(step,10) === 2 && $('.mt_primelink-export-step-2').length){
    refreshExportTemplateList();
  }
  // Load step 6 when entering step 6 (import)
  if(parseInt(step,10) === 6 && $('.mt_primelink-import-step-6').length){
    loadStep6();
  }
});

// Load templates immediately when step 5 renders on page load
$(function(){
  const $select = $('#mt_primelink-load-template');
  if($select.length){
    // Check if we're on export or import page
    if($('body').hasClass('mt_primelink-export-wizard') || $('.mt_primelink-export-step-2').length){
      // Export page - use export template list
      refreshExportTemplateList();
    } else {
      // Import page - use import template list
      refreshTemplateList();
    
      // Check if template parameter is in URL and load it automatically
      const url = new URL(window.location.href);
      const templateParam = url.searchParams.get('template');
      if(templateParam){
        // If a template is explicitly requested via URL, prefer that.
        // Support both "template:NAME" and "import:ID" notations.
        setTimeout(async function(){
          try {
            let tplData = {};
            if (templateParam.startsWith('import:')) {
              // Load mapping from a previous import (used by Reload Import).
              const sourceId = parseInt(templateParam.replace('import:', ''), 10);
              if (sourceId > 0) {
                const res = await restPost('/import/templates/load', { import_id: sourceId });
                tplData = res.data || res || {};
              }
            } else {
              const templateName = templateParam.startsWith('template:') ? templateParam.replace('template:', '') : templateParam;
              const res = await restPost('/import/templates/load', { name: templateName });
              tplData = res.data || res || {};
              
              // Select the template in dropdown (with template: prefix for consistency)
              if (templateName) {
                $('#mt_primelink-load-template').val('template:' + templateName);
              }
            }
            
            // Only apply if we have actual mapping data
            if (tplData && (tplData.mapping || Object.keys(tplData).length > 0)) {
              applyTemplateToUI(tplData);
              showToastOrAlert('success', 'Template loaded automatically.', 'Load');
            } else {
              console.warn('Template data is empty:', tplData);
            }
            
            // Remove template parameter from URL
            url.searchParams.delete('template');
            history.replaceState({}, '', url.toString());
          } catch(e){
            console.error('Failed to load template:', e);
            showToastOrAlert('error', 'Failed to load template: ' + (e.json?.message || e.message || 'Unknown error'), 'Load');
            // Remove template parameter from URL even on error
            url.searchParams.delete('template');
            history.replaceState({}, '', url.toString());
          }
        }, 800); // Increased delay to ensure UI is fully ready
      } else {
        // No explicit template in URL: auto-load mapping from current import draft (step 5 state).
        // This ensures that reloaded imports (and revisited imports) open with their saved mapping.
        setTimeout(async function(){
          try {
            const importId = currentImportId() || parseInt($('.mt_primelink-import-step-5').data('import-id'), 10) || 0;
            if(!importId){ return; }
            const res = await restPost('/import/templates/load', { import_id: importId });
            const tplData = res.data || res || {};
            if (tplData && (tplData.mapping || Object.keys(tplData).length > 0)) {
              applyTemplateToUI(tplData);
            }
          } catch(e){
            // Silent fail – mapping auto-load is a UX enhancement, not critical.
            console.warn('Auto-load of import mapping failed:', e);
          }
        }, 800);
      }
    }
  }
  if($('.mt_primelink-map-slot').length){
    syncSlotBadges();
  }
  toggleVariationPanel();
});

// -----------------------------
// Step 6 - Import Options
// -----------------------------

function collectStep6State(){
  const updateMode = $('input[name="mt_primelink-update-mode"]:checked').val() || 'all';
  const updateFields = [];
  $('.mt_primelink-update-field:checked').each(function(){
    updateFields.push($(this).val());
  });

  // Incremental import fields
  const incrementalFields = [];
  $('.mt_primelink-incremental-field:checked').each(function(){
    incrementalFields.push($(this).val());
  });

  // Duplicate detection fields
  const duplicateFields = [];
  $('.mt_primelink-duplicate-field:checked').each(function(){
    duplicateFields.push($(this).val());
  });

  return {
    match_existing: $('#mt_primelink-match-existing').val() || 'title',
    duplicate_detection: {
      enabled: $('#mt_primelink-duplicate-strategy').val() !== 'single',
      strategy: $('#mt_primelink-duplicate-strategy').val() || 'single',
      fields: duplicateFields.length > 0 ? duplicateFields : ['sku'],
      require_all: $('#mt_primelink-duplicate-require-all').is(':checked'),
      fuzzy_threshold: parseFloat($('#mt_primelink-fuzzy-threshold').val() || $('#mt_primelink-hybrid-fuzzy-threshold').val() || '85') / 100
    },
    update_mode: updateMode,
    update_fields: updateFields,
    use_first_gallery_as_featured: $('#mt_primelink-use-first-gallery-as-featured').is(':checked'),
    speed_optimization: $('#mt_primelink-speed-optimization').is(':checked'),
    iterative_processing: $('#mt_primelink-iterative-processing').is(':checked'),
    iteration_size: parseInt($('#mt_primelink-iteration-size').val(), 10) || 20,
    incremental: {
      enabled: $('#mt_primelink-incremental-enabled').is(':checked'),
      mode: $('#mt_primelink-incremental-mode').val() || 'all',
      fields: incrementalFields,
      skip_unchanged: $('#mt_primelink-incremental-skip-unchanged').is(':checked')
    },
    test_mode: {
      enabled: $('#mt_primelink-test-mode').is(':checked'),
      limit: parseInt($('#mt_primelink-test-limit').val()) || 10,
      validate_required: $('#mt_primelink-test-validate-required').is(':checked'),
      validate_format: $('#mt_primelink-test-validate-format').is(':checked'),
      check_duplicates: $('#mt_primelink-test-check-duplicates').is(':checked'),
      skip_unchanged: $('#mt_primelink-test-skip-unchanged').is(':checked')
    },
    schedule: {
      enabled: $('#mt_primelink-enable-schedule').is(':checked'),
      name: ($('#mt_primelink-schedule-name').val() || '').trim(),
      type: $('#mt_primelink-schedule-type').val() || 'preset',
      interval: $('#mt_primelink-schedule-interval').val() || 'daily',
      start_time: $('#mt_primelink-schedule-start').val() || '',
      cron: $('#mt_primelink-schedule-cron').val() || '',
      timezone: $('#mt_primelink-schedule-timezone').val() || '',
      start_date: $('#mt_primelink-schedule-start-date').val() || '',
      end_date: $('#mt_primelink-schedule-end-date').val() || '',
      max_runs: $('#mt_primelink-schedule-max-runs').val() || '',
      retry_failure: $('#mt_primelink-schedule-retry-failure').is(':checked'),
      retry_attempts: parseInt($('#mt_primelink-schedule-retry-attempts').val()) || 3,
      retry_delay: parseInt($('#mt_primelink-schedule-retry-delay').val()) || 30,
      pause_on_error: $('#mt_primelink-schedule-pause-on-error').is(':checked'),
      weekday_filter: $('#mt_primelink-schedule-weekday-filter').val() || '',
      weekly_days: (function(){
        const days = [];
        $('.mt_primelink-schedule-day:checked').each(function(){
          days.push(parseInt($(this).val()));
        });
        return days;
      })(),
      monthly_days: $('#mt_primelink-schedule-month-days').val() || '',
      time_slots: (function(){
        const slots = [];
        $('.mt_primelink-schedule-time-slot').each(function(){
          const time = $(this).val();
          if(time) slots.push(time);
        });
        if(!slots.length){
          const startTime = $('#mt_primelink-schedule-start').val();
          if(startTime) slots.push(startTime);
        }
        return slots;
      })(),
      email_attachment: $('#mt_primelink-email-attachment').is(':checked')
    },
    notify_override: {
      enabled: $('#mt_primelink-notify-override').is(':checked'),
      email: ($('#mt_primelink-notify-email-override').val() || '').trim(),
      tpl_finish: $('#mt_primelink-notify-finish-override').val() || '',
      tpl_error: $('#mt_primelink-notify-error-override').val() || ''
    }
  };
}

async function saveStep6(){
  const importId = currentImportId();
  const data = collectStep6State();

  await restPost('/import/save-step', {
    import_id: importId,
    step: 6,
    data: data
  });

  return data;
}

function applyStep6State(data, defaultSpeedOpt){
  data = data || {};
  defaultSpeedOpt = defaultSpeedOpt !== undefined ? defaultSpeedOpt : false;

  // Duplicate detection
  const dupConfig = data.duplicate_detection || {};
  const strategy = dupConfig.strategy || 'single';
  $('#mt_primelink-duplicate-strategy').val(strategy);
  
  // Show/hide strategy-specific options
  $('.mt_primelink-duplicate-strategy-wrap').hide();
  if(strategy === 'single'){
    $('#mt_primelink-duplicate-single-wrap').show();
  } else if(strategy === 'multiple'){
    $('#mt_primelink-duplicate-multiple-wrap').show();
  } else if(strategy === 'fuzzy'){
    $('#mt_primelink-duplicate-fuzzy-wrap').show();
  } else if(strategy === 'hybrid'){
    $('#mt_primelink-duplicate-hybrid-wrap').show();
  }

  // Set fields
  $('.mt_primelink-duplicate-field').prop('checked', false);
  if(Array.isArray(dupConfig.fields) && dupConfig.fields.length){
    dupConfig.fields.forEach(v => {
      $('.mt_primelink-duplicate-field[value="'+v+'"]').prop('checked', true);
    });
  } else {
    // Defaults
    if(strategy === 'single'){
      $('.mt_primelink-duplicate-field[value="sku"]').prop('checked', true);
    } else {
      $('.mt_primelink-duplicate-field[value="sku"]').prop('checked', true);
      if(strategy === 'fuzzy' || strategy === 'hybrid'){
        $('.mt_primelink-duplicate-field[value="title"]').prop('checked', true);
      }
    }
  }

  // Set other duplicate detection options
  $('#mt_primelink-duplicate-require-all').prop('checked', !!dupConfig.require_all);
  if(dupConfig.fuzzy_threshold !== undefined){
    const threshold = Math.round((dupConfig.fuzzy_threshold || 0.85) * 100);
    $('#mt_primelink-fuzzy-threshold').val(threshold);
    $('#mt_primelink-hybrid-fuzzy-threshold').val(threshold);
  }

  // Event handler for strategy change
  $('#mt_primelink-duplicate-strategy').off('change').on('change', function(){
    const strategy = $(this).val();
    $('.mt_primelink-duplicate-strategy-wrap').hide();
    if(strategy === 'single'){
      $('#mt_primelink-duplicate-single-wrap').show();
    } else if(strategy === 'multiple'){
      $('#mt_primelink-duplicate-multiple-wrap').show();
    } else if(strategy === 'fuzzy'){
      $('#mt_primelink-duplicate-fuzzy-wrap').show();
    } else if(strategy === 'hybrid'){
      $('#mt_primelink-duplicate-hybrid-wrap').show();
    }
  });

  // Trigger change to show correct wrap on load
  $('#mt_primelink-duplicate-strategy').trigger('change');

  // Legacy match_existing (for backward compatibility)
  $('#mt_primelink-match-existing').val(data.match_existing || 'title');

  const updateMode = data.update_mode || 'all';
  $('input[name="mt_primelink-update-mode"][value="'+updateMode+'"]').prop('checked', true);

  // show/hide choose fields
  if(updateMode === 'choose'){
    $('#mt_primelink-update-choose-wrap').show();
  } else {
    $('#mt_primelink-update-choose-wrap').hide();
  }

  const updateFields = Array.isArray(data.update_fields) ? data.update_fields : [];
  $('.mt_primelink-update-field').prop('checked', false);
  if(updateFields.length){
    updateFields.forEach(v=>{
      $('.mt_primelink-update-field[value="'+v+'"]').prop('checked', true);
    });
  } else {
    // default all on
    $('.mt_primelink-update-field').prop('checked', true);
  }

  $('#mt_primelink-use-first-gallery-as-featured').prop('checked', !!data.use_first_gallery_as_featured);
  
  // Speed optimization: use data.speed_optimization if set, otherwise use default_speed_opt from settings
  let speedOptimization = data.speed_optimization;
  if (speedOptimization === undefined || speedOptimization === null) {
    // Use default from settings if not set in import data
    speedOptimization = defaultSpeedOpt;
  }
  $('#mt_primelink-speed-optimization').prop('checked', !!speedOptimization);
  
  $('#mt_primelink-iterative-processing').prop('checked', data.iterative_processing !== false);
  $('#mt_primelink-iteration-size').val(data.iteration_size || 20);

  // Incremental import
  const incremental = data.incremental || {};
  $('#mt_primelink-incremental-enabled').prop('checked', !!incremental.enabled);
  if(incremental.enabled){
    $('#mt_primelink-incremental-options').show();
  } else {
    $('#mt_primelink-incremental-options').hide();
  }
  $('#mt_primelink-incremental-mode').val(incremental.mode || 'all');
  $('#mt_primelink-incremental-skip-unchanged').prop('checked', !!incremental.skip_unchanged);
  
  // Show/hide custom fields based on mode
  if(incremental.mode === 'custom'){
    $('#mt_primelink-incremental-fields-wrap').show();
  } else {
    $('#mt_primelink-incremental-fields-wrap').hide();
  }
  
  const incrementalFields = Array.isArray(incremental.fields) ? incremental.fields : [];
  $('.mt_primelink-incremental-field').prop('checked', false);
  if(incrementalFields.length){
    incrementalFields.forEach(v=>{
      $('.mt_primelink-incremental-field[value="'+v+'"]').prop('checked', true);
    });
  } else {
    // default: title and product_data
    $('.mt_primelink-incremental-field[value="title"]').prop('checked', true);
    $('.mt_primelink-incremental-field[value="product_data"]').prop('checked', true);
  }

  // Test mode
  const testMode = data.test_mode || {};
  $('#mt_primelink-test-mode').prop('checked', !!testMode.enabled);
  if(testMode.enabled){
    $('#mt_primelink-test-mode-options').show();
    $('#mt_primelink-test-limit').val(testMode.limit || 10);
    $('#mt_primelink-test-validate-required').prop('checked', testMode.validate_required !== false);
    $('#mt_primelink-test-validate-format').prop('checked', testMode.validate_format !== false);
    $('#mt_primelink-test-check-duplicates').prop('checked', testMode.check_duplicates !== false);
    $('#mt_primelink-test-skip-unchanged').prop('checked', !!testMode.skip_unchanged);
  } else {
    $('#mt_primelink-test-mode-options').hide();
  }

  const sched = data.schedule || {};
  $('#mt_primelink-enable-schedule').prop('checked', !!sched.enabled);

  if(sched.enabled){
    $('#mt_primelink-schedule-wrap').show();
  } else {
    $('#mt_primelink-schedule-wrap').hide();
  }

  $('#mt_primelink-schedule-name').val(sched.name || '');
  $('#mt_primelink-schedule-type').val(sched.type || 'preset');
  $('#mt_primelink-schedule-interval').val(sched.interval || 'daily');
  $('#mt_primelink-schedule-start').val(sched.start_time || '00:00');
  $('#mt_primelink-schedule-cron').val(sched.cron || '');
  $('#mt_primelink-schedule-timezone').val(sched.timezone || '');
  $('#mt_primelink-schedule-start-date').val(sched.start_date || '');
  $('#mt_primelink-schedule-end-date').val(sched.end_date || '');
  $('#mt_primelink-schedule-max-runs').val(sched.max_runs || '');
  $('#mt_primelink-schedule-retry-failure').prop('checked', !!sched.retry_failure);
  $('#mt_primelink-schedule-retry-attempts').val(sched.retry_attempts || 3);
  $('#mt_primelink-schedule-retry-delay').val(sched.retry_delay || 30);
  $('#mt_primelink-schedule-pause-on-error').prop('checked', !!sched.pause_on_error);
  $('#mt_primelink-schedule-weekday-filter').val(sched.weekday_filter || '');
  
  // Weekly days
  if(sched.weekly_days && Array.isArray(sched.weekly_days)){
    $('.mt_primelink-schedule-day').prop('checked', false);
    sched.weekly_days.forEach(day => {
      $('.mt_primelink-schedule-day[value="'+day+'"]').prop('checked', true);
    });
  }
  
  // Monthly days
  $('#mt_primelink-schedule-month-days').val(sched.monthly_days || '');
  
  // Multiple time slots
  const timesWrap = $('#mt_primelink-schedule-times-wrap').empty();
  if(sched.time_slots && Array.isArray(sched.time_slots) && sched.time_slots.length > 0){
    sched.time_slots.forEach((time, idx) => {
      timesWrap.append(renderScheduleTimeRow(time, idx > 0));
    });
  } else {
    timesWrap.append(renderScheduleTimeRow('00:00', false));
  }
  
  // Show/hide schedule type sections
  updateScheduleTypeUI();
  
  $('#mt_primelink-email-attachment').prop('checked', !!sched.email_attachment);

  const notify = data.notify_override || {};
  $('#mt_primelink-notify-override').prop('checked', !!notify.enabled);
  if(notify.enabled){
    $('#mt_primelink-notify-override-wrap').show();
  } else {
    $('#mt_primelink-notify-override-wrap').hide();
  }
  $('#mt_primelink-notify-email-override').val(notify.email || '');
  $('#mt_primelink-notify-finish-override').val(notify.tpl_finish || '');
  $('#mt_primelink-notify-error-override').val(notify.tpl_error || '');
}

async function loadStep6(){
  const importId = currentImportId();

  try {
    const res = await restPost('/import/save-step', {
      import_id: importId,
      step: 6
    });
    // If backend returns nothing on GET-like call, ignore.
    if(res && res.data){
      // Load settings to get default_speed_opt
      let defaultSpeedOpt = false;
      try {
        const settingsRes = await restGet('/settings?ts=' + Date.now());
        defaultSpeedOpt = !!settingsRes.default_speed_opt;
      } catch(e) {
        // If settings load fails, default to false
      }
      applyStep6State(res.data, defaultSpeedOpt);
    }
  } catch(e){
    // ignore
  }
}

// UI logic
$(document).on('change', 'input[name="mt_primelink-update-mode"]', function(){
  const v = $(this).val();
  if(v === 'choose'){
    $('#mt_primelink-update-choose-wrap').slideDown(120);
  } else {
    $('#mt_primelink-update-choose-wrap').slideUp(120);
  }
  saveStep6();
});

function renderScheduleTimeRow(time, showRemove){
  return `
    <div class="mt_primelink-schedule-time-row" style="display:grid;grid-template-columns:1fr auto;gap:8px;margin-bottom:4px;">
      <input type="time" class="mt_primelink-schedule-time-slot" value="${time || '00:00'}" />
      <button type="button" class="button mt_primelink-schedule-time-remove" ${showRemove ? '' : 'style="display:none;"'}>Remove</button>
    </div>
  `;
}

function updateScheduleTypeUI(){
  const type = $('#mt_primelink-schedule-type').val();
  $('.mt_primelink-schedule-type-wrap').hide();
  
  if(type === 'preset'){
    $('#mt_primelink-schedule-preset-wrap').show();
    const interval = $('#mt_primelink-schedule-interval').val();
    if(interval === 'weekly'){
      $('#mt_primelink-schedule-weekly-options').show();
    } else {
      $('#mt_primelink-schedule-weekly-options').hide();
    }
    if(interval === 'monthly'){
      $('#mt_primelink-schedule-monthly-options').show();
    } else {
      $('#mt_primelink-schedule-monthly-options').hide();
    }
  } else if(type === 'custom'){
    $('#mt_primelink-schedule-custom-wrap').show();
  } else if(type === 'advanced'){
    $('#mt_primelink-schedule-advanced-wrap').show();
  }
}

// Test Mode
$(document).on('change', '#mt_primelink-test-mode', function(){
  if($(this).is(':checked')){
    $('#mt_primelink-test-mode-options').slideDown(120);
  } else {
    $('#mt_primelink-test-mode-options').slideUp(120);
    $('#mt_primelink-test-results').hide();
  }
  saveStep6();
});

$(document).on('click', '#mt_primelink-run-test-import', async function(){
  const importId = currentImportId();
  if(!importId) {
    alert('No import ID found.');
    return;
  }

  const $btn = $(this);
  const originalText = $btn.text();
  $btn.prop('disabled', true).text('Running test...');

  const options = {
    limit: parseInt($('#mt_primelink-test-limit').val()) || 10,
    validate_required: $('#mt_primelink-test-validate-required').is(':checked'),
    validate_format: $('#mt_primelink-test-validate-format').is(':checked'),
    check_duplicates: $('#mt_primelink-test-check-duplicates').is(':checked'),
    skip_unchanged: $('#mt_primelink-test-skip-unchanged').is(':checked')
  };

  try {
    const results = await restPost('/import/dry-run', {
      import_id: importId,
      ...options
    });

    if(!results.success){
      alert(results.error || 'Test import failed.');
      $btn.prop('disabled', false).text(originalText);
      return;
    }

    // Display results
    displayTestResults(results);
    $('#mt_primelink-test-results').slideDown(200);
    
  } catch(e){
    alert(e.json?.message || 'Failed to run test import.');
  } finally {
    $btn.prop('disabled', false).text(originalText);
  }
});

function displayTestResults(results){
  const container = $('#mt_primelink-test-results-content').empty();
  
  // Summary
  const summary = `
    <div style="margin-bottom:16px;padding:12px;background:rgba(255,255,255,0.05);border-radius:4px;">
      <h5 style="margin-top:0;">Summary</h5>
      <div style="display:grid;grid-template-columns:repeat(2, 1fr);gap:8px;">
        <div><strong>Total Records:</strong> ${results.total}</div>
        <div><strong>Processed:</strong> ${results.processed}</div>
        <div style="color:#4caf50;"><strong>Would Create:</strong> ${results.would_create}</div>
        <div style="color:#ff9800;"><strong>Would Update:</strong> ${results.would_update}</div>
        <div style="color:#9e9e9e;"><strong>Would Skip:</strong> ${results.would_skip}</div>
        <div style="color:#f44336;"><strong>Errors:</strong> ${results.errors}</div>
        <div style="color:#ff9800;"><strong>Warnings:</strong> ${results.warnings}</div>
      </div>
    </div>
  `;
  container.append(summary);

  // Errors
  if(results.validation.errors && results.validation.errors.length > 0){
    let errorsHtml = '<div style="margin-bottom:12px;"><h5 style="color:#f44336;margin-top:0;">Errors</h5><div style="max-height:200px;overflow-y:auto;">';
    results.validation.errors.slice(0, 20).forEach(err => {
      errorsHtml += `<div style="padding:6px;margin-bottom:4px;background:rgba(244,67,54,0.1);border-left:3px solid #f44336;">
        <strong>Row ${err.row}</strong> - ${err.field}: ${err.message}
      </div>`;
    });
    if(results.validation.errors.length > 20){
      errorsHtml += `<div style="padding:6px;color:#9e9e9e;">... and ${results.validation.errors.length - 20} more errors</div>`;
    }
    errorsHtml += '</div></div>';
    container.append(errorsHtml);
  }

  // Warnings
  if(results.validation.warnings && results.validation.warnings.length > 0){
    let warningsHtml = '<div style="margin-bottom:12px;"><h5 style="color:#ff9800;margin-top:0;">Warnings</h5><div style="max-height:200px;overflow-y:auto;">';
    results.validation.warnings.slice(0, 20).forEach(warn => {
      warningsHtml += `<div style="padding:6px;margin-bottom:4px;background:rgba(255,152,0,0.1);border-left:3px solid #ff9800;">
        <strong>Row ${warn.row}</strong> - ${warn.field}: ${warn.message}
      </div>`;
    });
    if(results.validation.warnings.length > 20){
      warningsHtml += `<div style="padding:6px;color:#9e9e9e;">... and ${results.validation.warnings.length - 20} more warnings</div>`;
    }
    warningsHtml += '</div></div>';
    container.append(warningsHtml);
  }

  // Sample items
  if(results.sample_items && results.sample_items.length > 0){
    let samplesHtml = '<div><h5 style="margin-top:0;">Sample Items (First 5)</h5><div style="max-height:300px;overflow-y:auto;">';
    results.sample_items.forEach(item => {
      const actionColor = item.action === 'create' ? '#4caf50' : '#ff9800';
      samplesHtml += `<div style="padding:8px;margin-bottom:6px;background:rgba(255,255,255,0.05);border-radius:4px;">
        <div style="display:flex;justify-content:space-between;align-items:center;">
          <div><strong>Row ${item.row}</strong> - <span style="color:${actionColor};">${item.action.toUpperCase()}</span></div>
          ${item.item_id ? `<div style="color:#9e9e9e;">Existing ID: ${item.item_id}</div>` : ''}
        </div>
        <div style="margin-top:4px;font-size:12px;color:#9e9e9e;">
          ${item.mapped.post?.post_title || item.mapped.product?.sku || item.mapped.order?.order_number || 'N/A'}
        </div>
      </div>`;
    });
    samplesHtml += '</div></div>';
    container.append(samplesHtml);
  }

  // Success message
  if(results.errors === 0 && results.warnings === 0){
    container.prepend('<div style="padding:12px;background:rgba(76,175,80,0.2);border-left:3px solid #4caf50;margin-bottom:12px;border-radius:4px;"><strong style="color:#4caf50;">&#10003; Test completed successfully! No errors or warnings found.</strong></div>');
  } else if(results.errors === 0){
    container.prepend('<div style="padding:12px;background:rgba(255,152,0,0.2);border-left:3px solid #ff9800;margin-bottom:12px;border-radius:4px;"><strong style="color:#ff9800;">&#9888; Test completed with warnings. Review warnings before running actual import.</strong></div>');
  } else {
    container.prepend('<div style="padding:12px;background:rgba(244,67,54,0.2);border-left:3px solid #f44336;margin-bottom:12px;border-radius:4px;"><strong style="color:#f44336;">&#10007; Test completed with errors. Please fix errors before running actual import.</strong></div>');
  }
}

$(document).on('change', '#mt_primelink-enable-schedule', function(){
  if($(this).is(':checked')){
    $('#mt_primelink-schedule-wrap').slideDown(120);
  } else {
    $('#mt_primelink-schedule-wrap').slideUp(120);
  }
  saveStep6();
});

$(document).on('change', '#mt_primelink-schedule-type', function(){
  updateScheduleTypeUI();
  saveStep6();
});

$(document).on('change', '#mt_primelink-schedule-interval', function(){
  updateScheduleTypeUI();
  saveStep6();
});

$(document).on('change', '#mt_primelink-schedule-retry-failure', function(){
  if($(this).is(':checked')){
    $('#mt_primelink-schedule-retry-options').slideDown(120);
  } else {
    $('#mt_primelink-schedule-retry-options').slideUp(120);
  }
  saveStep6();
});

$(document).on('click', '#mt_primelink-schedule-time-add', function(){
  const timesWrap = $('#mt_primelink-schedule-times-wrap');
  const rows = timesWrap.find('.mt_primelink-schedule-time-row');
  rows.find('.mt_primelink-schedule-time-remove').show();
  timesWrap.append(renderScheduleTimeRow('00:00', true));
  saveStep6();
});

$(document).on('click', '.mt_primelink-schedule-time-remove', function(){
  const rows = $('#mt_primelink-schedule-times-wrap').find('.mt_primelink-schedule-time-row');
  if(rows.length > 1){
    $(this).closest('.mt_primelink-schedule-time-row').remove();
    const remaining = $('#mt_primelink-schedule-times-wrap').find('.mt_primelink-schedule-time-row');
    if(remaining.length === 1){
      remaining.find('.mt_primelink-schedule-time-remove').hide();
    }
    saveStep6();
  }
});
$(document).on('change', '#mt_primelink-notify-override', function(){
  if($(this).is(':checked')){
    $('#mt_primelink-notify-override-wrap').slideDown(120);
  } else {
    $('#mt_primelink-notify-override-wrap').slideUp(120);
  }
  saveStep6();
});

// Incremental import UI handlers
$(document).on('change', '#mt_primelink-incremental-enabled', function(){
  if($(this).is(':checked')){
    $('#mt_primelink-incremental-options').slideDown(120);
  } else {
    $('#mt_primelink-incremental-options').slideUp(120);
  }
  saveStep6();
});

$(document).on('change', '#mt_primelink-incremental-mode', function(){
  const mode = $(this).val();
  if(mode === 'custom'){
    $('#mt_primelink-incremental-fields-wrap').slideDown(120);
  } else {
    $('#mt_primelink-incremental-fields-wrap').slideUp(120);
  }
  saveStep6();
});

// autosave for all step6 inputs
$(document).on('change blur', '.mt_primelink-import-step-6 input, .mt_primelink-import-step-6 select, .mt_primelink-import-step-6 textarea', function(){
  saveStep6();
});

// -----------------------------
// Step 7 - Review Summary
// -----------------------------

function shortPath(p){
  if(!p) return '';
  const clean = String(p);
  if(clean.length <= 48) return clean;
  const parts = clean.split(/[/\\\\]/);
  if(parts.length < 3) return clean;
  return parts[0] + '/.../' + parts[parts.length-1];
}

function renderSummaryRows(rows, emptyText){
  const html = rows
    .filter(r => r && r.value !== undefined && r.value !== null && r.value !== '')
    .map(r => (
      '<div class="mt_primelink-summary-row">' +
        '<span class="mt_primelink-summary-label">'+escapeHtml(r.label)+'</span>' +
        '<span class="mt_primelink-summary-value">'+escapeHtml(String(r.value))+'</span>' +
      '</div>'
    )).join('');
  return html || '<div class="mt_primelink-empty">'+escapeHtml(emptyText || 'No data yet.')+'</div>';
}

function renderSummaryList(items, emptyText){
  if(!items || !items.length){
    return '<div class="mt_primelink-empty">'+escapeHtml(emptyText || 'No data yet.')+'</div>';
  }
  return '<ul class="mt_primelink-summary-list">' + items.map(item =>
    {
      const val = (item.value === undefined || item.value === null) ? '' : String(item.value);
      return '<li><span class="mt_primelink-summary-label">'+escapeHtml(item.label)+'</span>' +
             '<span class="mt_primelink-summary-value">'+escapeHtml(val)+'</span></li>';
    }
  ).join('') + '</ul>';
}

function summarizeFile(fileInfo){
  if(!fileInfo || !Object.keys(fileInfo).length){
    return '<div class="mt_primelink-empty">No file selected yet.</div>';
  }

  const badge = fileInfo.type ? '<span class="mt_primelink-summary-pill mt_primelink-pill-ghost">'+escapeHtml(String(fileInfo.type).toUpperCase())+'</span>' : '';

  const meta = [
    { label: 'Source', value: fileInfo.source || 'Unknown' },
    { label: 'Stored path', value: shortPath(fileInfo.path) },
    { label: 'Uploaded', value: fileInfo.uploaded_at || '' }
  ];

  return (
    '<div class="mt_primelink-summary-card">' +
      '<div class="mt_primelink-summary-top">' +
        '<span class="mt_primelink-summary-eyebrow">Data source</span>' +
        badge +
      '</div>' +
      '<div class="mt_primelink-summary-lead">'+escapeHtml(fileInfo.original_name || 'File attached')+'</div>' +
      '<div class="mt_primelink-summary-meta-grid">' +
        meta.map(m =>
          '<div class="mt_primelink-summary-meta">' +
            '<span class="mt_primelink-summary-label">'+escapeHtml(m.label)+'</span>' +
            '<span class="mt_primelink-summary-value">'+escapeHtml(String(m.value || ''))+'</span>' +
          '</div>'
        ).join('') +
      '</div>' +
    '</div>'
  );
}

function summarizeOptions(options){
  const modeLabels = {
    new_update: 'Import new items & update existing',
    new_only: 'Import new items only',
    update_only: 'Update existing items only'
  };
  const matchLabels = {
    title: 'Title',
    content: 'Content',
    slug: 'Slug',
    post_meta: 'Post Meta',
    sku: 'SKU',
    post_id: 'Post ID'
  };
  const updateModeLabels = {
    all: 'Update all data',
    price_stock: 'Update price & stock only',
    choose: 'Update selected fields only'
  };
  const updateFieldLabels = {
    title: 'Title & Content',
    product_data: 'Product Data',
    images: 'Images',
    yoast: 'Yoast SEO',
    custom_fields: 'Custom Fields',
    taxonomies: 'Taxonomies'
  };
  const intervalLabels = {
    hourly: 'Hourly',
    twicedaily: 'Twice Daily',
    daily: 'Daily',
    weekly: 'Weekly',
    monthly: 'Monthly'
  };

  const step3 = options.step3 || {};
  const step6 = options.step6 || {};

  const rows = [];

  rows.push({
    label: 'Import mode',
    value: modeLabels[step3.import_mode] || step3.import_mode || 'Not set'
  });

  rows.push({
    label: 'Match existing by',
    value: matchLabels[step6.match_existing] || step6.match_existing || 'Title'
  });

  rows.push({
    label: 'Update strategy',
    value: updateModeLabels[step6.update_mode] || updateModeLabels.all
  });

  rows.push({
    label: 'Speed optimization',
    value: step6.speed_optimization ? 'Enabled' : 'Disabled'
  });

  rows.push({
    label: 'Iterative processing',
    value: step6.iterative_processing
      ? 'Enabled (' + (step6.iteration_size || 20) + ' per batch)'
      : 'Disabled'
  });

  if(step6.update_mode === 'choose'){
    const fields = (step6.update_fields || []).map(f => updateFieldLabels[f] || f);
    rows.push({
      label: 'Fields to update',
      value: fields.length ? fields.join(', ') : 'None selected'
    });
  }

  const schedule = step6.schedule || {};
  const scheduleRows = [
    { label: 'Scheduling', value: schedule.enabled ? 'Enabled' : 'Disabled' }
  ];
  if(schedule.enabled){
    scheduleRows.push({ label: 'Name', value: schedule.name || 'Background import' });
    scheduleRows.push({ label: 'Interval', value: intervalLabels[schedule.interval] || schedule.interval || 'Daily' });
    if(schedule.start_time){
      scheduleRows.push({ label: 'Start time', value: schedule.start_time });
    }
    scheduleRows.push({ label: 'Email attachment', value: schedule.email_attachment ? 'Yes' : 'No' });
  }

  const notify = step6.notify_override || {};
  const notifyRows = [
    { label: 'Notifications', value: notify.enabled ? 'Custom (this import)' : 'Global defaults' }
  ];
  if(notify.enabled){
    notifyRows.push({ label: 'Notify email', value: notify.email || '(not set)' });
    if(notify.tpl_finish){
      notifyRows.push({ label: 'Finish template', value: (notify.tpl_finish || '').slice(0, 120) + (notify.tpl_finish.length > 120 ? '&#8230;' : '') });
    }
    if(notify.tpl_error){
      notifyRows.push({ label: 'Error template', value: (notify.tpl_error || '').slice(0, 120) + (notify.tpl_error.length > 120 ? '&#8230;' : '') });
    }
  }

  return (
    '<div class="mt_primelink-summary-card">' +
      '<div class="mt_primelink-summary-top"><span class="mt_primelink-summary-eyebrow">Options</span></div>' +
      '<div class="mt_primelink-pill-row">' +
        '<span class="mt_primelink-summary-pill">'+escapeHtml(modeLabels[step3.import_mode] || 'Mode not set')+'</span>' +
        '<span class="mt_primelink-summary-pill">'+escapeHtml('Match: ' + (matchLabels[step6.match_existing] || 'Title'))+'</span>' +
        '<span class="mt_primelink-summary-pill">'+escapeHtml('Update: ' + (updateModeLabels[step6.update_mode] || updateModeLabels.all))+'</span>' +
      '</div>' +
      '<div class="mt_primelink-summary-stack">' +
        renderSummaryRows(rows, 'No options selected yet.') +
      '</div>' +
      '<div class="mt_primelink-summary-divider"></div>' +
      '<div class="mt_primelink-summary-subtitle">Scheduling</div>' +
      renderSummaryRows(scheduleRows, 'Scheduling not enabled.') +
      '<div class="mt_primelink-summary-divider"></div>' +
      '<div class="mt_primelink-summary-subtitle">Notifications</div>' +
      renderSummaryRows(notifyRows, 'Using global defaults.') +
    '</div>'
  );
}

function summarizeMapping(mappingData){
  const mapping = mappingData.mapping || {};
  const custom = mappingData.custom_fields || [];
  const mapped = Object.entries(mapping).filter(([,cfg]) => cfg && cfg.source);

  const mappedList = mapped.map(([target, cfg]) => ({
    label: target,
    value: cfg.source
  }));

  const attrList = mapped
    .filter(([target]) => target.indexOf('attribute:') === 0)
    .map(([target, cfg]) => ({
      label: target.replace(/^attribute:/, ''),
      value: cfg.source,
      variation: !!cfg.variation
    }));

  const customList = (custom || []).filter(cf => cf && cf.key).map(cf => ({
    label: cf.key,
    value: cf.source || cf.field || cf.value || ''
  }));

  // Critical fields: Title / SKU presence (only for products)
  let criticalBadges = [];
  if(!document.body.classList.contains('mt_primelink-import-orders')){
    const criticalDefs = [
      { label: 'Title', keys: ['title','post_title','name'] },
      { label: 'SKU',   keys: ['sku','product_sku'] }
    ];
    criticalBadges = criticalDefs.map(def => {
      const found = mapped.some(([target]) => def.keys.includes(String(target).toLowerCase()));
      return {
        label: def.label,
        ok: found
      };
    });
  } else {
    // For orders, check Order ID or Customer Email
    const orderCriticalDefs = [
      { label: 'Order ID', keys: ['order_id'] },
      { label: 'Customer Email', keys: ['customer_email'] }
    ];
    criticalBadges = orderCriticalDefs.map(def => {
      const found = mapped.some(([target]) => def.keys.includes(String(target).toLowerCase()));
      return {
        label: def.label,
        ok: found
      };
    });
  }

  let html = '<div class="mt_primelink-summary-stack">';
  html += '<div class="mt_primelink-summary-card">';
  html += '  <div class="mt_primelink-summary-top"><span class="mt_primelink-summary-eyebrow">Mapping</span></div>';
  html += '  <div class="mt_primelink-summary-stat-grid">';
  html += '    <div class="mt_primelink-summary-stat"><div class="mt_primelink-stat-value">'+mappedList.length+'</div><div class="mt_primelink-stat-label">Mapped targets</div></div>';
  if(!document.body.classList.contains('mt_primelink-import-orders')){
    html += '    <div class="mt_primelink-summary-stat"><div class="mt_primelink-stat-value">'+attrList.length+'</div><div class="mt_primelink-stat-label">Attributes</div></div>';
  }
  html += '    <div class="mt_primelink-summary-stat"><div class="mt_primelink-stat-value">'+customList.length+'</div><div class="mt_primelink-stat-label">Custom fields</div></div>';
  html += '  </div>';

  if(criticalBadges.length > 0){
    html += '<div class="mt_primelink-critical-badges">';
    criticalBadges.forEach(b=>{
      html += '<span class="mt_primelink-critical-badge '+(b.ok?'is-ok':'is-missing')+'">'+escapeHtml(b.label)+(b.ok?' mapped':' missing')+'</span>';
    });
    html += '</div>';
  }

  html += '  <div class="mt_primelink-summary-divider"></div>';
  html += '  <div class="mt_primelink-summary-subtitle">Targets</div>';
  html +=      renderSummaryList(mappedList, 'No target fields mapped yet.');

  // Attributes section (only for products)
  if(!document.body.classList.contains('mt_primelink-import-orders')){
    if(attrList.length){
      const attrsWithFlag = attrList.map(a => ({
        label: a.label + (a.variation ? ' (variations)' : ''),
        value: a.value
      }));
      html += '  <div class="mt_primelink-summary-subtitle">Attributes</div>';
      html +=        renderSummaryList(attrsWithFlag, 'No attributes mapped.');
      if(mappingData.create_variations){
        html += '<div class="mt_primelink-summary-note">Create variations: Enabled</div>';
      }
    }
  }

  if(customList.length){
    html += '  <div class="mt_primelink-summary-subtitle">Custom Fields</div>';
    html +=        renderSummaryList(customList, 'No custom fields added yet.');
  }

  // Product type (only for products)
  if(!document.body.classList.contains('mt_primelink-import-orders')){
    if(mappingData.product_type && mappingData.product_type !== 'mapped'){
      html += '<div class="mt_primelink-summary-note">Product type: '+escapeHtml(mappingData.product_type)+'</div>';
    }
  }
  html += '</div>';
  html += '</div>';

  return html;
}

async function buildSummary(){
  const importId = currentImportId();

  // Don't make request if no valid import_id
  if(!importId || importId === 0){
    return;
  }

  try {
    const res = await restPost('/import/get-draft', { import_id: importId });
    const draft = res.draft || {};
    const steps = draft.step_data || {};

    const fileInfo = steps[2]?.file || {};
    const options  = {
      step3: steps[3] || {},
      step4: steps[4] || {},
      step6: steps[6] || {}
    };
    const mapping  = steps[5] || {};

    $('#mt_primelink-summary-file').html(summarizeFile(fileInfo));
    $('#mt_primelink-summary-options').html(summarizeOptions(options));
    $('#mt_primelink-summary-mapping').html(summarizeMapping(mapping));

    // Warnings (no mapping / no images)
    const warnings = [];
    const mapped = mapping.mapping || mapping;
    const mappedCount = Object.values(mapped || {}).filter(cfg => cfg && cfg.source).length;
    // Nu afiÈ™a warnings pentru orders
    if(!document.body.classList.contains('mt_primelink-import-orders')) {
      if(!mappedCount){
        warnings.push('No fields mapped. Please map at least one field.');
      }
      const hasImage = Object.keys(mapped || {}).some(k => /image|img|gallery/i.test(k) && mapped[k]?.source);
      if(!hasImage){
        warnings.push('No image fields mapped or stored. Make sure products get images.');
      }
    }

    const $warn = $('#mt_primelink-summary-warnings');
    if($warn.length){
      if(warnings.length){
        $warn.html('<strong>Review warnings:</strong><ul>'+warnings.map(w=>'<li>'+escapeHtml(w)+'</li>').join('')+'</ul>');
        $warn.show();
      } else {
        $warn.hide().empty();
      }
    }

    // Critical missing list + link back to step 5
    const criticalMissing = [];
    const mappedTargets = Object.keys(mapped || {}).map(k => k.toLowerCase());
    // Nu afiÈ™a critical missing pentru Title/SKU la orders
    if(!document.body.classList.contains('mt_primelink-import-orders')) {
      const hasTitle = mappedTargets.some(k => ['title','post_title','name'].includes(k));
      if(!hasTitle) criticalMissing.push('Title missing');
      const hasSKU = mappedTargets.some(k => ['sku'].includes(k));
      if(!hasSKU) criticalMissing.push('SKU missing');
    } else {
      // For orders, check Order ID or Customer Email instead
      const hasOrderId = mappedTargets.some(k => ['order_id'].includes(k));
      const hasCustomerEmail = mappedTargets.some(k => ['customer_email'].includes(k));
      if(!hasOrderId && !hasCustomerEmail) {
        criticalMissing.push('Order ID or Customer Email missing');
      }
    }
    const $crit = $('#mt_primelink-critical-missing');
    if($crit.length){
      if(criticalMissing.length){
        $crit.html('<strong>Critical fields missing:</strong><ul>'+criticalMissing.map(w=>'<li>'+escapeHtml(w)+'</li>').join('')+'</ul>');
        $crit.show();
      } else {
        $crit.hide().empty();
      }
    }

    $('#mt_primelink-summary-loading').hide();
    $('#mt_primelink-summary-content').show();

  } catch(e){
    $('#mt_primelink-summary-loading').text('Summary unavailable.');
  }
}

// -----------------------------
// Step 8 - Runner UI
// -----------------------------

// Track previous progress for smooth interpolation
let previousProgress = 0;
let progressAnimationFrame = null;

function renderRunnerState(state){
  const total = state.total || 0;
  const current = state.current || 0;
  const progress = Math.max(0, Math.min(100, state.progress || 0));
  const status = state.status || 'idle';
  const statusText = String(status).charAt(0).toUpperCase() + String(status).slice(1);

  // Smooth progress bar animation
  const $progressBar = $('.mt_primelink-progress-bar__inner');
  const targetProgress = progress;
  
  // Cancel any ongoing animation
  if (progressAnimationFrame) {
    cancelAnimationFrame(progressAnimationFrame);
  }
  
  // Smooth interpolation for progress bar using previousProgress variable
  const animateProgress = () => {
    const currentProgress = previousProgress;
    const diff = targetProgress - currentProgress;
    
    if (Math.abs(diff) > 0.1) {
      // Smooth interpolation (ease-out) - 20% of difference per frame
      const step = diff * 0.2;
      const newProgress = currentProgress + step;
      $progressBar.css('width', newProgress + '%');
      previousProgress = newProgress;
      progressAnimationFrame = requestAnimationFrame(animateProgress);
    } else {
      // Final value
      $progressBar.css('width', targetProgress + '%');
      previousProgress = targetProgress;
    }
  };
  
  // Start animation only if there's a significant change
  if (Math.abs(targetProgress - previousProgress) > 0.1) {
    animateProgress();
  } else {
    // Small change - update directly
    $progressBar.css('width', targetProgress + '%');
    previousProgress = targetProgress;
  }
  
  // Add/remove running class for shimmer effect
  if (status === 'running') {
    $progressBar.addClass('is-running');
  } else {
    $progressBar.removeClass('is-running');
  }

  $('#mt_primelink-progress-text').text(Math.round(progress) + '%');
  $('#mt_primelink-progress-count').text(current + ' / ' + total);
  $('#mt_primelink-progress-status').text(status);
  $('#mt_primelink-run-total').text(total);
  $('#mt_primelink-run-current').text(current);

  $('#mt_primelink-run-status-pill')
    .text(statusText)
    .removeClass('is-running is-paused is-finished is-idle')
    .addClass('is-' + status);

  if(status === 'running'){
    $('#mt_primelink-start-import').prop('disabled', true);
    $('#mt_primelink-pause-import').prop('disabled', false);
    $('#mt_primelink-resume-import').prop('disabled', true);
  } else if(status === 'paused'){
    $('#mt_primelink-start-import').prop('disabled', true);
    $('#mt_primelink-pause-import').prop('disabled', true);
    $('#mt_primelink-resume-import').prop('disabled', false);
  } else if(status === 'finished'){
    $('#mt_primelink-start-import').prop('disabled', true);
    $('#mt_primelink-pause-import').prop('disabled', true);
    $('#mt_primelink-resume-import').prop('disabled', true);
    
    // Check if finished with anomalies
    const importId = currentImportId();
    if (importId > 0) {
      if (state.has_anomalies && state.anomalies_count > 0) {
        // Show inline button and also open modal once to draw attention.
        $('#mt_primelink-review-anomalies').show();
        setTimeout(() => {
          showAnomaliesModal(importId);
        }, 500);
      } else {
        // If state flags are missing, still try to detect anomalies via REST.
        restPost('/import/anomalies', { import_id: importId }).then(response => {
          if (response.anomalies && response.anomalies.length > 0) {
            $('#mt_primelink-review-anomalies').show();
          }
        }).catch(() => {});
      }
    }
  } else {
    $('#mt_primelink-start-import').prop('disabled', false);
    $('#mt_primelink-pause-import').prop('disabled', true);
    $('#mt_primelink-resume-import').prop('disabled', true);
  }

  const log = state.log || [];
  if(log.length){
    $('#mt_primelink-run-log').html(
      log.slice(-200).map(l => '<div class="mt_primelink-run-log__line">'+escapeHtml(String(l))+'</div>').join('')
    );
  } else {
    // Show different message based on status
    if(status === 'running'){
      $('#mt_primelink-run-log').html('<div class="mt_primelink-run-log__placeholder">Import is running... Logs will appear here.</div>');
    } else if(status === 'paused'){
      $('#mt_primelink-run-log').html('<div class="mt_primelink-run-log__placeholder">Import is paused.</div>');
  } else {
    $('#mt_primelink-run-log').html('<div class="mt_primelink-run-log__placeholder">Waiting for import to start...</div>');
    }
  }
}

let runnerPollTimer = null;
let runnerBackground = false;

async function pollRunner(){
  if(runnerBackground){ return; }
  const importId = currentImportId();

  try {
    const state = await restPost('/import/run/status', { import_id: importId });
    renderRunnerState(state);

    // Check if import finished with anomalies
    if(state.status === 'finished' && state.has_anomalies && state.anomalies_count > 0){
      // Small delay to ensure state is saved
      setTimeout(() => {
        showAnomaliesModal(importId);
      }, 500);
    }

    // Faster polling when running for smoother updates
    if(state.status === 'running'){
      runnerPollTimer = setTimeout(pollRunner, 800); // Reduced from 1500ms to 800ms for smoother updates
    } else {
      runnerPollTimer = setTimeout(pollRunner, 2000);
    }
  } catch(e){
    runnerPollTimer = setTimeout(pollRunner, 2500);
  }
}

$(document).on('click', '#mt_primelink-start-import', async function(){
  runnerBackground = false;
  const importId = currentImportId();
  if(!importId || importId < 1){
    alert('Invalid import ID. Please refresh the page and try again.');
    return;
  }
  
  // Disable button immediately for better UX
  const $startBtn = $('#mt_primelink-start-import');
  $startBtn.prop('disabled', true);
  
  // Update UI optimistically
  $('#mt_primelink-run-status-pill')
    .text('Starting...')
    .removeClass('is-running is-paused is-finished is-idle')
    .addClass('is-running');
  $('#mt_primelink-progress-status').text('Starting...');
  $('#mt_primelink-run-log').html('<div class="mt_primelink-run-log__placeholder">Starting import...</div>');
  
  try {
    const state = await restPost('/import/run/start', { import_id: importId });
    renderRunnerState(state);
    
    // Start polling immediately
    pollRunner();
  } catch(e){
    // Re-enable button on error
    $startBtn.prop('disabled', false);
    alert('Failed to start import: ' + (e.json?.message || e.status || 'Unknown error'));
    console.error('Start import error:', e);
    
    // Reset UI on error
    $('#mt_primelink-run-status-pill')
      .text('Idle')
      .removeClass('is-running is-paused is-finished is-idle')
      .addClass('is-idle');
    $('#mt_primelink-progress-status').text('Idle');
  }
});

$(document).on('click', '#mt_primelink-pause-import', async function(){
  const importId = currentImportId();
  const state = await restPost('/import/run/pause', { import_id: importId });
  renderRunnerState(state);
});

$(document).on('click', '#mt_primelink-resume-import', async function(){
  const importId = currentImportId();
  const state = await restPost('/import/run/resume', { import_id: importId });
  renderRunnerState(state);
  pollRunner();
});

$(document).on('click', '#mt_primelink-start-import-bg', async function(){
  const importId = currentImportId();
  try{
    const state = await restPost('/import/run/start', { import_id: importId });
    renderRunnerState(state);
    runnerBackground = true;
    if(typeof runnerPollTimer !== 'undefined' && runnerPollTimer){
      clearTimeout(runnerPollTimer);
      runnerPollTimer = null;
    }
    $('#mt_primelink-run-bg-note').show();
    if($('#mt_primelink-run-bg-notify').is(':checked')){
      alert('Import started in background. You can navigate away.');
    }
  }catch(e){
    alert(e.json?.message || 'Failed to start import.');
  }
});

// -----------------------------
// Manage Imports page controls
// -----------------------------

function ensureAnomalyButton(importId, count) {
  if (!count || count <= 0) {
    // Nu ascundem butonul chiar dacă între timp anomaliile au fost rezolvate;
    // vrem ca utilizatorul să poată vedea că au existat și să verifice manual.
    return;
  }
  const $row = $('.mt_primelink-import-row[data-id="' + importId + '"]');
  if (!$row.length) return;
  const $actions = $row.find('.mt_primelink-import-actions');
  if (!$actions.length) return;

  let $btn = $actions.find('.mt-primelink-review-anomalies');
  const label = 'Review Anomalies (' + count + ')';

  if ($btn.length === 0) {
    $btn = $('<button type="button" class="button mt-primelink-review-anomalies" data-id="' + importId + '"></button>');
    $actions.prepend($btn);
  }

  $btn.text(label).show();
}

function updateManageRow(importId, state){
  const $row = $('.mt_primelink-import-row[data-id="'+importId+'"]');
  if(!$row.length) return;

  const status = state.status || 'idle';
  const progress = state.progress || 0;
  const current = state.current || 0;
  const total = state.total || 0;

  $row.find('.mt_primelink-status-pill')
    .attr('class','mt_primelink-status-pill mt_primelink-status-' + status)
    .text(status.charAt(0).toUpperCase() + status.slice(1));

  $row.find('.mt_primelink-dash-progress__bar').css('width', Math.max(0, Math.min(100, progress)) + '%');
  $row.find('.muted').text(current + ' / ' + total);

  // Toggle buttons
  $row.find('.mt_primelink-import-start').prop('disabled', status === 'running' || status === 'paused');
  $row.find('.mt_primelink-import-pause').prop('disabled', status !== 'running');
  $row.find('.mt_primelink-import-resume').prop('disabled', status !== 'paused');
}

async function refreshManageRow(importId){
  try {
    const state = await restPost('/import/run/status', { import_id: importId });
    updateManageRow(importId, state);
    
    // Always check anomalies for this import and ensure the Review button appears
    try {
      const resp = await restPost('/import/anomalies', { import_id: importId });
      const anomalies = resp.anomalies || [];
      ensureAnomalyButton(importId, anomalies.length);
    } catch(e) {
      // ignore
    }
  } catch(e){}
}

$(document).on('click', '.mt_primelink-import-pause', async function(){
  const importId = parseInt($(this).data('id'), 10);
  try{
    const state = await restPost('/import/run/pause', { import_id: importId });
    updateManageRow(importId, state);
    // Pause polling but don't stop it completely (might resume)
  } catch(e){}
});

$(document).on('click', '#mt_primelink-imports-refresh', async function(){
  $('.mt_primelink-import-row').each(function(){
    const id = parseInt($(this).data('id'), 10);
    refreshManageRow(id);
  });
});

// Real-time progress updates for imports with optimized polling
// Similar to exports - faster polling when running, slower on errors
let importPollIntervals = {};

function startImportPolling(importId) {
  // Clear existing interval if any
  if (importPollIntervals[importId]) {
    clearInterval(importPollIntervals[importId]);
  }

  let pollCount = 0;
  let currentInterval = 1500; // Start with 1.5s for running imports

  const poll = async function() {
    try {
      const state = await restPost('/import/run/status', { import_id: importId });
      updateManageRow(importId, state);
      
      // Check if finished with anomalies
      if (state.status === 'finished' && state.has_anomalies && state.anomalies_count > 0) {
        const $row = $('.mt_primelink-import-row[data-id="' + importId + '"]');
        const $actions = $row.find('.mt_primelink-import-actions');
        if ($actions.length > 0 && $actions.find('.mt-primelink-review-anomalies').length === 0) {
          const $btn = $('<button type="button" class="button mt-primelink-review-anomalies" data-id="' + importId + '">Review Anomalies (' + state.anomalies_count + ')</button>');
          $actions.prepend($btn);
        }
      }

      const status = (state.status || 'idle').toLowerCase();
      
      // Stop polling if completed, error, or idle
      if (status === 'completed' || status === 'error' || status === 'idle' || status === 'finished') {
        stopImportPolling(importId);
        return;
      }

      // Adjust interval based on status
      if (status === 'running') {
        currentInterval = 1500; // Fast polling when running
      } else if (status === 'paused') {
        currentInterval = 2500; // Slower when paused
      }

      // Restart with new interval
      stopImportPolling(importId);
      importPollIntervals[importId] = setTimeout(poll, currentInterval);
      
    } catch (e) {
      // On error, use slower polling
      currentInterval = 2500;
      stopImportPolling(importId);
      importPollIntervals[importId] = setTimeout(poll, currentInterval);
    }
  };

  // Start polling
  poll();
}

function stopImportPolling(importId) {
  if (importPollIntervals[importId]) {
    clearTimeout(importPollIntervals[importId]);
    delete importPollIntervals[importId];
  }
}

// Initialize polling for all running/paused imports on page load
$(document).ready(function() {
    $('.mt_primelink-import-row').each(function() {
    const status = $(this).find('.mt_primelink-status-pill').text().toLowerCase().trim();
      if (status === 'running' || status === 'paused') {
        const id = parseInt($(this).data('id'), 10);
      if (id > 0) {
        startImportPolling(id);
      }
    }
  });
});

// Start polling when import starts
// Reload Import - duplicate an import with same settings
$(document).on('click', '.mt_primelink-import-reload', async function(){
  const importId = $(this).data('id');
  if(!importId){
    return;
  }
  
  if(!confirm('Create a new import with the same settings as Import #' + importId + '?')){
    return;
  }
  
  try {
    const $row = $(this).closest('.mt_primelink-import-row');
    const importType = $row.data('type') || 'products';
    const sourceImportId = parseInt(importId, 10);
    const res = await restPost('/import/reload', { import_id: importId });
    if(res && res.import_id){
      // Redirect to new import wizard
      const baseAdminUrl = (typeof mtPrimeLink !== 'undefined' && mtPrimeLink.adminUrl) ? mtPrimeLink.adminUrl : (window.mtPrimeLinkWizard && mtPrimeLinkWizard.adminUrl ? mtPrimeLinkWizard.adminUrl : (window.ajaxurl ? window.ajaxurl.replace(/admin-ajax\.php.*/, '') : '/wp-admin/'));
      const targetUrl = baseAdminUrl
        + 'admin.php?page=mt-primelink-new-import'
        + '&import_id=' + encodeURIComponent(res.import_id)
        + '&import_type=' + encodeURIComponent(importType)
        + '&step=5'
        // Pass original import as "template" so mapping can be auto-loaded from it.
        + '&template=' + encodeURIComponent('import:' + sourceImportId);
      window.location.href = targetUrl;
    } else {
      showToastOrAlert('error', 'Failed to reload import.', 'Reload');
    }
  } catch(e){
    showToastOrAlert('error', 'Failed to reload import: ' + (e.json?.message || e.message || 'Unknown error'), 'Reload');
  }
});

$(document).on('click', '.mt_primelink-import-start', async function(){
  const importId = parseInt($(this).data('id'), 10);
  try{
    const state = await restPost('/import/run/start', { import_id: importId });
    updateManageRow(importId, state);
    startImportPolling(importId);
  } catch(e){}
});

// Update polling when import resumes
$(document).on('click', '.mt_primelink-import-resume', async function(){
  const importId = parseInt($(this).data('id'), 10);
  try{
    const state = await restPost('/import/run/resume', { import_id: importId });
    updateManageRow(importId, state);
    startImportPolling(importId);
  } catch(e){}
});

// Download log (Import)
$(document).on('click', '.mt_primelink-import-log', async function(){
  const importId = parseInt($(this).data('id'), 10);
  try{
    const res = await restPost('/import/log', { import_id: importId });
    const logArr = res.log || [];
    const text = logArr.join('\n');
    const blob = new Blob([text], {type:'text/plain'});
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'import-'+importId+'-log.txt';
    document.body.appendChild(a);
    a.click();
    a.remove();
    URL.revokeObjectURL(url);
  }catch(e){
    alert(e.json?.message || 'Failed to download log.');
  }
});

// Download log (Export)
$(document).on('click', '.mt_primelink-export-log', async function(){
  const exportId = parseInt($(this).data('id'), 10);
  try{
    const res = await restPost('/export/log', { export_id: exportId });
    const logArr = res.log || [];
    const text = logArr.join('\n');
    const blob = new Blob([text], {type:'text/plain'});
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'export-'+exportId+'-log.txt';
    document.body.appendChild(a);
    a.click();
    a.remove();
    URL.revokeObjectURL(url);
  }catch(e){
    alert(e.json?.message || 'Failed to download log.');
  }
});

// Select all toggle (per category)
$(document).on('change', '.mt_primelink-imports-select-all', function(){
  const checked = $(this).is(':checked');
  const type = $(this).data('type') || '';
  const $section = $(this).closest('.mt_primelink-import-section');
  if(type){
    $section.find('.mt_primelink-import-select[data-type="'+type+'"]').prop('checked', checked);
  } else {
    $section.find('.mt_primelink-import-select').prop('checked', checked);
  }
});

// Select all for scheduled imports
$(document).on('change', '.mt_primelink-imports-select-all-scheduled', function(){
  const checked = $(this).is(':checked');
  const type = $(this).data('type') || '';
  const $section = $(this).closest('.mt_primelink-import-section-scheduled');
  if(type){
    $section.find('.mt_primelink-import-select[data-type="'+type+'"]').prop('checked', checked);
  } else {
    $section.find('.mt_primelink-import-select').prop('checked', checked);
  }
});

// Bulk delete (per category)
$(document).on('click', '.mt_primelink-import-delete-selected', async function(e){
  e.preventDefault();
  e.stopPropagation();
  
  const type = $(this).data('type') || '';
  let selector = '.mt_primelink-import-select:checked';
  if(type){
    selector = '.mt_primelink-import-select[data-type="'+type+'"]:checked';
  }
  
  // Get checkboxes from the same section (manual or scheduled)
  const $section = $(this).closest('.mt_primelink-import-section, .mt_primelink-import-section-scheduled');
  const ids = $section.find(selector).map(function(){ 
    return parseInt($(this).val(), 10); 
  }).get().filter(id => !isNaN(id) && id > 0);
  
  if(!ids.length){
    showToastOrAlert('warning', 'Select at least one import to delete.', 'Import');
    return;
  }
  if(!confirm('Delete selected imports? This cannot be undone.')) return;

  const $button = $(this);
  const originalText = $button.text();
  $button.prop('disabled', true).text('Deleting...');

  try{
    for(const importId of ids){
      await restPost('/import/delete-draft', { import_id: importId });
      $('.mt_primelink-import-row[data-id="'+importId+'"]').fadeOut(300, function(){ $(this).remove(); });
    }
    // Uncheck select all checkboxes
    if(type){
      $('.mt_primelink-imports-select-all[data-type="'+type+'"]').prop('checked', false);
      $('.mt_primelink-imports-select-all-scheduled[data-type="'+type+'"]').prop('checked', false);
    }
    showToastOrAlert('success', 'Selected imports deleted.', 'Import');
  } catch(e){
    showToastOrAlert('error', 'Delete failed: ' + (e.json?.message || 'Unknown error'), 'Import');
  } finally {
    $button.prop('disabled', false).text(originalText);
  }
});

// Export management - Select All (Manual)
$(document).on('change', '.mt_primelink-exports-select-all', function(){
  const type = $(this).data('type') || '';
  const checked = $(this).is(':checked');
  let selector = '.mt_primelink-export-select';
  if(type){
    selector = '.mt_primelink-export-select[data-type="'+type+'"]';
  }
  // Only select checkboxes in the same section (manual exports)
  $(this).closest('.mt_primelink-import-section').find(selector).prop('checked', checked);
});

// Export management - Select All (Scheduled)
$(document).on('change', '.mt_primelink-exports-select-all-scheduled', function(){
  const type = $(this).data('type') || '';
  const checked = $(this).is(':checked');
  let selector = '.mt_primelink-export-select';
  if(type){
    selector = '.mt_primelink-export-select[data-type="'+type+'"]';
  }
  // Only select checkboxes in the same section (scheduled exports)
  $(this).closest('.mt_primelink-import-section-scheduled').find(selector).prop('checked', checked);
});

// Export management - Delete selected
$(document).on('click', '.mt_primelink-export-delete-selected', async function(e){
  e.preventDefault();
  e.stopPropagation();
  
  const type = $(this).data('type') || '';
  let selector = '.mt_primelink-export-select:checked';
  if(type){
    selector = '.mt_primelink-export-select[data-type="'+type+'"]:checked';
  }
  
  // Get checkboxes from the same section (manual or scheduled)
  const $section = $(this).closest('.mt_primelink-import-section, .mt_primelink-import-section-scheduled');
  const ids = $section.find(selector).map(function(){ 
    return parseInt($(this).val(), 10); 
  }).get().filter(id => !isNaN(id) && id > 0);
  
  if(!ids.length){
    showToastOrAlert('warning', 'Select at least one export to delete.', 'Export');
    return;
  }
  if(!confirm('Delete selected exports? This cannot be undone.')) return;

  const $button = $(this);
  const originalText = $button.text();
  $button.prop('disabled', true).text('Deleting...');

  try{
    for(const exportId of ids){
      await restPost('/export/delete-draft', { export_id: exportId });
      $('.mt_primelink-export-row[data-id="'+exportId+'"]').fadeOut(300, function(){ $(this).remove(); });
    }
    // Uncheck select all checkboxes
    if(type){
      $('.mt_primelink-exports-select-all[data-type="'+type+'"]').prop('checked', false);
      $('.mt_primelink-exports-select-all-scheduled[data-type="'+type+'"]').prop('checked', false);
    }
  } catch(e){
    alert('Delete failed: ' + (e.json?.message || 'Unknown error'));
  } finally {
    $button.prop('disabled', false).text(originalText);
  }
});

// Delete products for a specific import
// Rollback import
$(document).on('click', '.mt_primelink-import-rollback', async function(){
  const importId = parseInt($(this).data('id'), 10);
  if(!importId) return;

  try {
    // Get rollback summary first
    const summary = await restPost('/import/rollback-summary', { import_id: importId });
    
    if(!summary.can_rollback){
      alert('No items to rollback for this import.');
      return;
    }

    const s = summary.summary || {};
    const created = s.total_created || 0;
    const updated = s.total_updated || 0;
    
    let msg = 'Are you sure you want to rollback this import?\n\n';
    msg += 'This will:\n';
    if(created > 0){
      msg += `- Delete ${created} created item(s)\n`;
    }
    if(updated > 0){
      msg += `- Restore ${updated} updated item(s) to their previous state\n`;
    }
    msg += '\nThis action cannot be undone!';

    if(!confirm(msg)){
      return;
    }

    // Show options
    const deleteCreated = created > 0 ? confirm('Delete created items?') : false;
    const restoreUpdated = updated > 0 ? confirm('Restore updated items to previous state?') : true;

    if(!deleteCreated && !restoreUpdated){
      alert('No action selected. Rollback cancelled.');
      return;
    }

    const $btn = $(this);
    const originalText = $btn.text();
    $btn.prop('disabled', true).text('Rolling back...');

    const res = await restPost('/import/rollback', {
      import_id: importId,
      delete_created: deleteCreated,
      restore_updated: restoreUpdated
    });

    alert(res.message || 'Rollback completed successfully.');
    
    // Refresh the row
    refreshManageRow(importId);
    
    $btn.prop('disabled', false).text(originalText);
  } catch(e){
    alert(e.json?.message || 'Rollback failed. Please try again.');
    $(this).prop('disabled', false);
  }
});

$(document).on('click', '.mt_primelink-import-delete-products', async function(){
  const importId = parseInt($(this).data('id'), 10);
  if(!importId) return;
  if(!confirm('Delete all products (and their images) imported in this session? This cannot be undone.')) return;

  try{
    const res = await restPost('/import/delete-products', { import_id: importId });
    alert('Deleted products: ' + (res.deleted_products || 0) + ' | Images removed: ' + (res.deleted_attachments || 0));
  }catch(e){
    alert(e.json?.message || 'Delete products failed.');
  }
});

// -----------------------------
// Settings page
// -----------------------------
async function loadSettings(){
  const notice = $('#mt_primelink-settings-notice');
  try{
    const res = await restGet('/settings?ts=' + Date.now());
    $('#mt_primelink-license-key').val(res.license_key || '');
    $('#mt_primelink-enable-beta').prop('checked', !!res.enable_beta);
    $('#mt_primelink-enable-logs').prop('checked', !!res.enable_logs);
    $('#mt_primelink-default-iteration-size').val(res.default_iteration_size || 20);
    $('#mt_primelink-default-speed-opt').prop('checked', !!res.default_speed_opt);
    $('#mt_primelink-fast-import-mode').prop('checked', !!res.fast_import_mode);
    $('#mt_primelink-notify-email').val(res.notify_email || '');
    $('#mt_primelink-notify-finish').prop('checked', !!res.notify_on_finish);
    $('#mt_primelink-notify-error').prop('checked', !!res.notify_on_error);
    $('#mt_primelink-notify-template-finish').val(res.notify_tpl_finish || '');
    $('#mt_primelink-notify-template-error').val(res.notify_tpl_error || '');
    initEmailBuilder(res.notify_builder || '');
    $('#mt_primelink-cleanup-days').val(res.cleanup_days || 0);
    $('#mt_primelink-uninstall-delete-data').prop('checked', !!res.uninstall_delete_data);
    $('#mt_primelink-dropbox-token').val(res.dropbox_access_token || '');
    $('#mt_primelink-dropbox-default-path').val(res.dropbox_default_path || '');
    $('#mt_primelink-gdrive-token').val(res.gdrive_access_token || '');
    $('#mt_primelink-gdrive-default-file').val(res.gdrive_default_file || '');
    $('#mt_primelink-onedrive-token').val(res.onedrive_access_token || '');
    $('#mt_primelink-onedrive-default-file').val(res.onedrive_default_file || '');
    $('#mt_primelink-cron-mode').val(res.cron_mode || 'wp');
    $('#mt_primelink-cron-token').val(res.cron_token || '');
    $('#mt_primelink-source-retention').val(typeof res.source_retention_days !== 'undefined' ? res.source_retention_days : '');
    updateCronUrlTemplate(res.cron_token || '');
    $('#mt_primelink-ftp-protocol').val(res.ftp_protocol || 'ftp');
    $('#mt_primelink-ftp-host').val(res.ftp_host || '');
    $('#mt_primelink-ftp-port').val(res.ftp_port || '');
    $('#mt_primelink-ftp-user').val(res.ftp_user || '');
    $('#mt_primelink-ftp-pass').val(res.ftp_pass || '');
    $('#mt_primelink-ftp-passive').prop('checked', !!res.ftp_passive);
    $('#mt_primelink-ftp-root').val(res.ftp_root || '');
    $('#mt_primelink-ftp-default-file').val(res.ftp_default_file || '');
    
    // Load platform connectors
    if(!window.mt_primelinkSettings) window.mt_primelinkSettings = {};
    let pc = res.platform_connectors || {};
    // Ensure we store platform_connectors as a plain object, not an array
    if (Array.isArray(pc)) {
      pc = {};
    }
    window.mt_primelinkSettings.platform_connectors = pc;
    
    // Load anomaly detection settings
    $('#mt_primelink-anomaly-detection-enabled').prop('checked', !!res.anomaly_detection_enabled);
    if (res.anomaly_detection_config) {
      const config = res.anomaly_detection_config;
      $('#mt_primelink-price-drop-threshold').val(config.price_drop_threshold || 50);
      $('#mt_primelink-price-increase-threshold').val(config.price_increase_threshold || 200);
      $('#mt_primelink-price-deviation-threshold').val(config.price_deviation_threshold || 50);
      $('#mt_primelink-max-absolute-price-change').val(config.max_absolute_price_change || 0);
      $('#mt_primelink-stock-change-threshold').val(config.stock_change_threshold || 90);
      $('#mt_primelink-max-stock-threshold').val(config.max_stock_threshold || 10000);
      $('#mt_primelink-content-change-threshold').val(config.content_change_threshold || 30);
      $('#mt_primelink-require-sku').prop('checked', !!config.require_sku);
      $('#mt_primelink-pause-on-critical').prop('checked', !!config.pause_on_critical);
      $('#mt_primelink-detect-script-injection').prop('checked', !!config.detect_script_injection);
    }
    
    // Toggle anomaly detection settings visibility
    $('#mt_primelink-anomaly-detection-enabled').off('change').on('change', function(){
      $('#mt_primelink-anomaly-detection-settings').toggle($(this).is(':checked'));
    }).trigger('change');
    
    updateLicenseStatus(res.license_status || '');
    notice.hide();
  } catch(e){
    notice.text('Failed to load settings.').show();
  }
}

function updateLicenseStatus(status){
  const pill = $('#mt_primelink-license-status');
  let label = 'Not saved';
  let cls = 'mt_primelink-status-idle';
  if(status === 'saved'){
    label = 'Saved';
    cls = 'mt_primelink-status-finished';
  }
  pill.text(label)
      .removeClass('mt_primelink-status-idle mt_primelink-status-finished')
      .addClass(cls);
}

$(document).on('click', '#mt_primelink-save-settings', async function(e){
  e.preventDefault();
  const notice = $('#mt_primelink-settings-notice');
  notice.hide();

  // mask key on send? we send full key

  // Before building payload, persist current platform connector form values into memory
  // so they are included even if user didn't click "Test Connection".
  if ($('#mt_primelink-platform-connector-select').length) {
    const connectorName = $('#mt_primelink-platform-connector-select').val();
    if (connectorName) {
      const connectorCreds = {};
      $('#mt_primelink-platform-connector-fields input').each(function () {
        const fieldKey = $(this).data('field');
        if (fieldKey) {
          connectorCreds[fieldKey] = $(this).val() || '';
        }
      });

      if (!window.mt_primelinkSettings) window.mt_primelinkSettings = {};
      if (!window.mt_primelinkSettings.platform_connectors || Array.isArray(window.mt_primelinkSettings.platform_connectors)) {
        window.mt_primelinkSettings.platform_connectors = {};
      }

      if (Object.keys(connectorCreds).length > 0) {
        window.mt_primelinkSettings.platform_connectors[connectorName] = connectorCreds;
      }
    }
  }

  const payload = {
    license_key: $('#mt_primelink-license-key').val() || '',
    enable_beta: $('#mt_primelink-enable-beta').is(':checked'),
    enable_logs: $('#mt_primelink-enable-logs').is(':checked'),
    default_iteration_size: parseInt($('#mt_primelink-default-iteration-size').val(), 10) || 20,
      default_speed_opt: $('#mt_primelink-default-speed-opt').is(':checked'),
      fast_import_mode: $('#mt_primelink-fast-import-mode').is(':checked'),
    notify_email: $('#mt_primelink-notify-email').val() || '',
    notify_on_finish: $('#mt_primelink-notify-finish').is(':checked'),
    notify_on_error: $('#mt_primelink-notify-error').is(':checked'),
    notify_tpl_finish: $('#mt_primelink-notify-template-finish').val() || '',
    notify_tpl_error: $('#mt_primelink-notify-template-error').val() || '',
    notify_builder: $('#mt_primelink-notify-builder-data').val() || '',
    cleanup_days: parseInt($('#mt_primelink-cleanup-days').val(), 10) || 0,
    uninstall_delete_data: $('#mt_primelink-uninstall-delete-data').is(':checked'),
    dropbox_access_token: $('#mt_primelink-dropbox-token').val() || '',
    dropbox_default_path: $('#mt_primelink-dropbox-default-path').val() || '',
    gdrive_access_token: $('#mt_primelink-gdrive-token').val() || '',
    gdrive_default_file: $('#mt_primelink-gdrive-default-file').val() || '',
    onedrive_access_token: $('#mt_primelink-onedrive-token').val() || '',
    onedrive_default_file: $('#mt_primelink-onedrive-default-file').val() || '',
    cron_mode: $('#mt_primelink-cron-mode').val() || 'wp',
    cron_token: $('#mt_primelink-cron-token').val() || '',
    source_retention_days: parseInt($('#mt_primelink-source-retention').val(), 10) || 0,
    ftp_protocol: $('#mt_primelink-ftp-protocol').val() || 'ftp',
    ftp_host: $('#mt_primelink-ftp-host').val() || '',
    ftp_port: parseInt($('#mt_primelink-ftp-port').val(), 10) || 0,
    ftp_user: $('#mt_primelink-ftp-user').val() || '',
    ftp_pass: $('#mt_primelink-ftp-pass').val() || '',
    // Anomaly Detection Settings
    anomaly_detection_enabled: $('#mt_primelink-anomaly-detection-enabled').is(':checked'),
    anomaly_detection_config: {
      price_drop_threshold: parseInt($('#mt_primelink-price-drop-threshold').val(), 10) || 50,
      price_increase_threshold: parseInt($('#mt_primelink-price-increase-threshold').val(), 10) || 200,
      price_deviation_threshold: parseInt($('#mt_primelink-price-deviation-threshold').val(), 10) || 50,
      max_absolute_price_change: parseFloat($('#mt_primelink-max-absolute-price-change').val()) || 0,
      stock_change_threshold: parseInt($('#mt_primelink-stock-change-threshold').val(), 10) || 90,
      max_stock_threshold: parseInt($('#mt_primelink-max-stock-threshold').val(), 10) || 10000,
      content_change_threshold: parseInt($('#mt_primelink-content-change-threshold').val(), 10) || 30,
      require_sku: $('#mt_primelink-require-sku').is(':checked'),
      pause_on_critical: $('#mt_primelink-pause-on-critical').is(':checked'),
      detect_script_injection: $('#mt_primelink-detect-script-injection').is(':checked'),
    },
    ftp_passive: $('#mt_primelink-ftp-passive').is(':checked'),
    ftp_root: $('#mt_primelink-ftp-root').val() || '',
    ftp_default_file: $('#mt_primelink-ftp-default-file').val() || '',
    platform_connectors: (function(){
      let pc = window.mt_primelinkSettings?.platform_connectors || {};
      // Ensure we don't send an array here; use plain object so JSON keeps keys
      if (Array.isArray(pc)) {
        pc = {};
      }
      return pc;
    })()
  };

  try{
    const res = await restPost('/settings/save', payload);
    updateLicenseStatus(res.settings?.license_status || '');
    notice.text('Settings saved.').show();
  } catch(err){
    notice.text('Failed to save settings.').show();
  }
});


  function updateCronUrlTemplate(token){
    const base = window.location.origin;
    const url = base + '/wp-json/primelink/v1/cron/tick?token=' + encodeURIComponent(token || '{TOKEN}');
    $('#mt_primelink-cron-url-template').text(url);
  }
  $(document).on('input change', '#mt_primelink-cron-token', function(){
    updateCronUrlTemplate($(this).val());
  });

  // Test email
  $(document).on('click', '#mt_primelink-test-email', async function(){
    const email = $('#mt_primelink-notify-email').val() || '';
    const status = $('#mt_primelink-test-email-status');
    status.hide();
    if(!email){
      alert('Set a notify email first.');
      return;
    }
    $(this).prop('disabled', true);
    status.text('Sending...').show();
    try{
      const res = await restPost('/settings/notify-test', { email });
      status.text(res.message || 'Sent.').show();
    }catch(e){
      status.text(e.json?.message || 'Failed to send test email.').show();
    } finally {
      $(this).prop('disabled', false);
    }
  });

  // Email builder logic
  let mt_primelinkEmailBlocks = [];
  function syncBuilderHidden(){
    $('#mt_primelink-notify-builder-data').val(JSON.stringify(mt_primelinkEmailBlocks));
  }
  function renderEmailBlocks(){
    const wrap = $('#mt_primelink-email-blocks');
    wrap.empty();
    mt_primelinkEmailBlocks.forEach((b, idx)=>{
      let html = '<div class="mt_primelink-email-block" data-idx="'+idx+'">';
      html += '<div class="mt_primelink-email-block__header"><strong>'+b.type+'</strong>';
      html += '<div class="mt_primelink-email-block__controls">';
      html += '<button type="button" class="button mt_primelink-block-up" '+(idx===0?'disabled':'')+'>&uarr;</button>';
      html += '<button type="button" class="button mt_primelink-block-down" '+(idx===mt_primelinkEmailBlocks.length-1?'disabled':'')+'>&darr;</button>';
      html += '<button type="button" class="button mt_primelink-block-del">&times;</button>';
      html += '</div></div>';
      if(b.type === 'heading' || b.type === 'paragraph'){
        html += '<textarea class="mt_primelink-block-text" rows="'+(b.type==='heading'?2:3)+'">'+escapeHtml(b.text||'')+'</textarea>';
      }else if(b.type === 'html'){
        html += '<textarea class="mt_primelink-block-html" rows="5" placeholder="<p>Custom HTML</p>">'+escapeHtml(b.html||b.text||'')+'</textarea>';
      }else if(b.type === 'button'){
        html += '<input type="text" class="mt_primelink-block-text" placeholder="Button label" value="'+escapeHtml(b.text||'')+'"/>';
        html += '<input type="text" class="mt_primelink-block-url" placeholder="https://example.com" value="'+escapeHtml(b.url||'')+'"/>';
      }else if(b.type === 'stats'){
        html += '<div class="muted">Stats block will show Created/Updated/Skipped/Errors.</div>';
      }
      html += '</div>';
      wrap.append(html);
    });
    syncBuilderHidden();
  }
  function initEmailBuilder(raw){
    try{
      mt_primelinkEmailBlocks = raw ? JSON.parse(raw) : [];
      if(!Array.isArray(mt_primelinkEmailBlocks)) mt_primelinkEmailBlocks=[];
    }catch(e){ mt_primelinkEmailBlocks=[]; }
    if(!mt_primelinkEmailBlocks.length){
      mt_primelinkEmailBlocks = [
        {type:'heading', text:'Import #{import_id} finished'},
        {type:'stats'},
        {type:'paragraph', text:'Status: {status}'}
      ];
    }
    renderEmailBlocks();
  }
  $(document).on('click', '#mt_primelink-email-block-add', function(){
    const t = $('#mt_primelink-email-block-type').val();
    const block = {type:t};
    if(t==='heading') block.text='Import #{import_id} finished';
    if(t==='paragraph') block.text='Status: {status}';
    if(t==='html') block.html='<p><strong>Custom HTML</strong> with placeholders like {status}</p>';
    if(t==='button'){ block.text='View import'; block.url=window.location.origin; }
    mt_primelinkEmailBlocks.push(block);
    renderEmailBlocks();
  });
  $(document).on('click', '.mt_primelink-block-del', function(){
    const idx = parseInt($(this).closest('.mt_primelink-email-block').data('idx'),10);
    mt_primelinkEmailBlocks.splice(idx,1);
    renderEmailBlocks();
  });
  $(document).on('click', '.mt_primelink-block-up', function(){
    const idx = parseInt($(this).closest('.mt_primelink-email-block').data('idx'),10);
    if(idx>0){
      [mt_primelinkEmailBlocks[idx-1], mt_primelinkEmailBlocks[idx]] = [mt_primelinkEmailBlocks[idx], mt_primelinkEmailBlocks[idx-1]];
      renderEmailBlocks();
    }
  });
  $(document).on('click', '.mt_primelink-block-down', function(){
    const idx = parseInt($(this).closest('.mt_primelink-email-block').data('idx'),10);
    if(idx<mt_primelinkEmailBlocks.length-1){
      [mt_primelinkEmailBlocks[idx+1], mt_primelinkEmailBlocks[idx]] = [mt_primelinkEmailBlocks[idx], mt_primelinkEmailBlocks[idx+1]];
      renderEmailBlocks();
    }
  });
  $(document).on('input', '.mt_primelink-block-text', function(){
    const idx = parseInt($(this).closest('.mt_primelink-email-block').data('idx'),10);
    mt_primelinkEmailBlocks[idx].text = $(this).val();
    syncBuilderHidden();
  });
  $(document).on('input', '.mt_primelink-block-html', function(){
    const idx = parseInt($(this).closest('.mt_primelink-email-block').data('idx'),10);
    mt_primelinkEmailBlocks[idx].html = $(this).val();
    syncBuilderHidden();
  });
  $(document).on('input', '.mt_primelink-block-url', function(){
    const idx = parseInt($(this).closest('.mt_primelink-email-block').data('idx'),10);
    mt_primelinkEmailBlocks[idx].url = $(this).val();
    syncBuilderHidden();
  });
  $(document).on('click', '#mt_primelink-email-preview-btn', function(){
    const sample = {
      import_id: 123,
      status: 'finished',
      created: 10,
      updated: 5,
      skipped: 2,
      errors: 0
    };
    let html = '';
    mt_primelinkEmailBlocks.forEach(b=>{
      if(b.type==='heading'){
        html += '<h3>'+escapeHtml(applyPlaceholders(b.text||'', sample))+'</h3>';
      } else if(b.type==='paragraph'){
        html += '<p>'+escapeHtml(applyPlaceholders(b.text||'', sample))+'</p>';
      } else if(b.type==='html'){
        html += applyPlaceholders(b.html||b.text||'', sample);
      } else if(b.type==='stats'){
        html += '<ul>';
        html += '<li>Created: '+sample.created+'</li>';
        html += '<li>Updated: '+sample.updated+'</li>';
        html += '<li>Skipped: '+sample.skipped+'</li>';
        html += '<li>Errors: '+sample.errors+'</li>';
        html += '</ul>';
      } else if(b.type==='button'){
        const url = applyPlaceholders(b.url||'', sample);
        const txt = applyPlaceholders(b.text||'Open', sample);
        html += '<p><a href="'+escapeHtml(url)+'" style="display:inline-block;padding:8px 12px;background:#007cba;color:#fff;border-radius:6px;text-decoration:none;">'+escapeHtml(txt)+'</a></p>';
      }
    });
    $('#mt_primelink-email-preview').html(html || '<em>No blocks.</em>').show();
  });
  function applyPlaceholders(text, data){
    return text.replace(/{(\w+)}/g, (_,k)=> data[k]!==undefined ? data[k] : '');
  }

$(document).ready(function(){
  if($('.mt_primelink-settings').length){
    loadSettings();
  }
});

// Category tabs (WooCommerce / WooCommerce)
$(document).on('click', '.mt_primelink-category-tab-btn', function(e){
  e.preventDefault();
  const category = $(this).data('category');
  $('.mt_primelink-category-tab-btn').removeClass('is-active');
  $(this).addClass('is-active');
  
  // Show/hide category content
  $('.mt_primelink-category-content').removeClass('is-active');
  $('.mt_primelink-category-content[data-category-content="'+category+'"]').addClass('is-active');
  
  // Show/hide tab panels for this category
  $('.mt_primelink-tab-panel').removeClass('is-active');
  const $firstTab = $('.mt_primelink-tab-panel[data-category="'+category+'"]').first();
  if($firstTab.length){
    $firstTab.addClass('is-active');
  }
  
  // Update sub-tabs active state
  $('.mt_primelink-tab-btn[data-category="'+category+'"]').first().addClass('is-active');
  $('.mt_primelink-tab-btn[data-category="'+category+'"]').not(':first').removeClass('is-active');
});

// Settings tabs (sub-tabs within categories)
$(document).on('click', '.mt_primelink-tab-btn', function(e){
  e.preventDefault();
  const tab = $(this).data('tab');
  const category = $(this).data('category');
  
  // If category exists, only process if this tab belongs to the active category
  if(category){
    const $activeCategory = $('.mt_primelink-category-tab-btn.is-active');
    const activeCategory = $activeCategory.data('category');
    
    if(category !== activeCategory){
      return; // Ignore clicks on inactive category tabs
    }
    
    // Update tab buttons for this category
    $('.mt_primelink-tab-btn[data-category="'+category+'"]').removeClass('is-active');
    $(this).addClass('is-active');
    
    // Update tab panels for this category (only panels in the active category)
    $('.mt_primelink-tab-panel[data-category="'+category+'"]').removeClass('is-active');
    $('.mt_primelink-tab-panel[data-tab-panel="'+tab+'"][data-category="'+category+'"]').addClass('is-active');
  } else {
    // No category - handle as regular settings tabs (like in settings page)
  $('.mt_primelink-tab-btn').removeClass('is-active');
  $(this).addClass('is-active');
    
    // Update all tab panels (without category filter)
  $('.mt_primelink-tab-panel').removeClass('is-active');
  $('.mt_primelink-tab-panel[data-tab-panel="'+tab+'"]').addClass('is-active');
  }
});

function initWizardUI(){
  const $typeSelect = $('#mt_primelink-product-type-select');
  if($typeSelect.length){
    mt_primelinkSelectedProductType = $typeSelect.val() || 'simple';
  }
  const $existingPath = $('#mt-primelink-existing-path');
  if($existingPath.length){
    try{
        populateExistingRecent();
        fetchExistingUploads();
      }catch(e){}
  }
  if(getStep() !== 5){
    setSaveStatus('', '');
  }
    filterFileFields();
    bindDnD();
    markUnmappedSlots();
    toggleVariationPanel();
    updatePreviewPaginationUI();
    loadPreview();
    loadMappingPreview(window.mt_primelinkCurrentMapIndex || 0);
    fetchFilterPresets();
    // Only refresh import templates if we're on import page, not export
    if(!$('body').hasClass('mt_primelink-export-wizard') && !$('.mt_primelink-export-step-2').length){
    refreshTemplateList();
    }
    if($('.mt_primelink-import-step-7').length){
      buildSummary();
    }
    if($('.mt_primelink-import-step-8').length){
      if(typeof runnerPollTimer !== 'undefined' && runnerPollTimer){
        clearTimeout(runnerPollTimer);
        runnerPollTimer = null;
      }
      pollRunner();
    }
  }
  
  // Refresh export templates when step 2 is visible
  // NOTE: This is handled in $(function()) block below, don't duplicate
  // if($('.mt_primelink-export-step-2').length){
  //   refreshExportTemplateList();
  // }

  function collectAliasState(){
  const list = [];
  jQuery('.mt_primelink-alias-row').each(function(){
    const target = (jQuery(this).find('.mt_primelink-alias-target').val() || '').trim();
    const aliases = (jQuery(this).find('.mt_primelink-alias-values').val() || '').split(',').map(v=>v.trim()).filter(Boolean);
    if(target && aliases.length){
      list.push({ target, aliases });
    }
  });
  return list;
}

function collectOtherOptions(){
  return {
    global_prefix: jQuery('#mt_primelink-opt-global-prefix').val() || '',
    global_suffix: jQuery('#mt_primelink-opt-global-suffix').val() || '',
    global_trim: jQuery('#mt_primelink-opt-global-trim').is(':checked'),
    slugify: jQuery('#mt_primelink-opt-slugify').is(':checked'),
    fallback_image: jQuery('#mt_primelink-opt-fallback-image').val() || '',
    skip_if_empty: jQuery('#mt_primelink-opt-skip-field').val() || ''
  };
}

  // -----------------------------
  // Platform Connectors
  // -----------------------------
  let platformConnectors = {};
  let platformCredentials = {};

  async function initPlatformConnector(){
    try {
      const res = await restGet('/platform/connectors');
      platformConnectors = {};
      (res.connectors || []).forEach(c => {
        if(c && c.name){
          // Fields can be an object (associative array from PHP) or an array
          let fieldsData = c.fields || {};
          let fieldsArray = [];
          
          if(Array.isArray(fieldsData)){
            // If it's already an array, use it directly
            fieldsArray = fieldsData;
          } else if(typeof fieldsData === 'object' && fieldsData !== null){
            // Convert object to array: {key: {label, type, ...}} -> [{key, label, type, ...}]
            const keys = Object.keys(fieldsData);
            fieldsArray = keys.map(key => {
              const fieldData = fieldsData[key];
              
              // Check if fieldData is an object (not a string or other type)
              if(typeof fieldData === 'object' && fieldData !== null && !Array.isArray(fieldData)){
                // Spread all properties from fieldData and add the key
                return {
                  key: key,
                  ...fieldData
                };
              } else {
                // If fieldData is not an object, create a basic field structure
                return {
                  key: key,
                  label: key,
                  type: 'text',
                  placeholder: '',
                  required: false,
                  description: ''
                };
              }
            });
          }
          
          platformConnectors[c.name] = {
            name: c.name,
            display_name: c.display_name || c.name,
            fields: fieldsArray
          };
        }
      });
    } catch(err){
      console.error('Failed to load connectors:', err);
      platformConnectors = {};
    }
  }

  // Helper function to get current import type
  function getCurrentImportType(){
    const url = new URL(window.location.href);
    let importType = url.searchParams.get('import_type') || '';
    if(!importType && document.body.classList.contains('mt_primelink-import-orders')){
      importType = 'orders';
    } else if(!importType && document.body.classList.contains('mt_primelink-import-customers')){
      importType = 'customers';
    } else if(!importType && document.body.classList.contains('mt_primelink-import-coupons')){
      importType = 'coupons';
    } else if(!importType){
      importType = 'products'; // default
    }
    return importType;
  }

  $(document).on('change', '#mt_primelink-platform-connector', async function(){
    const connectorName = $(this).val();
    const $credentials = $('#mt_primelink-platform-credentials');
    const $fields = $('#mt_primelink-platform-credentials-fields');
    const $options = $('#mt_primelink-platform-options');
    const $dataTypeRow = $('#mt_primelink-platform-data-type-row');
    const $productsInfo = $('#mt_primelink-platform-products-info');
    
    if(!connectorName){
      $credentials.hide();
      $options.hide();
      return;
    }

    // Ensure connectors are loaded
    if(Object.keys(platformConnectors).length === 0){
      await initPlatformConnector();
    }

    const connector = platformConnectors[connectorName];
    if(!connector){
      $credentials.hide();
      $options.hide();
      return;
    }

    // Data type is automatically determined from current import type, no need for dropdown
    // Hide data type row as it's no longer needed
    $dataTypeRow.hide();

    // Fields should already be processed as array in initPlatformConnector
    // Use it directly - no need to reprocess
    let fieldsArray = Array.isArray(connector.fields) ? connector.fields : [];
    
    if(fieldsArray.length === 0){
      // Try to reload connectors
      await initPlatformConnector();
      const updatedConnector = platformConnectors[connectorName];
      if(updatedConnector && Array.isArray(updatedConnector.fields) && updatedConnector.fields.length > 0){
        fieldsArray = updatedConnector.fields;
      } else {
        $credentials.hide();
        $options.hide();
        return;
      }
    }

    // Load saved credentials from settings
    const savedCreds = window.mt_primelinkSettings?.platform_connectors?.[connectorName] || {};
    
    // Render credentials fields
    let html = '';
    fieldsArray.forEach((field) => {
      // Use the key from the field object (e.g., 'shop_domain', 'api_key')
      const fieldKey = field.key || '';
      const fieldId = 'mt_primelink-platform-' + fieldKey.replace(/[^a-z0-9-]/gi, '-');
      
      // Use label from field, fallback to key if label doesn't exist
      const fieldLabel = field.label || fieldKey;
      
      // Get saved value if exists
      const savedValue = savedCreds[fieldKey] || '';
      
      html += '<div class="mt_primelink-form-row">';
      html += '<label for="' + fieldId + '">' + escapeHtml(fieldLabel);
      if(field.required) html += ' <span style="color:#f00;">*</span>';
      html += '</label>';
      
      const isPassword = field.type === 'password';
      
      // For BigCommerce access_token, ensure no maxlength restriction
      let inputAttrs = '';
      if(fieldKey === 'access_token' && connectorName === 'bigcommerce'){
        // BigCommerce tokens can be 64+ characters, ensure no maxlength
        inputAttrs = 'maxlength=""';
      } else if(field.maxlength){
        inputAttrs = 'maxlength="' + escapeHtml(field.maxlength) + '"';
      }
      
      if(isPassword){
        html += '<div style="position:relative;">';
        html += '<input type="password" id="' + fieldId + '" class="widefat" placeholder="' + escapeHtml(field.placeholder || '') + '" data-field="' + escapeHtml(fieldKey) + '" value="' + escapeHtml(savedValue) + '" style="padding-right:80px;" ' + inputAttrs + '>';
        html += '<button type="button" class="button" data-toggle-password="' + fieldId + '" style="position:absolute;right:4px;top:50%;transform:translateY(-50%);height:calc(100% - 8px);padding:0 12px;font-size:12px;line-height:1;">Show</button>';
        html += '</div>';
      } else {
        html += '<input type="text" id="' + fieldId + '" class="widefat" placeholder="' + escapeHtml(field.placeholder || '') + '" data-field="' + escapeHtml(fieldKey) + '" value="' + escapeHtml(savedValue) + '" ' + inputAttrs + '>';
      }
      
      if(field.description){
        html += '<p class="description">' + escapeHtml(field.description) + '</p>';
      }
      html += '</div>';
    });
    
    $fields.html(html);
    $credentials.show();
    $options.hide();
    
    // If we have saved credentials, auto-populate platformCredentials
    // User can still modify them if needed, and test connection again
    if(Object.keys(savedCreds).length > 0){
      platformCredentials[connectorName] = savedCreds;
      // Show a message that credentials were loaded from settings
      const $status = $('#mt_primelink-platform-connection-status');
      if($status.length){
        $status.html('<span style="color:#0a0;font-size:12px;">&#10003; Credentials loaded from settings. You can modify them or test connection.</span>');
      }
    }
  });

  $(document).on('click', '#mt_primelink-platform-test-connection', async function(){
    const connectorName = $('#mt_primelink-platform-connector').val();
    if(!connectorName){
      alert('Please select a platform first.');
      return;
    }

    const connector = platformConnectors[connectorName];
    if(!connector){
      alert('Connector not found.');
      return;
    }

    // Collect credentials
    const credentials = {};
    $('#mt_primelink-platform-credentials-fields input').each(function(){
      const $input = $(this);
      const fieldName = $input.data('field');
      if(fieldName){
        credentials[fieldName] = $input.val() || '';
      }
    });

    // Validate required fields
    let missing = [];
    const fieldsObj = connector.fields || {};
    let fieldsToCheck = [];
    
    if(Array.isArray(fieldsObj)){
      fieldsToCheck = fieldsObj;
    } else {
      fieldsToCheck = Object.keys(fieldsObj).map(key => {
        return { key: key, ...fieldsObj[key] };
      });
    }
    
    fieldsToCheck.forEach(field => {
      if(field.required){
        const fieldName = field.key || field.label.toLowerCase().replace(/\s+/g, '_');
        if(!credentials[fieldName] || credentials[fieldName].trim() === ''){
          missing.push(field.label || fieldName);
        }
      }
    });

    if(missing.length > 0){
      alert('Please fill in required fields: ' + missing.join(', '));
      return;
    }

    const $btn = $(this);
    const $status = $('#mt_primelink-platform-connection-status');
    $btn.prop('disabled', true).text('Testing...');
    $status.html('');

    try {
      const res = await restPost('/platform/test-connection', {
        connector: connectorName,
        credentials: credentials
      });

      if(res.success){
        $status.html('<span style="color:#0a0;">&#10003; Connection successful! Fetching data...</span>');
        platformCredentials[connectorName] = credentials;
        $('#mt_primelink-platform-options').show();
        
        // Automatically fetch and preview data after successful connection
        const importType = getCurrentImportType();
        // Normalize import type to data_type format
        let dataType = importType;
        if(dataType === 'product'){
          dataType = 'products';
        } else if(dataType === 'order'){
          dataType = 'orders';
        } else if(dataType === 'customer'){
          dataType = 'customers';
        } else if(dataType === 'coupon'){
          dataType = 'coupons';
        } else if(dataType === 'category'){
          dataType = 'categories';
        } else if(dataType === 'tag'){
          dataType = 'tags';
        } else if(dataType === 'attribute'){
          dataType = 'attributes';
        } else if(dataType === 'variation'){
          dataType = 'variations';
        } else if(dataType === 'review'){
          dataType = 'reviews';
        } else if(dataType === 'download'){
          dataType = 'downloads';
        }
        
        // Automatically trigger fetch and preview
        await fetchAndPreviewPlatformData(connectorName, credentials, dataType);
      } else {
        $status.html('<span style="color:#f00;">&#10007; ' + escapeHtml(res.message || 'Connection failed') + '</span>');
      }
    } catch(err){
      $status.html('<span style="color:#f00;">&#10007; ' + escapeHtml(err.json?.message || 'Connection failed') + '</span>');
    } finally {
      $btn.prop('disabled', false).text('Test Connection');
    }
  });

  $(document).on('change', '#mt_primelink-platform-realtime', function(){
    const enabled = $(this).is(':checked');
    $('#mt_primelink-platform-realtime-options').toggle(enabled);
  });

  // Function to fetch and preview platform data (can be called automatically or manually)
  async function fetchAndPreviewPlatformData(connectorName, credentials, dataType){
    if(!connectorName || !credentials || !dataType){
      console.error('fetchAndPreviewPlatformData: Missing parameters', {
        connectorName: !!connectorName,
        credentials: !!credentials,
        dataType: !!dataType
      });
      return;
    }

    // Validate credentials before sending
    if(!credentials.access_token || credentials.access_token.trim() === ''){
      console.error('fetchAndPreviewPlatformData: Missing or empty access_token', {
        has_access_token: !!credentials.access_token,
        credentials_keys: Object.keys(credentials)
      });
      alert('Error: Access token is missing or empty. Please test the connection again.');
      return;
    }

    // Token length for BigCommerce can vary; we only validate that it is non-empty.
    // Detailed permission/auth issues are handled by server-side error messages.

    const $preview = $('#mt_primelink-platform-preview');
    const $content = $('#mt_primelink-platform-preview-content');
    const $status = $('#mt_primelink-platform-connection-status');
    
    $preview.hide();
    $content.html('');
    if($status.length){
      $status.html('<span style="color:#0a0;">&#10003; Connection successful! Fetching data...</span>');
    }

    try {
      const res = await restPost('/platform/fetch', {
        connector: connectorName,
        credentials: credentials,
        data_type: dataType,
        limit: 5,
        page: 1
      });

      if(res.success){
        let html = '<p><strong>Total items:</strong> ' + (res.total || 0) + '</p>';
        
        if(res.preview){
          html += '<div style="margin-top:12px;padding:12px;background:rgba(0,0,0,0.3);border-radius:4px;max-height:300px;overflow-y:auto;">';
          html += '<h5>Preview (first item converted):</h5>';
          html += '<pre style="white-space:pre-wrap;font-size:12px;">' + escapeHtml(JSON.stringify(res.preview, null, 2)) + '</pre>';
          html += '</div>';
        }

        if(res.data && res.data.length > 0){
          html += '<div style="margin-top:12px;"><strong>Raw data (first ' + res.data.length + ' items):</strong></div>';
          res.data.slice(0, 3).forEach((item, idx) => {
            html += '<div style="margin-top:8px;padding:8px;background:rgba(0,0,0,0.2);border-radius:4px;">';
            html += '<strong>Item ' + (idx + 1) + ':</strong><br>';
            html += '<pre style="white-space:pre-wrap;font-size:11px;margin-top:4px;">' + escapeHtml(JSON.stringify(item, null, 2).substring(0, 500)) + '...</pre>';
            html += '</div>';
          });
        }

        $content.html(html);
        $preview.show();
        
        if($status.length){
          $status.html('<span style="color:#0a0;">&#10003; Connection successful! Data fetched.</span>');
        }

        // Save to draft
        const importId = currentImportId();
        if(importId){
          try {
            await restPost('/import/save-step', {
              import_id: importId,
              step: 2,
              data: {
                source: 'platform',
                connector: connectorName,
                credentials: credentials,
                data_type: dataType,
                realtime_enabled: $('#mt_primelink-platform-realtime').is(':checked'),
                realtime_events: $('.mt_primelink-platform-event:checked').map(function(){ return $(this).val(); }).get()
              }
            });
          } catch(e){
            console.error('Failed to save platform config:', e);
          }
        }
      } else {
        $content.html('<p style="color:#f00;">' + escapeHtml(res.error || 'Failed to fetch data') + '</p>');
        $preview.show();
        if($status.length){
          $status.html('<span style="color:#f00;">&#10007; Failed to fetch data: ' + escapeHtml(res.error || 'Unknown error') + '</span>');
        }
      }
    } catch(err){
      $content.html('<p style="color:#f00;">' + escapeHtml(err.json?.message || 'Failed to fetch data') + '</p>');
      $preview.show();
      if($status.length){
        $status.html('<span style="color:#f00;">&#10007; Failed to fetch data: ' + escapeHtml(err.json?.message || 'Unknown error') + '</span>');
      }
    }
  }

  // Keep the button handler for manual trigger if needed (though button is now hidden)
  $(document).on('click', '#mt_primelink-platform-fetch-preview', async function(){
    const connectorName = $('#mt_primelink-platform-connector').val();
    const importType = getCurrentImportType();
    let dataType = importType;
    if(dataType === 'product'){
      dataType = 'products';
    } else if(dataType === 'order'){
      dataType = 'orders';
    } else if(dataType === 'customer'){
      dataType = 'customers';
    } else if(dataType === 'coupon'){
      dataType = 'coupons';
    } else if(dataType === 'category'){
      dataType = 'categories';
    } else if(dataType === 'tag'){
      dataType = 'tags';
    } else if(dataType === 'attribute'){
      dataType = 'attributes';
    } else if(dataType === 'variation'){
      dataType = 'variations';
    } else if(dataType === 'review'){
      dataType = 'reviews';
    } else if(dataType === 'download'){
      dataType = 'downloads';
    }
    
    const credentials = platformCredentials[connectorName];
    if(!credentials){
      alert('Please test connection first.');
      return;
    }

    await fetchAndPreviewPlatformData(connectorName, credentials, dataType);
  });

  // Platform Connectors in Settings
  $(document).on('change', '#mt_primelink-platform-connector-select', async function(){
    const connectorName = $(this).val();
    const $credentials = $('#mt_primelink-platform-connector-credentials');
    const $fields = $('#mt_primelink-platform-connector-fields');
    
    if(!connectorName){
      $credentials.hide();
      return;
    }

    // Ensure connectors are loaded
    if(Object.keys(platformConnectors).length === 0){
      await initPlatformConnector();
    }

    const connector = platformConnectors[connectorName];
    if(!connector){
      $credentials.hide();
      return;
    }

    let fieldsArray = Array.isArray(connector.fields) ? connector.fields : [];
    
    if(fieldsArray.length === 0){
      await initPlatformConnector();
      const updatedConnector = platformConnectors[connectorName];
      if(updatedConnector && Array.isArray(updatedConnector.fields) && updatedConnector.fields.length > 0){
        fieldsArray = updatedConnector.fields;
      } else {
        $credentials.hide();
        return;
      }
    }

    // Render credentials fields
    let html = '';
    fieldsArray.forEach((field) => {
      const fieldKey = field.key || '';
      const fieldId = 'mt_primelink-settings-platform-' + fieldKey.replace(/[^a-z0-9-]/gi, '-');
      const fieldLabel = field.label || fieldKey;
      
      // Try to load saved credentials
      const savedCreds = window.mt_primelinkSettings?.platform_connectors?.[connectorName] || {};
      const savedValue = savedCreds[fieldKey] || '';
      
      html += '<div class="mt_primelink-form-row">';
      html += '<label for="' + fieldId + '">' + escapeHtml(fieldLabel);
      if(field.required) html += ' <span style="color:#f00;">*</span>';
      html += '</label>';
      
      const isPassword = field.type === 'password';
      
      if(isPassword){
        html += '<div style="position:relative;">';
        html += '<input type="password" id="' + fieldId + '" class="widefat" placeholder="' + escapeHtml(field.placeholder || '') + '" data-field="' + escapeHtml(fieldKey) + '" value="' + escapeHtml(savedValue) + '" style="padding-right:80px;">';
        html += '<button type="button" class="button" data-toggle-password="' + fieldId + '" style="position:absolute;right:4px;top:50%;transform:translateY(-50%);height:calc(100% - 8px);padding:0 12px;font-size:12px;line-height:1;">Show</button>';
        html += '</div>';
      } else {
        html += '<input type="text" id="' + fieldId + '" class="widefat" placeholder="' + escapeHtml(field.placeholder || '') + '" data-field="' + escapeHtml(fieldKey) + '" value="' + escapeHtml(savedValue) + '">';
      }
      
      if(field.description){
        html += '<p class="description">' + escapeHtml(field.description) + '</p>';
      }
      html += '</div>';
    });
    
    $fields.html(html);
    $credentials.show();
  });

  $(document).on('click', '#mt_primelink-platform-connector-test', async function(){
    const connectorName = $('#mt_primelink-platform-connector-select').val();
    if(!connectorName){
      alert('Please select a platform first.');
      return;
    }

    const connector = platformConnectors[connectorName];
    if(!connector){
      alert('Connector not found.');
      return;
    }

    // Collect credentials
    const credentials = {};
    $('#mt_primelink-platform-connector-fields input').each(function(){
      const fieldKey = $(this).data('field');
      if(fieldKey){
        credentials[fieldKey] = $(this).val();
      }
    });

    const $btn = $(this);
    const $status = $('#mt_primelink-platform-connector-status');
    $btn.prop('disabled', true).text('Testing...');
    $status.html('');

    try {
      const res = await restPost('/platform/test-connection', {
        connector: connectorName,
        credentials: credentials
      });

      if(res.success){
        $status.html('<span style="color:#0a0;">&#10003; Connection successful!</span>');
        
        // Save credentials to settings
        if(!window.mt_primelinkSettings) window.mt_primelinkSettings = {};
        if(!window.mt_primelinkSettings.platform_connectors || Array.isArray(window.mt_primelinkSettings.platform_connectors)){
          window.mt_primelinkSettings.platform_connectors = {};
        }
        window.mt_primelinkSettings.platform_connectors[connectorName] = credentials;
        
        // Trigger settings save
        $('#mt_primelink-save-settings').click();
      } else {
        $status.html('<span style="color:#f00;">&#10007; ' + escapeHtml(res.message || 'Connection failed') + '</span>');
      }
    } catch(err){
      $status.html('<span style="color:#f00;">&#10007; ' + escapeHtml(err.json?.message || 'Connection failed') + '</span>');
    } finally {
      $btn.prop('disabled', false).text('Test Connection');
    }
  });

  // Load saved platform credentials on settings page load
  $(document).ready(function(){
    if($('#mt_primelink-platform-connector-select').length && window.mt_primelinkSettings?.platform_connectors){
      // Pre-select connector if credentials exist
      const savedConnectors = Object.keys(window.mt_primelinkSettings.platform_connectors);
      if(savedConnectors.length > 0){
        // Could auto-select first saved connector, but for now just ensure they're available
      }
    }
  });

  // Toggle password visibility
  $(document).on('click', '[data-toggle-password]', function(){
    const fieldId = $(this).data('toggle-password');
    const $input = $('#' + fieldId);
    const $btn = $(this);
    
    if($input.attr('type') === 'password'){
      $input.attr('type', 'text');
      $btn.text('Hide');
    } else {
      $input.attr('type', 'password');
      $btn.text('Show');
    }
  });

  // -----------------------------
  // Export Wizard
  // -----------------------------
  function currentExportId(){
    const url = new URL(window.location.href);
    let id = parseInt(url.searchParams.get('export_id') || '0', 10);
    if(!id){
      const $step = $('[data-export-id]').first();
      id = parseInt($step.data('export-id') || '0', 10);
    }
    return id || 0;
  }

  function setExportIdEverywhere(exportId){
    const url = new URL(window.location.href);
    url.searchParams.set('export_id', exportId);
    history.replaceState({}, '', url.toString());

    $('#mt-primelink-next-step, #mt-primelink-finish-export').data('export-id', exportId);
  }

  function getExportStepData(){
    const data = {};
    $('.mt-primelink-wizard__body').find('input, select, textarea').each(function(){
      const $el = $(this);
      const name = $el.attr('name');
      if(!name) return;

      if($el.is(':radio')){
        if($el.is(':checked')) {
          setNestedValue(data, name, $el.val());
        }
      } else if($el.is(':checkbox')){
        if($el.is(':checked')){
          const val = $el.val();
          if(name.indexOf('[]') !== -1){
            // Handle array checkboxes like filters[categories][]
            const nameBase = name.replace(/\[\]$/, '');
            if(!getNestedValue(data, nameBase)){
              setNestedValue(data, nameBase, []);
            }
            const arr = getNestedValue(data, nameBase);
            arr.push(val);
          } else {
            setNestedValue(data, name, 1);
          }
        }
      } else {
        setNestedValue(data, name, $el.val());
      }
    });
    return data;
  }

  function setNestedValue(obj, path, value){
    const keys = path.split(/[\[\]]/).filter(k => k);
    let current = obj;
    for(let i = 0; i < keys.length - 1; i++){
      const key = keys[i];
      if(!current[key] || typeof current[key] !== 'object'){
        current[key] = {};
      }
      current = current[key];
    }
    current[keys[keys.length - 1]] = value;
  }

  function getNestedValue(obj, path){
    const keys = path.split(/[\[\]]/).filter(k => k);
    let current = obj;
    for(let i = 0; i < keys.length; i++){
      if(!current || typeof current !== 'object') return undefined;
      current = current[keys[i]];
    }
    return current;
  }

  // Export wizard next step
  $(document).on('click', '#mt-primelink-next-step', async function(e){
    e.preventDefault();

    const step = getStep();
    const nextStep = step + 1;
    let exportId = parseInt($(this).data('export-id'), 10) || currentExportId();

    try {
      if(!exportId){
        const draft = await restPost('/export/create-draft', {});
        exportId = draft.export_id;
        setExportIdEverywhere(exportId);
      }

      // For step 2, use mapping collection (similar to import step 5)
      const payload = (step === 2) ? collectExportMappingState() : getExportStepData();
      if (step === 2) {
        const mapping = payload.mapping || {};
        if (Object.keys(mapping).length === 0) {
          showToastOrAlert('warning', 'Map at least one field before continuing.', 'Export');
          return;
        }
      }
      
      // Auto-set export_type for step 1 based on export_type from URL
      if(step === 1){
        const url = new URL(window.location.href);
        const exportType = url.searchParams.get('export_type') || '';
        if(exportType){
          payload.export_type = exportType;
        }
      }

      await restPost('/export/save-step', {
        export_id: exportId,
        step: step,
        data: payload
      });

      const url = new URL(window.location.href);
      url.searchParams.set('step', nextStep);
      url.searchParams.set('export_id', exportId);
      window.location.href = url.toString();

    } catch(err){
      showToastOrAlert('error', 'Save failed: ' + (err.json?.message || err.status || 'unknown'), 'Export');
    }
  });

  // Export mapping state collection (similar to import step 5)
  function collectExportMappingState(){
    const mapping = {};
    
    // Collect from standard slots
    $('.mt_primelink-export-step-2 .mt_primelink-map-slot').each(function(){
      const target = $(this).data('target');
      const source = $(this).find('.mt_primelink-map-input').val() || '';
      let cfg = {};
      try {
        cfg = JSON.parse($(this).find('.mt_primelink-map-config').val() || '{}');
      } catch(e){ cfg = {}; }

      if(target && source){
        mapping[target] = { source, config: JSON.stringify(cfg || {}) };
      }
    });
    
    // Also collect from custom columns
    $('#mt_primelink-custom-export-columns-wrap .mt_primelink-map-slot').each(function(){
      const target = $(this).data('target');
      const source = $(this).find('.mt_primelink-map-input').val() || '';
      let cfg = {};
      try {
        cfg = JSON.parse($(this).find('.mt_primelink-map-config').val() || '{}');
      } catch(e){ cfg = {}; }

      if(target && source){
        mapping[target] = { source, config: JSON.stringify(cfg || {}) };
      }
    });

    // ACF export fields
    const acfFields = [];
    $('#mt_primelink-acf-export-fields-wrap .mt_primelink-acf-field').each(function(){
      const $row   = $(this);
      const label  = $row.find('.mt_primelink-acf-label').val() || '';
      const key    = $row.find('.mt_primelink-acf-key').val() || '';
      const source = $row.find('.mt_primelink-map-input').val() || '';
      let cfg = {};
      try {
        cfg = JSON.parse($row.find('.mt_primelink-map-config').val() || '{}');
      } catch(e){ cfg = {}; }

      if (key) {
        acfFields.push({ label, key, source, ...(cfg || {}) });
        if (source) {
          mapping[key] = { source, config: JSON.stringify(cfg || {}) };
        }
      }
    });
    
    return {
      mapping: mapping,
      row_filters: collectFilterRowsData(),
      custom_aliases: collectAliasState(),
      acf_fields: acfFields,
    };
  }

  // Persist export step 2 mapping to draft (debounced)
  let mt_primelinkExportStep2SaveTimer = null;
  function saveExportStep2Mapping(immediate){
    if(mt_primelinkExportStep2SaveTimer){
      clearTimeout(mt_primelinkExportStep2SaveTimer);
    }

    const runner = async () => {
      let exportId = currentExportId() || parseInt($('.mt_primelink-export-step-2').data('export-id'), 10) || 0;
      if(!exportId){
        try{
          const draft = await restPost('/export/create-draft', {});
          exportId = draft.export_id || 0;
          if(exportId){
            setExportIdEverywhere(exportId);
            $('.mt_primelink-export-step-2').attr('data-export-id', exportId);
          }
        }catch(e){
          console.error('Export ID missing:', e);
          throw e; // Re-throw so caller can handle
        }
      }
      const payload = collectExportMappingState();
      try{
        await restPost('/export/save-step', {
          export_id: exportId,
          step: 2,
          data: payload
        });
      } catch(err){
        console.error('Save failed:', err);
        throw err; // Re-throw so caller can handle
      }
    };

    if(immediate){
      return runner(); // Return promise for await
    }

    mt_primelinkExportStep2SaveTimer = setTimeout(runner, 100);
    return Promise.resolve(); // Return resolved promise for non-immediate case
  }

  // Auto-save export mapping when changes occur
  $(document).on('change blur', '.mt_primelink-export-step-2 .mt_primelink-map-input, .mt_primelink-export-step-2 .mt_primelink-map-config', function(){
    saveExportStep2Mapping();
  });

  // Also handle custom columns
  $(document).on('change blur', '#mt_primelink-custom-export-columns-wrap .mt_primelink-map-input, #mt_primelink-custom-export-columns-wrap .mt_primelink-map-config', function(){
    saveExportStep2Mapping();
  });

  // Auto-save when drag & drop occurs in export step 2
  $(document).on('drop', '.mt_primelink-export-step-2 .mt-map-slot__drop', function(){
    setTimeout(() => saveExportStep2Mapping(), 100);
  });

  // Add custom export column
  $(document).on('click', '#mt_primelink-add-custom-export-column', function(){
    const existingCount = $('#mt_primelink-custom-export-columns-wrap .mt_primelink-map-slot').length;
    const customId = 'custom_column_' + (existingCount + 1);
    
    const html = 
      '<div class="mt_primelink-map-slot unmapped" data-target="' + escapeHtml(customId) + '">' +
        '<div class="mt_primelink-map-label">' +
          '<span class="mt_primelink-map-label__text" data-editable="true" title="Click to rename">' + escapeHtml(customId) + '</span>' +
          '<input type="text" class="mt_primelink-custom-column-name" style="display:none;width:200px;padding:2px 6px;font-size:13px;" value="' + escapeHtml(customId) + '" />' +
          '<button type="button" class="button-link-delete mt_primelink-map-slot-remove" title="Remove column">&times;</button>' +
        '</div>' +
        '<div class="mt_primelink-map-drop mt-map-slot__drop">' +
          '<span class="mt_primelink-muted">Drop field here</span>' +
        '</div>' +
        '<input type="hidden" class="mt_primelink-map-input" value="" />' +
        '<input type="hidden" class="mt_primelink-map-config" value="" />' +
      '</div>';
    
    $('#mt_primelink-custom-export-columns-wrap').append(html);
    
    // Initialize drag & drop for the new slot
    bindDnD();
    
    // Save mapping
    saveExportStep2Mapping();
  });

  // Remove custom export column
  $(document).on('click', '#mt_primelink-custom-export-columns-wrap .mt_primelink-map-slot-remove', function(){
    $(this).closest('.mt_primelink-map-slot').remove();
    saveExportStep2Mapping();
    loadExportPreview();
  });

  // Edit custom column name (click to edit)
  $(document).on('click', '#mt_primelink-custom-export-columns-wrap .mt_primelink-map-label__text[data-editable="true"]', function(e){
    e.stopPropagation();
    const $text = $(this);
    const $input = $text.siblings('.mt_primelink-custom-column-name');
    const $slot = $text.closest('.mt_primelink-map-slot');
    
    $text.hide();
    $input.show().focus().select();
  });

  // Save custom column name (on blur or Enter)
  $(document).on('blur keydown', '#mt_primelink-custom-export-columns-wrap .mt_primelink-custom-column-name', function(e){
    if(e.type === 'keydown' && e.keyCode !== 13) return; // Only handle Enter key
    
    const $input = $(this);
    const $text = $input.siblings('.mt_primelink-map-label__text');
    const $slot = $input.closest('.mt_primelink-map-slot');
    const newName = $input.val().trim() || $slot.data('target'); // Fallback to target if empty
    
    // Update display text
    $text.text(newName);
    $text.show();
    $input.hide();
    
    // Update config with column_header
    let cfg = {};
    try {
      cfg = JSON.parse($slot.find('.mt_primelink-map-config').val() || '{}');
    } catch(e){ cfg = {}; }
    
    cfg.column_header = newName;
    $slot.find('.mt_primelink-map-config').val(JSON.stringify(cfg));
    
    // Save mapping
    saveExportStep2Mapping();
    loadExportPreview();
  });

  // Select/Deselect all fields
  $(document).on('click', '#mt_primelink-select-all-fields', function(){
    $('input[name="fields[]"]').prop('checked', true);
  });

  $(document).on('click', '#mt_primelink-deselect-all-fields', function(){
  // ACF export fields: add/remove & key sync
  $(document).on('click', '#mt_primelink-add-acf-export-field', function(){
    const i = $('#mt_primelink-acf-export-fields-wrap .mt_primelink-acf-field').length;
    const html =
      '<div class="mt_primelink-acf-field" data-index="'+i+'">' +
        '<div class="mt_primelink-acf-row">' +
          '<input type="text" class="mt_primelink-acf-label" placeholder="ACF Field Label" />' +
          '<input type="text" class="mt_primelink-acf-key" placeholder="ACF meta key (e.g. field_XXXX or my_field)" />' +
        '</div>' +
        '<div class="mt_primelink-map-slot unmapped" data-target="">' +
          '<div class="mt_primelink-map-drop mt-map-slot__drop"><span class="mt_primelink-muted">Drop field here</span></div>' +
        '</div>' +
        '<input type="hidden" class="mt_primelink-map-input" value="" />' +
        '<input type="hidden" class="mt_primelink-map-config" value="" />' +
        '<button type="button" class="button-link-delete mt_primelink-acf-export-remove">Remove</button>' +
      '</div>';
    $('#mt_primelink-acf-export-fields-wrap').append(html);
    bindDnD();
  });

  $(document).on('click', '.mt_primelink-acf-export-remove', function(){
    $(this).closest('.mt_primelink-acf-field').remove();
    saveExportStep2Mapping();
  });

  // When meta key changes, update data-target to key (so mapping saves correctly)
  $(document).on('input change', '#mt_primelink-acf-export-fields-wrap .mt_primelink-acf-key', function(){
    const key = ($(this).val() || '').trim();
    const $field = $(this).closest('.mt_primelink-acf-field');
    const $slot = $field.find('.mt_primelink-map-slot');
    $slot.attr('data-target', key || '');
    // optional: update label placeholder if empty
    const $label = $field.find('.mt_primelink-acf-label');
    if(!$label.val().trim() && key){
      $label.val(key);
    }
    saveExportStep2Mapping();
  });

    $('input[name="fields[]"]').prop('checked', false);
  });

  // Load export preview (step 2)
  async function loadExportPreview(){
    const $preview = $('#mt-primelink-export-preview');
    if(!$preview.length) return;

    const exportId = parseInt($preview.data('export-id'), 10) || currentExportId();
    if(!exportId) {
      $preview.html('<div class="mt_primelink-empty">Please complete step 1 first.</div>');
      return;
    }

    try {
      const res = await restPost('/export/preview', {
        export_id: exportId,
        page: 1,
        per_page: 10
      });

      const headers = res.headers || [];
      const rows = res.rows || [];
      const total = res.total || 0;

      if (!total || rows.length === 0) {
        $preview.html('<div class="mt_primelink-empty">No items found. Please configure filters.</div>');
        return;
      }

      // Get current mapping state
      const mappingState = collectExportMappingState();
      const mapping = mappingState.mapping || {};

      if(Object.keys(mapping).length === 0){
        $preview.html('<div class="mt_primelink-empty">No columns mapped yet. Drag fields from left panel to create export columns.</div>');
        return;
      }

      // Use first row for preview (or index if provided)
      const previewIndex = window.mt_primelinkExportPreviewIndex || 0;
      const currentRow = rows[Math.min(previewIndex, rows.length - 1)] || [];
      const rowNumber = Math.min(previewIndex, rows.length - 1) + 1;

      // Build mapped values - match headers with mapping
      // IMPORTANT: Headers and rows are built in the same order as mapping keys in PHP
      // We need to match by index, but ensure we use the same order as backend
      const mappingKeys = Object.keys(mapping);
      const mapped = {};
      
      // Match by index - headers and rows are in the same order as mapping keys
      mappingKeys.forEach((target, index) => {
        if(index >= headers.length || index >= currentRow.length){
          mapped[target] = '';
          return;
        }
        
        // Get value directly by index (rows are built in same order as headers/mapping keys)
        const value = currentRow[index] || '';
        mapped[target] = value;
      });

      // Render vertical table like import step 5
      let html = '<div class="mt-preview-meta"><strong>Type:</strong> Export</div>';

      // Navigator
      html += '<div class="mt-preview-nav">';
      html += '  <button type="button" class="button mt-export-preview-prev" ' + (previewIndex <= 0 ? 'disabled' : '') + ' data-index="' + Math.max(0, previewIndex-1) + '">&lsaquo; Prev</button>';
      html += '  <span class="mt-preview-counter">Row ' + rowNumber + ' / ' + total + '</span>';
      html += '  <button type="button" class="button button-primary mt-export-preview-next" ' + (previewIndex >= rows.length - 1 ? 'disabled' : '') + ' data-index="' + Math.min(rows.length - 1, previewIndex+1) + '">Next &rsaquo;</button>';
      html += '</div>';

      // Vertical table
      html += '<div class="mt-preview-vertical-wrap">';
      html += '<table class="mt-preview-vertical">';
      html += '<thead><tr><th>Target Field</th><th>Mapped Value</th></tr></thead><tbody>';

      Object.keys(mapping).forEach(target => {
        const config = mapping[target];
        const configObj = typeof config.config === 'string' ? JSON.parse(config.config || '{}') : (config.config || {});
        const customHeader = configObj.column_header || '';
        const fieldLabel = customHeader || (target.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()));
        
        let val = mapped[target] || '';
        const rawVal = val;

        if(Array.isArray(val)){
          val = val.map(v => "- " + v).join("\n");
        } else {
          val = (val === undefined || val === null) ? "" : String(val);
        }

        html += '<tr>';
        html += '  <td class="mt-preview-field">' + escapeHtml(fieldLabel) + '</td>';
        html += '  <td class="mt-preview-value"><pre style="margin:0;white-space:pre-wrap;">' + escapeHtml(val) + '</pre></td>';
        html += '</tr>';
      });

      html += '</tbody></table></div>';
      $preview.html(html);

      // Store index for navigation
      window.mt_primelinkExportPreviewIndex = previewIndex;

    } catch(err){
      $preview.html('<div class="mt_primelink-empty error">Failed to load preview: ' + (err.json?.message || 'Unknown error') + '</div>');
    }
  }

  // Auto-load export preview when step 2 is loaded
  $(document).ready(function(){
    if($('.mt_primelink-export-step-2').length){
      // Load existing custom columns from draft
      loadExportCustomColumns();
      // Load existing ACF export fields
      loadExportACFFields();
      // Wait a bit for mapping to be loaded, then load preview
      setTimeout(() => {
        loadExportPreview();
      }, 500);
    }
  });

  // Load custom columns from draft
  async function loadExportCustomColumns(){
    const exportId = currentExportId();
    if(!exportId) return;

    try {
      const draft = await restPost('/export/get-draft', { export_id: exportId });
      if(!draft || !draft.step_data || !draft.step_data[2]) return;

      const step2Data = draft.step_data[2];
      const mapping = step2Data.mapping || {};
      
      // Find custom columns (those starting with custom_column_)
      const customColumns = {};
      Object.keys(mapping).forEach(key => {
        if(key.startsWith('custom_column_')){
          customColumns[key] = mapping[key];
        }
      });

      if(Object.keys(customColumns).length === 0) return;

      // Clear existing custom columns
      $('#mt_primelink-custom-export-columns-wrap').empty();

      // Add custom columns
      Object.keys(customColumns).forEach(customId => {
        const columnConfig = customColumns[customId];
        const source = columnConfig.source || '';
        let cfg = {};
        try {
          cfg = typeof columnConfig.config === 'string' ? JSON.parse(columnConfig.config || '{}') : (columnConfig.config || {});
        } catch(e){ cfg = {}; }

        // Get custom column name from config or use ID
        const columnName = cfg.column_header || customId;
        
        const html = 
          '<div class="mt_primelink-map-slot' + (source ? '' : ' unmapped') + '" data-target="' + escapeHtml(customId) + '">' +
            '<div class="mt_primelink-map-label">' +
              '<span class="mt_primelink-map-label__text" data-editable="true" title="Click to rename">' + escapeHtml(columnName) + '</span>' +
              '<input type="text" class="mt_primelink-custom-column-name" style="display:none;width:200px;padding:2px 6px;font-size:13px;" value="' + escapeHtml(columnName) + '" />' +
              '<button type="button" class="button-link-delete mt_primelink-map-slot-remove" title="Remove column">&times;</button>' +
            '</div>' +
            '<div class="mt_primelink-map-drop mt-map-slot__drop">' +
              (source ? buildChip(source) : '<span class="mt_primelink-muted">Drop field here</span>') +
            '</div>' +
            '<input type="hidden" class="mt_primelink-map-input" value="' + escapeHtml(source) + '" />' +
            '<input type="hidden" class="mt_primelink-map-config" value="' + escapeHtml(JSON.stringify(cfg || {})) + '" />' +
          '</div>';
        
        $('#mt_primelink-custom-export-columns-wrap').append(html);
      });

      // Initialize drag & drop
      bindDnD();
    } catch(err){
      console.error('Failed to load custom columns:', err);
    }
  }

  // Load ACF export fields from draft
  async function loadExportACFFields(){
    const exportId = currentExportId();
    if(!exportId) return;

    try {
      const draft = await restPost('/export/get-draft', { export_id: exportId });
      if(!draft || !draft.step_data || !draft.step_data[2]) return;

      const step2Data = draft.step_data[2];
      const acfFields = step2Data.acf_fields || [];
      if(!acfFields.length) return;

      const wrap = $('#mt_primelink-acf-export-fields-wrap');
      if(!wrap.length) return;

      wrap.empty();
      acfFields.forEach((acf, index) => {
        const hasSource = acf.source && acf.source.trim();
        const unmappedClass = hasSource ? '' : ' unmapped';
        const dropHtml = hasSource
          ? buildChip(acf.source)
          : '<span class="mt_primelink-muted">Drop field here</span>';

        const html =
          '<div class="mt_primelink-acf-field" data-index="'+index+'">' +
            '<div class="mt_primelink-acf-row">' +
              '<input type="text" class="mt_primelink-acf-label" placeholder="ACF Field Label" value="'+escapeHtml(acf.label || '')+'" />' +
              '<input type="text" class="mt_primelink-acf-key" placeholder="ACF meta key (e.g. field_XXXX or my_field)" value="'+escapeHtml(acf.key || '')+'" />' +
            '</div>' +
            '<div class="mt_primelink-map-slot'+unmappedClass+'" data-target="'+escapeHtml(acf.key || '')+'">' +
              '<div class="mt_primelink-map-drop mt-map-slot__drop">' + dropHtml + '</div>' +
            '</div>' +
            '<input type="hidden" class="mt_primelink-map-input" value="'+escapeHtml(acf.source || '')+'" />' +
            '<input type="hidden" class="mt_primelink-map-config" value="'+escapeHtml(JSON.stringify(acf.config || {}))+'" />' +
            '<button type="button" class="button-link-delete mt_primelink-acf-export-remove">Remove</button>' +
          '</div>';
        wrap.append(html);
      });

      bindDnD();
    } catch(err){
      console.error('Failed to load ACF export fields:', err);
    }
  }

  // Reload preview when mapping changes
  $(document).on('change drop', '.mt_primelink-export-step-2 .mt_primelink-map-input, .mt_primelink-export-step-2 .mt-map-slot__drop', function(){
    setTimeout(() => {
      saveExportStep2Mapping();
      window.mt_primelinkExportPreviewIndex = 0; // Reset to first row
      loadExportPreview();
    }, 300);
  });

  // Export preview navigation
  $(document).on('click', '.mt-export-preview-prev, .mt-export-preview-next', function(){
    const index = parseInt($(this).data('index'), 10) || 0;
    window.mt_primelinkExportPreviewIndex = index;
    loadExportPreview();
  });

  // Reload preview when mapping is cleared (for export step 2)
  $(document).on('click', '.mt_primelink-export-step-2 .mt_primelink-suggestion-clear, .mt_primelink-export-step-2 #mt_primelink-clear-mapping', function(){
    setTimeout(() => {
      saveExportStep2Mapping();
      loadExportPreview();
    }, 300);
  });

  // Reload preview when slot is cleared manually
  $(document).on('click', '.mt_primelink-export-step-2 .mt-map-slot__drop .mt_primelink-chip', function(e){
    if(e.ctrlKey || e.metaKey){
      e.preventDefault();
      const $slot = $(this).closest('.mt_primelink-map-slot');
      $slot.find('.mt-map-slot__drop').html('<span class="mt_primelink-muted">Drop field here</span>');
      $slot.find('.mt_primelink-map-input').val('');
      $slot.find('.mt_primelink-map-config').val('');
      $slot.find('.mt_primelink-map-edit').prop('disabled', true);
      setTimeout(() => {
        saveExportStep2Mapping();
        loadExportPreview();
      }, 300);
    }
  });

  // Auto-map for export (similar to import but uses WooCommerce fields)
  function autoMapExportSuggestions(){
    // Get available WooCommerce fields from the left panel
    const sources = [];
    $('.mt_primelink-export-step-2 .mt_primelink-file-field').each(function(){
      const field = $(this).data('field') || $(this).find('.mt_primelink-file-field__name').text().trim();
      if(field){
        sources.push(field);
      }
    });

    if(!sources.length){
      showToastOrAlert('warning', 'No WooCommerce fields available.', 'Mapping');
      return;
    }

    const norm = s => (s || '').toString().toLowerCase().replace(/[^a-z0-9]+/g, '');

    // Target aliases for export columns (matching WooCommerce field names)
    const targetAliases = {
      id:                ['id','productid','product_id'],
      title:             ['title','name','productname','product_title'],
      sku:               ['sku','cod','code'],
      price:             ['price','regularprice','regular_price'],
      sale_price:        ['saleprice','sale_price','discountprice'],
      stock_quantity:    ['stock','stockquantity','stock_quantity','qty','quantity'],
      stock_status:      ['stockstatus','stock_status'],
      description:       ['description','desc','content'],
      short_description: ['shortdescription','short_desc','excerpt'],
      categories:        ['categories','category','cats'],
      tags:              ['tags','tag'],
      featured_image:    ['image','featuredimage','featured_image','mainimage'],
      gallery_images:    ['gallery','galleryimages','gallery_images','images'],
    };

    // Merge custom aliases
    $('.mt_primelink-alias-row').each(function(){
      const target = ($(this).find('.mt_primelink-alias-target').val() || '').trim();
      const vals = ($(this).find('.mt_primelink-alias-values').val() || '').split(',').map(v=>v.trim()).filter(Boolean);
      if(!target || !vals.length) return;
      if(!targetAliases[target]) targetAliases[target] = [];
      targetAliases[target] = targetAliases[target].concat(vals.map(v=>norm(v)));
    });

    const normalizedSources = sources.map(s => ({raw:s, n:norm(s)}));

    function similarity(a,b){
      const la = a.length, lb = b.length;
      if(!la || !lb) return 0;
      const dp = Array.from({length: la+1}, () => new Array(lb+1).fill(0));
      for(let i=0;i<=la;i++) dp[i][0]=i;
      for(let j=0;j<=lb;j++) dp[0][j]=j;
      for(let i=1;i<=la;i++){
        for(let j=1;j<=lb;j++){
          const cost = a[i-1] === b[j-1] ? 0 : 1;
          dp[i][j] = Math.min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+cost);
        }
      }
      const dist = dp[la][lb];
      return 1 - (dist / Math.max(la, lb));
    }

    function findBestMatch(target){
      const nTarget = norm(target);
      let best = { score: 0, source: null };

      // Exact match first
      normalizedSources.forEach(({raw,n}) => {
        if(n === nTarget && best.score < 1){
          best = { score: 1, source: raw };
        }
      });
      if(best.source) return best;

      // Alias-based
      const aliases = targetAliases[target] || [];
      normalizedSources.forEach(({raw,n}) => {
        if(aliases.includes(n)){
          best = { score: 0.99, source: raw };
        }
      });
      if(best.source) return best;

      // Fuzzy match
      normalizedSources.forEach(({raw,n}) => {
        const score = similarity(n, nTarget);
        if(score > best.score){
          best = { score, source: raw };
        }
      });
      if(best.score >= 0.65){
        return best;
      }
      return { score:0, source:null };
    }

    function buildChip(field){
      const $field = $('.mt_primelink-export-step-2 .mt_primelink-file-field[data-field="' + field + '"]');
      const label = $field.find('.mt_primelink-file-field__name').text() || field;
      const safe = field || '(unknown)';
      return '<span class="mt_primelink-chip" data-source="'+escapeHtml(safe)+'">'+escapeHtml(label)+' <a href="#" class="mt_primelink-chip-remove" aria-label="Remove">x</a><span class="mt_primelink-chip-edit-label">edit</span></span>';
    }

    let mappedCount = 0;
    $('.mt_primelink-export-step-2 .mt_primelink-map-slot').each(function(){
      const $slot = $(this);
      const target = $slot.data('target') || '';
      const $input = $slot.find('.mt_primelink-map-input');
      if(($input.val() || '').trim()){
        return; // already mapped
      }

      const match = findBestMatch(target);
      if(match.source){
        $slot.find('.mt-map-slot__drop').html(buildChip(match.source));
        $input.val(match.source);
        // Enable edit button and make it visible
        $slot.find('.mt_primelink-map-edit').prop('disabled', false).addClass('is-visible');
        mappedCount++;
      }
    });

    if(mappedCount){
      // Save mapping and wait for it to complete before loading preview
      (async () => {
        try {
          await saveExportStep2Mapping(true); // immediate save (returns promise)
          // Reload preview after save completes
          await loadExportPreview();
          showToastOrAlert('success', 'Auto-map applied to ' + mappedCount + ' columns.', 'Auto-Map Applied');
        } catch(err) {
          console.error('Auto-map save/preview error:', err);
          showToastOrAlert('warning', 'Auto-map applied to ' + mappedCount + ' columns, but preview may need a refresh.', 'Auto-Map');
        }
      })();
    } else {
      showToastOrAlert('info', 'No auto-map matches found.', 'Auto-Map');
    }
  }

  // -----------------------------
  // Export Templates (Save/Load/List/Delete)
  // -----------------------------

  async function refreshExportTemplateList(selectNameToKeep){
    const $select = $('#mt_primelink-load-template');
    if(!$select.length) return;

    // Get export type using helper function
    const exportType = await getExportType();
    
    // If exportType is undefined or empty, don't make the request (would return all templates)
    if(!exportType || exportType === ''){
      return;
    }

    try {
      // Use AJAX instead of REST (simpler and more reliable)
      const res = await $.ajax({
        url: mtPrimeLink.ajaxUrl,
        type: 'GET',
        data: {
          action: 'mt_primelink_export_list_templates',
          type: exportType,
          nonce: mtPrimeLink.ajaxNonce,
          ts: Date.now() // cache buster
        },
        dataType: 'json'
      });

      const names = (res.data && res.data.templates) || [];

      // Clear and rebuild dropdown
      let html = '<option value="">Load existing template...</option>';
      if (names.length > 0) {
      names.forEach(n=>{
        // Remove prefix for display
        const displayName = n.replace(/^(order|product|customer|coupon|category|tag):/, '');
        html += '<option value="'+escapeHtml(n)+'">'+escapeHtml(displayName)+'</option>';
      });
      }

      $select.html(html);

      if(selectNameToKeep){
        $select.val(selectNameToKeep);
      }
    } catch(e){
      // If list fails, keep current options
    }
  }

  function applyExportTemplateToUI(data){
    if(!data || typeof data !== 'object') return;

    const mapping = data.mapping || {};
    const row_filters = data.row_filters || [];
    const custom_aliases = data.custom_aliases || [];

    // Apply mapping to slots
    $('.mt_primelink-export-step-2 .mt_primelink-map-slot, #mt_primelink-custom-export-columns-wrap .mt_primelink-map-slot').each(function(){
      const target = $(this).data('target');
      const cfg = mapping[target] || null;

      const $drop  = $(this).find('.mt-map-slot__drop');
      const $input = $(this).find('.mt_primelink-map-input');
      const $conf  = $(this).find('.mt_primelink-map-config');

      if(cfg && cfg.source){
        $drop.html(buildChip(cfg.source));
        $input.val(cfg.source);
        $conf.val(cfg.config || '{}');
        // Remove unmapped class when source is set
        $(this).removeClass('unmapped');
        // Enable edit button when source is set
        $(this).find('.mt_primelink-map-edit').prop('disabled', false).addClass('is-visible');
      } else {
        $drop.html('<span class="mt_primelink-muted">Drop field here</span>');
        $input.val('');
        $conf.val('{}');
        // Add unmapped class when no source (for custom export columns)
        if($(this).closest('#mt_primelink-custom-export-columns-wrap').length){
          $(this).addClass('unmapped');
        }
        // Disable edit button when no source
        $(this).find('.mt_primelink-map-edit').prop('disabled', true).removeClass('is-visible');
      }
    });

    // Apply row filters
    if(row_filters && row_filters.length > 0){
      // TODO: Apply row filters to UI
    }

    // Apply custom aliases
    const aliasWrap = $('#mt_primelink-alias-wrap').empty();
    if(custom_aliases && custom_aliases.length){
      custom_aliases.forEach(a=>{
        aliasWrap.append(renderAliasRow(a.target || '', (a.aliases || []).join(', ')));
      });
    } else {
      aliasWrap.html('<div class="mt_primelink-empty">No custom aliases yet.</div>');
    }

    bindDnD();
    saveExportStep2Mapping();
    loadExportPreview();
  }

  // Save export template
  $(document).on('click', '#mt_primelink-save-template', async function(){
    // Check if we're on export page
    if(!$('.mt_primelink-export-step-2').length && !$('body').hasClass('mt_primelink-export-wizard')){
      return; // Not on export page, let import handler take over
    }
    const name = ($('#mt_primelink-template-name').val() || '').trim();
    if(!name){
      showToastOrAlert('warning', 'Please enter a template name.', 'Template');
      return;
    }

    // Get export type using helper function
    const exportType = await getExportType();

    const payload = collectExportMappingState();

    try {
      const saved = await restPost('/export/templates/save', {
        name: name,
        data: payload,
        type: exportType
      });

      // Clear input
      $('#mt_primelink-template-name').val('');

      // Refresh template list with a small delay to ensure server has processed the save
      setTimeout(async () => {
        // Ensure we have the export type before refreshing - get it fresh
        const currentExportType = await getExportType();
        if(currentExportType && currentExportType !== ''){
          await refreshExportTemplateList(saved.name || name);
        }
      }, 300);

      showToastOrAlert('success', 'Template saved.', 'Template');
    } catch(e){
      showToastOrAlert('error', 'Template save failed: ' + (e.json?.message || 'Unknown error'), 'Template');
    }
  });

  // Load export template
  $(document).on('click', '#mt_primelink-load-template-btn', async function(){
    // Check if we're on export page
    if(!$('.mt_primelink-export-step-2').length && !$('body').hasClass('mt_primelink-export-wizard')){
      return; // Not on export page, let import handler take over
    }
    const name = $('#mt_primelink-load-template').val();
    if(!name){
      showToastOrAlert('warning', 'Please select a template.', 'Template');
      return;
    }


    try {
      const res = await restPost('/export/templates/load', {
        name: name
      });

      // WooCommerce REST API returns: { success: true, data: {...} }
      if(res && res.success === true && res.data){
        applyExportTemplateToUI(res.data);
        showToastOrAlert('success', 'Template loaded.', 'Template');
        return; // Exit early to prevent any other code from running
      } else if(res && res.data){
        // Fallback: if data exists directly
        applyExportTemplateToUI(res.data);
        showToastOrAlert('success', 'Template loaded.', 'Template');
        return; // Exit early
      } else if(res && typeof res === 'object' && Object.keys(res).length > 0 && !res.message){
        // Fallback: if response is the data itself (but not an error message)
        applyExportTemplateToUI(res);
        showToastOrAlert('success', 'Template loaded.', 'Template');
        return; // Exit early
      } else {
        showToastOrAlert('error', 'Template load failed: Invalid response.', 'Template');
        return; // Exit early
      }
    } catch(e){
      console.error('[Export Templates Load] Load error:', e);
      // Only show error if it's a real error
      const errorMsg = (e.json && e.json.message) || e.message || 'Unknown error';
      showToastOrAlert('error', 'Template load failed: ' + errorMsg, 'Template');
    }
  });

  // Delete export template
  $(document).on('click', '.mt_primelink-export-step-2 #mt_primelink-delete-template', async function(){
    const name = $('#mt_primelink-load-template').val();
    if(!name){
      showToastOrAlert('warning', 'Please select a template to delete.', 'Template');
      return;
    }

    if(!confirm('Are you sure you want to delete this template?')){
      return;
    }

    try {
      await restPost('/export/templates/delete', {
        name: name
      });

      $('#mt_primelink-load-template').val('');
      await refreshExportTemplateList();
      showToastOrAlert('success', 'Template deleted.', 'Template');
    } catch(e){
      showToastOrAlert('error', 'Template delete failed: ' + (e.json?.message || 'Unknown error'), 'Template');
    }
  });

  // Init
  $(document).ready(function(){
    initWizardUI();
    
    // Initialize export wizard if on export page
    if($('body').hasClass('mt_primelink-export-wizard')){
      const exportId = currentExportId();
      if(exportId > 0){
        setExportIdEverywhere(exportId);
      }
      // Load export templates list
      if($('.mt_primelink-export-step-2').length){
        refreshExportTemplateList();
      }
    }
});



  // ============================================
  // Statistics & Analytics Dashboard
  // ============================================

/**
 * Statistics & Analytics Dashboard JavaScript
 *
 * @package PrimeLink
 */

    let charts = {};
    let currentStats = null;
    let currentTab = 'import';
    let currentImportType = '';
    let currentExportType = '';

    // Tab switching
    function switchTab(tab) {
        currentTab = tab;
        $('.mt_primelink-tab-button').removeClass('active');
        $(`.mt_primelink-tab-button[data-tab="${tab}"]`).addClass('active');
        $('.mt_primelink-tab-content').hide();
        $(`#tab-${tab}`).show();
        
        // Load statistics for the active tab
        if (tab === 'import') {
            const dateFrom = $('#mt_primelink-stats-date-from').val() || '';
            const dateTo = $('#mt_primelink-stats-date-to').val() || '';
            loadStatistics(dateFrom, dateTo, currentImportType);
        } else {
            const dateFrom = $('#mt_primelink-export-stats-date-from').val() || '';
            const dateTo = $('#mt_primelink-export-stats-date-to').val() || '';
            loadExportStatistics(dateFrom, dateTo, currentExportType);
        }
    }

    // Load statistics
    async function loadStatistics(dateFrom, dateTo, type = '') {
        // Check if mtPrimeLink is defined
        if (typeof mtPrimeLink === 'undefined') {
            console.error('mtPrimeLink is not defined');
            alert('Failed to load statistics: Configuration error. Please refresh the page.');
            return;
        }

        // Show loading state
        $('.mt_primelink-statistics__overview, .mt_primelink-statistics__charts, .mt_primelink-statistics__details, .mt_primelink-statistics__tables').css('opacity', '0.5');

        try {
            const res = await restPost('/import/statistics', {
                date_from: dateFrom || '',
                date_to: dateTo || '',
                type: type || '',
            });

            if (!res || typeof res !== 'object') {
                throw new Error('Invalid response from server');
            }

            currentStats = res;
            renderStatistics(res);
            
            // Hide loading state
            $('.mt_primelink-statistics__overview, .mt_primelink-statistics__charts, .mt_primelink-statistics__details, .mt_primelink-statistics__tables').css('opacity', '1');
        } catch(err) {
            
            // Hide loading state
            $('.mt_primelink-statistics__overview, .mt_primelink-statistics__charts, .mt_primelink-statistics__details, .mt_primelink-statistics__tables').css('opacity', '1');
            
            let errorMsg = 'Unknown error';
            if (err && typeof err === 'object') {
                if (err.json && err.json.message) {
                    errorMsg = err.json.message;
                } else if (err.message) {
                    errorMsg = err.message;
                } else if (err.status) {
                    errorMsg = 'HTTP ' + err.status;
                } else if (err.error) {
                    errorMsg = err.error;
                }
            } else if (typeof err === 'string') {
                errorMsg = err;
            }
            
            alert('Failed to load statistics: ' + errorMsg + '. Please check the browser console for more details.');
        }
    }

    // Render statistics
    function renderStatistics(stats) {
        // Overview stats
        $('#stat-total-imports').text(stats.overview.total_imports || 0);
        $('#stat-total-created').text(stats.overview.total_created || 0);
        $('#stat-total-updated').text(stats.overview.total_updated || 0);
        $('#stat-total-skipped').text(stats.overview.total_skipped || 0);
        $('#stat-total-errors').text(stats.overview.total_errors || 0);
        $('#stat-success-rate').text((stats.overview.success_rate || 0) + '%');

        // Performance metrics
        $('#stat-avg-runtime').text(formatDuration(stats.performance.avg_runtime || 0));
        $('#stat-total-runtime').text(formatDuration(stats.performance.total_runtime || 0));
        $('#stat-avg-speed').text((stats.performance.avg_speed || 0).toFixed(2) + ' items/sec');
        $('#stat-min-runtime').text(formatDuration(stats.performance.min_runtime || 0));
        $('#stat-max-runtime').text(formatDuration(stats.performance.max_runtime || 0));

        // Render charts only if Chart.js is available
        // Function to check and render charts
        function checkAndRenderCharts() {
        // Try multiple ways to access Chart.js
        let ChartLib = null;
            
            // Check if Chart is available globally
        if (typeof Chart !== 'undefined') {
            ChartLib = Chart;
        } else if (typeof window.Chart !== 'undefined') {
            ChartLib = window.Chart;
            } else if (window.chartjs && typeof window.chartjs.Chart !== 'undefined') {
                ChartLib = window.chartjs.Chart;
            } else {
                // Check if script tag exists and try to access it
                const chartScripts = document.querySelectorAll('script[src*="chart"]');
                if (chartScripts.length > 0) {
                    // Script is loading or loaded, wait a bit more
                }
            }
            
            if (ChartLib && typeof ChartLib.register !== 'undefined') {
                // Valid Chart.js library found
            // Temporarily assign to global Chart for chart functions
            if (typeof Chart === 'undefined') {
                window.Chart = ChartLib;
            }
                try {
            renderTimelineChart(stats.timeline || []);
            renderStatusChart(stats.by_status || {});
            renderTypesChart(stats.by_type || {});
                    return true;
                } catch (e) {
                    console.error('Error rendering charts:', e);
                    return false;
                }
            }
            return false;
        }
        
        // Try to render immediately
        if (!checkAndRenderCharts()) {
            // Wait for Chart.js to load (check multiple times with increasing delays)
            let attempts = 0;
            const maxAttempts = 10;
            const checkInterval = setInterval(function() {
                attempts++;
                if (checkAndRenderCharts()) {
                    clearInterval(checkInterval);
                } else if (attempts >= maxAttempts) {
                    clearInterval(checkInterval);
                    
            // Show message to user
            $('.mt_primelink-statistics__charts').prepend(
                '<div class="notice notice-warning" style="padding:10px;margin-bottom:10px;">' +
                        'Charts are not available. Chart.js library is not loaded. Please check the browser console for details and refresh the page.' +
                '</div>'
            );
                }
            }, 100); // Check every 100ms
        }

        // Render tables
        renderTopImports(stats.top_imports || []);
        renderRecentActivity(stats.recent_activity || []);
    }

    // Format duration in seconds to human readable
    function formatDuration(seconds) {
        if (!seconds || seconds < 60) return seconds + 's';
        if (seconds < 3600) return Math.floor(seconds / 60) + 'm ' + (seconds % 60) + 's';
        const hours = Math.floor(seconds / 3600);
        const mins = Math.floor((seconds % 3600) / 60);
        return hours + 'h ' + mins + 'm';
    }

    // Render timeline chart
    function renderTimelineChart(timeline) {
        const ctx = document.getElementById('chart-timeline');
        if (!ctx) return;

        // Get Chart library - try multiple ways
        const ChartLib = typeof Chart !== 'undefined' ? Chart : (typeof window.Chart !== 'undefined' ? window.Chart : null);
        if (!ChartLib) {
            console.error('Chart.js is not available for timeline chart');
            return;
        }

        const labels = timeline.map(t => t.date);
        const created = timeline.map(t => t.created || 0);
        const updated = timeline.map(t => t.updated || 0);
        const errors = timeline.map(t => t.errors || 0);

        if (charts.timeline) {
            charts.timeline.destroy();
        }

        charts.timeline = new ChartLib(ctx, {
            type: 'line',
            data: {
                labels: labels,
                datasets: [
                    {
                        label: 'Created',
                        data: created,
                        borderColor: 'rgb(16, 185, 129)',
                        backgroundColor: 'rgba(16, 185, 129, 0.1)',
                        tension: 0.4
                    },
                    {
                        label: 'Updated',
                        data: updated,
                        borderColor: 'rgb(59, 130, 246)',
                        backgroundColor: 'rgba(59, 130, 246, 0.1)',
                        tension: 0.4
                    },
                    {
                        label: 'Errors',
                        data: errors,
                        borderColor: 'rgb(239, 68, 68)',
                        backgroundColor: 'rgba(239, 68, 68, 0.1)',
                        tension: 0.4
                    }
                ]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        position: 'top',
                    }
                },
                scales: {
                    y: {
                        beginAtZero: true
                    }
                }
            }
        });
    }

    // Render status chart
    function renderStatusChart(statusData) {
        const ctx = document.getElementById('chart-status');
        if (!ctx) return;

        // Get Chart library - try multiple ways
        const ChartLib = typeof Chart !== 'undefined' ? Chart : (typeof window.Chart !== 'undefined' ? window.Chart : null);
        if (!ChartLib) {
            console.error('Chart.js is not available for status chart');
            return;
        }

        const labels = Object.keys(statusData);
        const data = Object.values(statusData);

        if (charts.status) {
            charts.status.destroy();
        }

        charts.status = new ChartLib(ctx, {
            type: 'doughnut',
            data: {
                labels: labels.map(l => l.charAt(0).toUpperCase() + l.slice(1)),
                datasets: [{
                    data: data,
                    backgroundColor: [
                        'rgba(156, 163, 175, 0.8)',
                        'rgba(59, 130, 246, 0.8)',
                        'rgba(251, 191, 36, 0.8)',
                        'rgba(16, 185, 129, 0.8)',
                        'rgba(239, 68, 68, 0.8)'
                    ]
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        position: 'bottom',
                    }
                }
            }
        });
    }

    // Render types chart
    function renderTypesChart(typesData) {
        const ctx = document.getElementById('chart-types');
        if (!ctx) return;

        // Get Chart library - try multiple ways
        const ChartLib = typeof Chart !== 'undefined' ? Chart : (typeof window.Chart !== 'undefined' ? window.Chart : null);
        if (!ChartLib) {
            console.error('Chart.js is not available for types chart');
            return;
        }

        const labels = Object.keys(typesData);
        const counts = Object.values(typesData);

        if (charts.types) {
            charts.types.destroy();
        }

        charts.types = new ChartLib(ctx, {
            type: 'bar',
            data: {
                labels: labels.map(l => l.charAt(0).toUpperCase() + l.slice(1)),
                datasets: [{
                    label: 'Import Count',
                    data: counts,
                    backgroundColor: 'rgba(59, 130, 246, 0.8)'
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        display: false
                    }
                },
                scales: {
                    y: {
                        beginAtZero: true
                    }
                }
            }
        });
    }

    // Render top imports table
    function renderTopImports(imports) {
        const $container = $('#stat-top-imports');
        if (!imports.length) {
            $container.html('<div class="mt_primelink-empty">No imports found.</div>');
            return;
        }

        let html = '<table class="mt_primelink-dash-table"><thead><tr>';
        html += '<th>ID</th><th>Type</th><th>Created</th><th>Updated</th><th>Errors</th><th>Status</th>';
        html += '</tr></thead><tbody>';

        imports.forEach(imp => {
            html += '<tr>';
            html += '<td>#' + imp.id + '</td>';
            html += '<td>' + escapeHtml(imp.type || 'product') + '</td>';
            html += '<td>' + (imp.created || 0) + '</td>';
            html += '<td>' + (imp.updated || 0) + '</td>';
            html += '<td>' + (imp.errors || 0) + '</td>';
            html += '<td><span class="mt_primelink-status-pill mt_primelink-status-' + escapeHtml(imp.status) + '">' + escapeHtml(imp.status.charAt(0).toUpperCase() + imp.status.slice(1)) + '</span></td>';
            html += '</tr>';
        });

        html += '</tbody></table>';
        $container.html(html);
    }

    // Render recent activity table
    function renderRecentActivity(activity) {
        const $container = $('#stat-recent-activity');
        if (!activity.length) {
            $container.html('<div class="mt_primelink-empty">No recent activity.</div>');
            return;
        }

        let html = '<table class="mt_primelink-dash-table"><thead><tr>';
        html += '<th>ID</th><th>Type</th><th>Created</th><th>Updated</th><th>Errors</th><th>Last Update</th>';
        html += '</tr></thead><tbody>';

        activity.forEach(act => {
            html += '<tr>';
            html += '<td>#' + act.id + '</td>';
            html += '<td>' + escapeHtml(act.type || 'product') + '</td>';
            html += '<td>' + (act.created || 0) + '</td>';
            html += '<td>' + (act.updated || 0) + '</td>';
            html += '<td>' + (act.errors || 0) + '</td>';
            html += '<td>' + escapeHtml(act.last_update || '-') + '</td>';
            html += '</tr>';
        });

        html += '</tbody></table>';
        $container.html(html);
    }

    // Helper function
    function escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    // Initialize on document ready (only on statistics page)
    $(document).ready(function() {
        // Only run on statistics page
        if (!$('.mt_primelink-statistics').length) {
            return;
        }

        // Check if mtPrimeLink is defined
        if (typeof mtPrimeLink === 'undefined') {
            console.error('mtPrimeLink is not defined. Make sure the script is properly enqueued.');
            alert('Failed to load statistics: Configuration error. Please refresh the page.');
            return;
        }

        // Event handlers
        $('#mt_primelink-stats-apply-filter').on('click', function() {
            const dateFrom = $('#mt_primelink-stats-date-from').val();
            const dateTo = $('#mt_primelink-stats-date-to').val();
            loadStatistics(dateFrom, dateTo);
        });

        $('#mt_primelink-stats-reset-filter').on('click', function() {
            $('#mt_primelink-stats-date-from').val('');
            $('#mt_primelink-stats-date-to').val('');
            loadStatistics('', '');
        });

        // Chart.js should be loaded as a dependency, but check anyway
        // Try multiple ways to access Chart.js
        let ChartAvailable = typeof Chart !== 'undefined';
        if (!ChartAvailable && typeof window.Chart !== 'undefined') {
            ChartAvailable = true;
        }
        if (!ChartAvailable && typeof window.chartjs !== 'undefined') {
            ChartAvailable = true;
        }
        
        if (!ChartAvailable) {
            // Chart.js is not available, charts will not be rendered
        }

        // Tab switching handlers
        $('.mt_primelink-tab-button').on('click', function() {
            const tab = $(this).data('tab');
            switchTab(tab);
        });

        // Type filter handlers for import
        $('#mt_primelink-import-type-filter').on('change', function() {
            currentImportType = $(this).val() || '';
            const dateFrom = $('#mt_primelink-stats-date-from').val() || '';
            const dateTo = $('#mt_primelink-stats-date-to').val() || '';
            loadStatistics(dateFrom, dateTo, currentImportType);
        });

        // Type filter handlers for export
        $('#mt_primelink-export-type-filter').on('change', function() {
            currentExportType = $(this).val() || '';
            const dateFrom = $('#mt_primelink-export-stats-date-from').val() || '';
            const dateTo = $('#mt_primelink-export-stats-date-to').val() || '';
            loadExportStatistics(dateFrom, dateTo, currentExportType);
        });

        // Export filter handlers
        $('#mt_primelink-export-stats-apply-filter').on('click', function() {
            const dateFrom = $('#mt_primelink-export-stats-date-from').val() || '';
            const dateTo = $('#mt_primelink-export-stats-date-to').val() || '';
            loadExportStatistics(dateFrom, dateTo, currentExportType);
        });

        $('#mt_primelink-export-stats-reset-filter').on('click', function() {
            $('#mt_primelink-export-stats-date-from').val('');
            $('#mt_primelink-export-stats-date-to').val('');
            $('#mt_primelink-export-type-filter').val('');
            currentExportType = '';
            loadExportStatistics('', '', '');
        });

        // Update import filter handler to include type
        $('#mt_primelink-stats-apply-filter').on('click', function() {
            const dateFrom = $('#mt_primelink-stats-date-from').val();
            const dateTo = $('#mt_primelink-stats-date-to').val();
            loadStatistics(dateFrom, dateTo, currentImportType);
        });

        $('#mt_primelink-stats-reset-filter').on('click', function() {
            $('#mt_primelink-stats-date-from').val('');
            $('#mt_primelink-stats-date-to').val('');
            $('#mt_primelink-import-type-filter').val('');
            currentImportType = '';
            loadStatistics('', '', '');
        });

        // Initial load
        loadStatistics('', '', '');
    });

    // Load export statistics
    async function loadExportStatistics(dateFrom, dateTo, type = '') {
        if (typeof mtPrimeLink === 'undefined') {
            console.error('mtPrimeLink is not defined');
            alert('Failed to load statistics: Configuration error. Please refresh the page.');
            return;
        }

        // Show loading state
        $('#tab-export .mt_primelink-statistics__overview, #tab-export .mt_primelink-statistics__charts, #tab-export .mt_primelink-statistics__details, #tab-export .mt_primelink-statistics__tables').css('opacity', '0.5');

        try {
            const params = new URLSearchParams({
                date_from: dateFrom || '',
                date_to: dateTo || '',
                type: type || '',
            });
            
            const res = await restGet('/export/statistics?' + params.toString());

            if (!res || typeof res !== 'object') {
                throw new Error('Invalid response from server');
            }

            renderExportStatistics(res);
            
            // Hide loading state
            $('#tab-export .mt_primelink-statistics__overview, #tab-export .mt_primelink-statistics__charts, #tab-export .mt_primelink-statistics__details, #tab-export .mt_primelink-statistics__tables').css('opacity', '1');
        } catch(err) {
            console.error('Failed to load export statistics:', err);
            
            // Hide loading state
            $('#tab-export .mt_primelink-statistics__overview, #tab-export .mt_primelink-statistics__charts, #tab-export .mt_primelink-statistics__details, #tab-export .mt_primelink-statistics__tables').css('opacity', '1');
            
            let errorMsg = 'Unknown error';
            if (err && typeof err === 'object') {
                if (err.json && err.json.message) {
                    errorMsg = err.json.message;
                } else if (err.message) {
                    errorMsg = err.message;
                }
            }
            
            showToastOrAlert('error', 'Failed to load export statistics: ' + errorMsg + '. Please check the browser console for more details.', 'Statistics');
        }
    }

    // Render export statistics
    function renderExportStatistics(stats) {
        // Overview stats
        $('#stat-export-total-exports').text(stats.overview.total_exports || 0);
        $('#stat-export-total-exported').text(stats.overview.total_exported || 0);
        $('#stat-export-total-errors').text(stats.overview.total_errors || 0);
        $('#stat-export-success-rate').text((stats.overview.success_rate || 0) + '%');

        // Performance metrics
        $('#stat-export-avg-runtime').text(formatDuration(stats.performance.avg_runtime || 0));
        $('#stat-export-total-runtime').text(formatDuration(stats.performance.total_runtime || 0));
        $('#stat-export-avg-speed').text((stats.performance.avg_speed || 0).toFixed(2) + ' items/sec');
        $('#stat-export-min-runtime').text(formatDuration(stats.performance.min_runtime || 0));
        $('#stat-export-max-runtime').text(formatDuration(stats.performance.max_runtime || 0));

        // Render charts
        const ChartLib = typeof Chart !== 'undefined' ? Chart : (typeof window.Chart !== 'undefined' ? window.Chart : null);
        
        if (ChartLib) {
            renderExportTimelineChart(stats.timeline || []);
            renderExportStatusChart(stats.by_status || {});
            renderExportTypesChart(stats.by_type || {});
        }

        // Render tables
        renderTopExports(stats.top_exports || []);
        renderExportRecentActivity(stats.recent_activity || []);
    }

    // Render export timeline chart
    function renderExportTimelineChart(timeline) {
        const ctx = document.getElementById('chart-export-timeline');
        if (!ctx) return;

        const ChartLib = typeof Chart !== 'undefined' ? Chart : (typeof window.Chart !== 'undefined' ? window.Chart : null);
        if (!ChartLib) return;

        const labels = timeline.map(t => t.date);
        const exported = timeline.map(t => t.exported || 0);
        const errors = timeline.map(t => t.errors || 0);

        if (charts.exportTimeline) {
            charts.exportTimeline.destroy();
        }

        charts.exportTimeline = new ChartLib(ctx, {
            type: 'line',
            data: {
                labels: labels,
                datasets: [
                    {
                        label: 'Exported',
                        data: exported,
                        borderColor: 'rgb(16, 185, 129)',
                        backgroundColor: 'rgba(16, 185, 129, 0.1)',
                        tension: 0.4
                    },
                    {
                        label: 'Errors',
                        data: errors,
                        borderColor: 'rgb(239, 68, 68)',
                        backgroundColor: 'rgba(239, 68, 68, 0.1)',
                        tension: 0.4
                    }
                ]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        position: 'top',
                    }
                },
                scales: {
                    y: {
                        beginAtZero: true
                    }
                }
            }
        });
    }

    // Render export status chart
    function renderExportStatusChart(statusData) {
        const ctx = document.getElementById('chart-export-status');
        if (!ctx) return;

        const ChartLib = typeof Chart !== 'undefined' ? Chart : (typeof window.Chart !== 'undefined' ? window.Chart : null);
        if (!ChartLib) return;

        const labels = Object.keys(statusData);
        const data = Object.values(statusData);

        if (charts.exportStatus) {
            charts.exportStatus.destroy();
        }

        charts.exportStatus = new ChartLib(ctx, {
            type: 'doughnut',
            data: {
                labels: labels.map(l => l.charAt(0).toUpperCase() + l.slice(1)),
                datasets: [{
                    data: data,
                    backgroundColor: [
                        'rgba(156, 163, 175, 0.8)',
                        'rgba(59, 130, 246, 0.8)',
                        'rgba(251, 191, 36, 0.8)',
                        'rgba(16, 185, 129, 0.8)',
                        'rgba(239, 68, 68, 0.8)'
                    ]
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        position: 'bottom',
                    }
                }
            }
        });
    }

    // Render export types chart
    function renderExportTypesChart(typesData) {
        const ctx = document.getElementById('chart-export-types');
        if (!ctx) return;

        const ChartLib = typeof Chart !== 'undefined' ? Chart : (typeof window.Chart !== 'undefined' ? window.Chart : null);
        if (!ChartLib) return;

        const labels = Object.keys(typesData);
        const counts = Object.values(typesData);

        if (charts.exportTypes) {
            charts.exportTypes.destroy();
        }

        charts.exportTypes = new ChartLib(ctx, {
            type: 'bar',
            data: {
                labels: labels.map(l => l.charAt(0).toUpperCase() + l.slice(1)),
                datasets: [{
                    label: 'Export Count',
                    data: counts,
                    backgroundColor: 'rgba(59, 130, 246, 0.8)'
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        display: false
                    }
                },
                scales: {
                    y: {
                        beginAtZero: true
                    }
                }
            }
        });
    }

    // Render top exports table
    function renderTopExports(exports) {
        const $container = $('#stat-top-exports');
        if (!exports.length) {
            $container.html('<div class="mt_primelink-empty">No exports found.</div>');
            return;
        }

        let html = '<table class="mt_primelink-dash-table"><thead><tr>';
        html += '<th>ID</th><th>Type</th><th>Exported</th><th>Errors</th><th>Status</th>';
        html += '</tr></thead><tbody>';

        exports.forEach(exp => {
            html += '<tr>';
            html += '<td>#' + exp.id + '</td>';
            html += '<td>' + escapeHtml(exp.type || 'product') + '</td>';
            html += '<td>' + (exp.exported || 0) + '</td>';
            html += '<td>' + (exp.errors || 0) + '</td>';
            html += '<td><span class="mt_primelink-status-pill mt_primelink-status-' + escapeHtml(exp.status) + '">' + escapeHtml(exp.status.charAt(0).toUpperCase() + exp.status.slice(1)) + '</span></td>';
            html += '</tr>';
        });

        html += '</tbody></table>';
        $container.html(html);
    }

    // Render export recent activity table
    function renderExportRecentActivity(activity) {
        const $container = $('#stat-export-recent-activity');
        if (!activity.length) {
            $container.html('<div class="mt_primelink-empty">No recent activity.</div>');
            return;
        }

        let html = '<table class="mt_primelink-dash-table"><thead><tr>';
        html += '<th>ID</th><th>Type</th><th>Exported</th><th>Errors</th><th>Last Update</th>';
        html += '</tr></thead><tbody>';

        activity.forEach(act => {
            html += '<tr>';
            html += '<td>#' + act.id + '</td>';
            html += '<td>' + escapeHtml(act.type || 'product') + '</td>';
            html += '<td>' + (act.exported || 0) + '</td>';
            html += '<td>' + (act.errors || 0) + '</td>';
            html += '<td>' + escapeHtml(act.last_update || '-') + '</td>';
            html += '</tr>';
        });

        html += '</tbody></table>';
        $container.html(html);
    }



  // ============================================
  // Export Management
  // ============================================

/* PrimeLink - Manage Exports
 * Handles export management page functionality
 */

    // Use global restPost from mt-primelink-admin.js
    function restPost(path, body) {
        if (typeof window.restPost === 'function') {
            return window.restPost(path, body);
        }
        console.error('Global restPost function is not available.');
        throw {status: 500, json: {message: 'restPost not available'}};
    }

    function updateExportRow(exportId, state) {
        const $row = $('.mt_primelink-export-row[data-id="' + exportId + '"]');
        if (!$row.length) return;

        const status = state.status || 'idle';
        const progress = state.progress || 0;
        const current = state.current || 0;
        const total = state.total || 0;

        $row.find('.mt_primelink-status-pill')
            .attr('class', 'mt_primelink-status-pill mt_primelink-status-' + status)
            .text(status.charAt(0).toUpperCase() + status.slice(1));

        $row.find('.mt_primelink-dash-progress__bar').css('width', Math.max(0, Math.min(100, progress)) + '%');
        $row.find('.muted').text(current + ' / ' + total);

        // Toggle buttons
        $row.find('.mt_primelink-export-start').prop('disabled', status === 'running' || status === 'paused');
        $row.find('.mt_primelink-export-pause').prop('disabled', status !== 'running');
        $row.find('.mt_primelink-export-resume').prop('disabled', status !== 'paused');
    }

    async function refreshExportRow(exportId) {
        try {
            const state = await restPost('/export/run/status', { export_id: exportId });
            updateExportRow(exportId, state);
        } catch (e) {
            // Silent fail
        }
    }

    $(document).ready(function() {
        // Tab switching is handled by the global handler above

        // Refresh button
        $('#mt_primelink-exports-refresh').on('click', function() {
            $('.mt_primelink-export-row').each(function() {
                const id = parseInt($(this).data('id'), 10);
                refreshExportRow(id);
            });
        });

        // Export actions
        $(document).on('click', '.mt_primelink-export-start', async function() {
            const exportId = parseInt($(this).data('id'), 10);
            try {
                const state = await restPost('/export/run/start', { export_id: exportId });
                updateExportRow(exportId, state);
            } catch (e) {
                showToastOrAlert('error', e.json?.message || 'Failed to start export.', 'Export');
            }
        });

        $(document).on('click', '.mt_primelink-export-pause', async function() {
            const exportId = parseInt($(this).data('id'), 10);
            try {
                const state = await restPost('/export/run/pause', { export_id: exportId });
                updateExportRow(exportId, state);
            } catch (e) {
                showToastOrAlert('error', e.json?.message || 'Failed to pause export.', 'Export');
            }
        });

        $(document).on('click', '.mt_primelink-export-resume', async function() {
            const exportId = parseInt($(this).data('id'), 10);
            try {
                const state = await restPost('/export/run/resume', { export_id: exportId });
                updateExportRow(exportId, state);
            } catch (e) {
                showToastOrAlert('error', e.json?.message || 'Failed to resume export.', 'Export');
            }
        });

        // Select all and delete selected are handled in mt-primelink-admin.js

        // Auto-refresh every 5 seconds for running exports
        setInterval(function() {
            $('.mt_primelink-export-row').each(function() {
                const status = $(this).find('.mt_primelink-status-pill').text().toLowerCase();
                if (status === 'running' || status === 'paused') {
                    const id = parseInt($(this).data('id'), 10);
                    refreshExportRow(id);
                }
            });
        }, 5000);
    });



  // ============================================
  // Template Manager
  // ============================================

/* PrimeLink - Template Manager
 * Handles template management page functionality
 */
    
    // Verify script loaded - remove after testing
    if (typeof window !== 'undefined') {
        window.templateManagerLoaded = true;
    }

    // Helper function for REST API calls
    async function restPost(path, body) {
        if (typeof mtPrimeLink === 'undefined') {
            console.error('mtPrimeLink is not defined.');
            throw {status: 500, json: {message: 'mtPrimeLink not available'}};
        }
        const opts = {
            method: 'POST',
            headers: {
                'X-WP-Nonce': mtPrimeLink.restNonce,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(body || {})
        };
        const r = await fetch(mtPrimeLink.restUrl + path, opts);
        const j = await r.json().catch(() => ({}));
        if (!r.ok) throw {status: r.status, json: j};
        return j;
    }

    async function restGet(path) {
        if (typeof mtPrimeLink === 'undefined') {
            console.error('mtPrimeLink is not defined.');
            throw {status: 500, json: {message: 'mtPrimeLink not available'}};
        }
        const r = await fetch(mtPrimeLink.restUrl + path, {
            method: 'GET',
            headers: { 'X-WP-Nonce': mtPrimeLink.restNonce }
        });
        const j = await r.json().catch(() => ({}));
        if (!r.ok) throw {status: r.status, json: j};
        return j;
    }

    // Helper function
    function escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    // Initialize on document ready
    $(document).ready(function() {
        // Initialization complete
    });

    // Tab switching is handled by the global handler above

    // Search functionality
    $(document).on('input', '#mt-primelink-template-search', function() {
        const query = $(this).val().toLowerCase();
        $('.mt-primelink-template-row').each(function() {
            const $row = $(this);
            const title = $row.find('td:first strong').text().toLowerCase();
            if (title.indexOf(query) !== -1) {
                $row.show();
            } else {
                $row.hide();
            }
        });
    });

    // Select all - same approach as manage imports
    $(document).on('change', '.mt-primelink-select-all', function() {
        const checked = $(this).is(':checked');
        const type = $(this).data('type') || '';
        
        // Use same approach as manage imports - simple selector with data-type
        if (type) {
            $('.mt-primelink-template-select[data-type="' + type + '"]').prop('checked', checked);
        } else {
            $('.mt-primelink-template-select').prop('checked', checked);
        }
    });

    // Sort functionality
    $(document).on('change', '.mt-primelink-sort-select', function() {
        const type = $(this).data('type') || '';
        const sortBy = $(this).val();
        const $tbody = $('.mt_primelink-tab-panel[data-tab-panel="' + type + '"] tbody');
        const $rows = $tbody.find('.mt-primelink-template-row').toArray();

        $rows.sort(function(a, b) {
            const $a = $(a);
            const $b = $(b);
            let aVal, bVal;

            if (sortBy.startsWith('name-')) {
                aVal = $a.find('td:first strong').text().toLowerCase();
                bVal = $b.find('td:first strong').text().toLowerCase();
                return sortBy === 'name-asc' ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
            } else if (sortBy.startsWith('date-')) {
                aVal = $a.find('td:nth-child(3)').text();
                bVal = $b.find('td:nth-child(3)').text();
                return sortBy === 'date-desc' ? bVal.localeCompare(aVal) : aVal.localeCompare(bVal);
            } else if (sortBy.startsWith('fields-')) {
                aVal = parseInt($a.find('td:nth-child(2) .muted').text().split(' ')[0] || '0', 10);
                bVal = parseInt($b.find('td:nth-child(2) .muted').text().split(' ')[0] || '0', 10);
                return sortBy === 'fields-desc' ? bVal - aVal : aVal - bVal;
            }
            return 0;
        });

        $tbody.empty().append($rows);
    });

    // Preview template
    $(document).on('click', '.mt-primelink-template-preview', async function(e) {
        e.preventDefault();
        e.stopPropagation();
        const name = $(this).data('name');
        const $modal = $('#mt-primelink-template-preview-modal');
        const $content = $('#mt-primelink-template-preview-content');

        $modal.show();
        $content.html('<p>Loading...</p>');

        try {
            const res = await restPost('/import/templates/load', { name: name });
            const data = res.data || {};

            let html = '<div class="mt-primelink-template-preview-details">';
            html += '<h3>' + escapeHtml(name.replace(/^(order|product|customer|coupon):/, '')) + '</h3>';

            // Mapped fields
            if (data.mapping && Array.isArray(data.mapping)) {
                const mapped = data.mapping.filter(slot => slot.source && slot.source.trim());
                html += '<h4>Mapped Fields (' + mapped.length + ')</h4>';
                html += '<ul class="mt-primelink-preview-list">';
                mapped.forEach(function(slot) {
                    html += '<li><strong>' + escapeHtml(slot.target || '') + '</strong> â† ' + escapeHtml(slot.source || '') + '</li>';
                });
                html += '</ul>';
            }

            // Aliases
            if (data.aliases && Array.isArray(data.aliases) && data.aliases.length > 0) {
                html += '<h4>Custom Aliases</h4>';
                html += '<ul class="mt-primelink-preview-list">';
                data.aliases.forEach(function(alias) {
                    html += '<li><strong>' + escapeHtml(alias.target || '') + '</strong>: ' + escapeHtml((alias.aliases || []).join(', ')) + '</li>';
                });
                html += '</ul>';
            }

            // Other options
            if (data.other) {
                const other = data.other;
                html += '<h4>Other Options</h4>';
                html += '<ul class="mt-primelink-preview-list">';
                if (other.global_prefix) html += '<li>Global Prefix: ' + escapeHtml(other.global_prefix) + '</li>';
                if (other.global_suffix) html += '<li>Global Suffix: ' + escapeHtml(other.global_suffix) + '</li>';
                if (other.global_trim) html += '<li>Global Trim: Enabled</li>';
                if (other.slugify) html += '<li>Slugify: Enabled</li>';
                if (other.fallback_image) html += '<li>Fallback Image: ' + escapeHtml(other.fallback_image) + '</li>';
                html += '</ul>';
            }

            html += '</div>';
            $content.html(html);
        } catch (e) {
            console.error('Preview error:', e);
            $content.html('<p class="error">Failed to load template preview: ' + (e.json?.message || 'Unknown error') + '</p>');
        }
    });

    // Close modal
    $(document).on('click', '.mt-primelink-modal__close, .mt-primelink-modal__overlay', function() {
        $('#mt-primelink-template-preview-modal').hide();
    });

    // Load template - show modal to select import
    $(document).on('click', '.mt-primelink-template-load', async function(e) {
        e.preventDefault();
        e.stopPropagation();
        const templateName = $(this).data('name');
        const templateType = $(this).data('type');
        
        // Normalize type
        let importType = templateType;
        if (templateType === 'orders') importType = 'order';
        else if (templateType === 'customers') importType = 'customer';
        else if (templateType === 'coupons') importType = 'coupon';
        else if (templateType === 'products') importType = 'product';
        else if (templateType === 'categories') importType = 'category';
        else if (templateType === 'tags') importType = 'tag';
        else if (templateType === 'attributes') importType = 'attribute';
        else if (templateType === 'variations') importType = 'variation';
        else if (templateType === 'reviews') importType = 'review';
        else if (templateType === 'downloads') importType = 'download';
        
        // Show modal to select import
        showTemplateLoadModal(templateName, importType);
    });
    
    // Function to show template load modal
    async function showTemplateLoadModal(templateName, importType) {
        // Create modal if it doesn't exist
        let $modal = $('#mt-primelink-template-load-modal');
        if ($modal.length === 0) {
            $modal = $('<div id="mt-primelink-template-load-modal" class="mt-primelink-modal" style="display:none;"><div class="mt-primelink-modal__overlay"></div><div class="mt-primelink-modal__content glass"><div class="mt-primelink-modal__header"><h2>Select Import</h2><button type="button" class="mt-primelink-modal__close">&times;</button></div><div class="mt-primelink-modal__body"><p>Select an import to load this template into:</p><select id="mt-primelink-template-load-import-select" style="width:100%;padding:8px;margin:12px 0;border:1px solid rgba(0,0,0,0.1);border-radius:6px;"><option value="">Loading imports...</option></select><p class="description" style="margin-top:8px;">Or <a href="#" id="mt-primelink-template-load-new-import" style="text-decoration:underline;">create a new import</a></p></div><div class="mt-primelink-modal__footer"><button type="button" class="button mt-primelink-modal__close">Cancel</button><button type="button" class="button button-primary" id="mt-primelink-template-load-confirm">Load Template</button></div></div></div>');
            $('body').append($modal);
            
            // Close modal handlers
            $modal.on('click', '.mt-primelink-modal__close, .mt-primelink-modal__overlay', function() {
                $modal.hide();
            });
        }
        
        // Load imports list
        try {
            const importsRes = await restGet('/import/list?type=' + encodeURIComponent(importType) + '&ts=' + Date.now());
            const imports = importsRes.imports || [];
            
            const $select = $('#mt-primelink-template-load-import-select');
            let html = '<option value="">Select an import...</option>';
            
            if (imports.length === 0) {
                html = '<option value="">No imports found. Create a new import instead.</option>';
            } else {
                imports.forEach(imp => {
                    html += '<option value="' + escapeHtml(imp.id) + '">' + escapeHtml(imp.display_name) + '</option>';
                });
            }
            
            $select.html(html);
            
            // Store template name and type for later use
            $modal.data('template-name', templateName);
            $modal.data('import-type', importType);
            
            // Show modal
            $modal.show();
        } catch(e) {
            showToastOrAlert('error', 'Failed to load imports: ' + (e.json?.message || e.message || 'Unknown error'), 'Load Template');
        }
    }
    
    // Confirm load template into selected import
    $(document).on('click', '#mt-primelink-template-load-confirm', async function() {
        const $modal = $('#mt-primelink-template-load-modal');
        const templateName = $modal.data('template-name');
        const importType = $modal.data('import-type');
        const importId = $('#mt-primelink-template-load-import-select').val();
        
        if (!importId) {
            showToastOrAlert('warning', 'Please select an import.', 'Load Template');
            return;
        }
        
        try {
            // Load template data
            let templateRes;
            try {
                templateRes = await restPost('/import/templates/load', { name: templateName });
            } catch(loadError) {
                // If load fails, show error and return
                showToastOrAlert('error', 'Template not found: ' + templateName, 'Load Template');
                return;
            }
            
            // Check if response has error message
            if (templateRes && templateRes.message && templateRes.message.includes('not found')) {
                showToastOrAlert('error', 'Template not found: ' + templateName, 'Load Template');
                return;
            }
            
            // Extract template data - response structure: { name, data, is_import }
            // The 'data' field contains the actual mapping data to save in step 5
            const mappingData = templateRes.data || templateRes || {};
            
            // Get current draft to check if type is set
            const draftRes = await restPost('/import/get-draft', { import_id: parseInt(importId, 10) });
            const draft = draftRes.draft || draftRes || {};
            
            // Normalize import type for URL (products -> products, order -> orders, etc.)
            let urlImportType = importType;
            if (importType === 'product') urlImportType = 'products';
            else if (importType === 'order') urlImportType = 'orders';
            else if (importType === 'customer') urlImportType = 'customers';
            else if (importType === 'coupon') urlImportType = 'coupons';
            else if (importType === 'category') urlImportType = 'categories';
            else if (importType === 'tag') urlImportType = 'tags';
            else if (importType === 'attribute') urlImportType = 'attributes';
            else if (importType === 'variation') urlImportType = 'variations';
            else if (importType === 'review') urlImportType = 'reviews';
            else if (importType === 'download') urlImportType = 'downloads';
            
            // Set import type in step 1 if not already set
            if (!draft.type && (!draft.step_data || !draft.step_data[1] || !draft.step_data[1].type)) {
                await restPost('/import/save-step', {
                    import_id: parseInt(importId, 10),
                    step: 1,
                    data: { type: importType }
                });
            }
            
            // Save template mapping data to import's step 5
            // Use mappingData which contains the actual mapping structure
            await restPost('/import/save-step', {
                import_id: parseInt(importId, 10),
                step: 5,
                data: mappingData
            });
            
            $modal.hide();
            
            // Redirect to import wizard at step 5 with import_type and template parameter for auto-load
            const adminUrl = (typeof mtPrimeLink !== 'undefined' && mtPrimeLink.adminUrl) ? mtPrimeLink.adminUrl : '';
            const url = adminUrl + 'admin.php?page=mt-primelink-new-import&import_id=' + importId + '&import_type=' + encodeURIComponent(urlImportType) + '&step=5&template=' + encodeURIComponent(templateName);
            window.location.href = url;
        } catch(e) {
            $modal.hide();
            showToastOrAlert('error', 'Failed to load template: ' + (e.json?.message || e.message || 'Unknown error'), 'Load Template');
        }
    });
    
    // Create new import link
    $(document).on('click', '#mt-primelink-template-load-new-import', function(e) {
        e.preventDefault();
        const $modal = $('#mt-primelink-template-load-modal');
        const templateName = $modal.data('template-name');
        const importType = $modal.data('import-type');
        
        $modal.hide();
        
        // Redirect to new import with template
        const adminUrl = (typeof mtPrimeLink !== 'undefined' && mtPrimeLink.adminUrl) ? mtPrimeLink.adminUrl : '';
        const url = adminUrl + 'admin.php?page=mt-primelink-new-import&import_type=' + importType + '&step=5&template=' + encodeURIComponent(templateName);
        window.location.href = url;
    });

    // Duplicate template
    $(document).on('click', '.mt-primelink-template-duplicate', async function(e) {
        e.preventDefault();
        e.stopPropagation();
        const name = $(this).data('name');
        const displayName = name.replace(/^(order|product|customer|coupon):/, '');
        const newName = prompt('Enter a new name for the duplicate:', displayName + ' copy');
        
        if (!newName || !newName.trim()) return;

        try {
            const res = await restPost('/import/templates/load', { name: name });
            
            // Determine type from name
            let templateType = 'product';
            let prefix = 'product:';
            if (name.startsWith('order:')) {
                templateType = 'order';
                prefix = 'order:';
            } else if (name.startsWith('customer:')) {
                templateType = 'customer';
                prefix = 'customer:';
            } else if (name.startsWith('coupon:')) {
                templateType = 'coupon';
                prefix = 'coupon:';
            } else if (name.startsWith('product:')) {
                templateType = 'product';
                prefix = 'product:';
            }

            // Remove any existing prefix from newName and add correct one
            const cleanName = newName.trim().replace(/^(order|product|customer|coupon):/, '');
            const finalName = prefix + cleanName;

            await restPost('/import/templates/save', {
                name: finalName,
                data: res.data,
                type: templateType
            });

            showToastOrAlert('success', 'Template duplicated successfully.', 'Template');
            location.reload();
        } catch (e) {
            console.error('Duplicate error:', e);
            showToastOrAlert('error', 'Failed to duplicate template: ' + (e.json?.message || 'Unknown error'), 'Template');
        }
    });

    // Delete template
    $(document).on('click', '.mt-primelink-template-delete', async function(e) {
        e.preventDefault();
        e.stopPropagation();
        const name = $(this).data('name');
        const displayName = name.replace(/^(order|product|customer|coupon):/, '');
        
        if (!confirm('Delete template "' + displayName + '"? This cannot be undone.')) {
            return;
        }

        try {
            await restPost('/import/templates/delete', { name: name });
            $(this).closest('.mt-primelink-template-row').fadeOut(300, function() {
                $(this).remove();
            });
        } catch (e) {
            console.error('Delete error:', e);
            showToastOrAlert('error', 'Failed to delete template: ' + (e.json?.message || 'Unknown error'), 'Template');
        }
    });

    // Bulk delete
    $(document).on('click', '.mt-primelink-bulk-delete', async function(e) {
        e.preventDefault();
        e.stopPropagation();
        const type = $(this).data('type') || '';
        
        // Use same approach as manage imports
        let selector = '.mt-primelink-template-select:checked';
        if (type) {
            selector = '.mt-primelink-template-select[data-type="' + type + '"]:checked';
        }
        const $checked = $(selector);
        
        if ($checked.length === 0) {
            showToastOrAlert('warning', 'Select at least one template to delete.', 'Template');
            return;
        }

        if (!confirm('Delete ' + $checked.length + ' selected template(s)? This cannot be undone.')) {
            return;
        }

        const $button = $(this);
        const originalText = $button.text();
        $button.prop('disabled', true).text('Deleting...');

        try {
            const names = $checked.map(function() {
                return $(this).val();
            }).get();

            for (const name of names) {
                await restPost('/import/templates/delete', { name: name });
                $('.mt-primelink-template-row[data-name="' + name + '"]').fadeOut(300, function() {
                    $(this).remove();
                });
            }
            
            // Uncheck select all
            if (type) {
                $('.mt-primelink-select-all[data-type="' + type + '"]').prop('checked', false);
            }
        } catch (e) {
            console.error('Bulk delete error:', e);
            showToastOrAlert('error', 'Failed to delete templates: ' + (e.json?.message || 'Unknown error'), 'Template');
        } finally {
            $button.prop('disabled', false).text(originalText);
        }
    });

    // Bulk duplicate
    $(document).on('click', '.mt-primelink-bulk-duplicate', async function(e) {
        e.preventDefault();
        e.stopPropagation();
        const type = $(this).data('type') || '';
        
        // Use same approach as manage imports
        let selector = '.mt-primelink-template-select:checked';
        if (type) {
            selector = '.mt-primelink-template-select[data-type="' + type + '"]:checked';
        }
        const $checked = $(selector);
        
        if ($checked.length === 0) {
            showToastOrAlert('warning', 'Select at least one template to duplicate.', 'Template');
            return;
        }

        const $button = $(this);
        const originalText = $button.text();
        $button.prop('disabled', true).text('Duplicating...');

        try {
            const names = $checked.map(function() {
                return $(this).val();
            }).get();

            for (const name of names) {
                const res = await restPost('/import/templates/load', { name: name });
                const displayName = name.replace(/^(order|product|customer|coupon):/, '');
                
                // Determine type and prefix
                let templateType = 'product';
                let prefix = 'product:';
                if (name.startsWith('order:')) {
                    templateType = 'order';
                    prefix = 'order:';
                } else if (name.startsWith('customer:')) {
                    templateType = 'customer';
                    prefix = 'customer:';
                } else if (name.startsWith('coupon:')) {
                    templateType = 'coupon';
                    prefix = 'coupon:';
                } else if (name.startsWith('product:')) {
                    templateType = 'product';
                    prefix = 'product:';
                }

                // Add prefix to new name
                const newName = prefix + displayName + ' copy';

                await restPost('/import/templates/save', {
                    name: newName,
                    data: res.data,
                    type: templateType
                });
            }

            showToastOrAlert('success', 'Templates duplicated successfully.', 'Template');
            location.reload();
        } catch (e) {
            console.error('Bulk duplicate error:', e);
            showToastOrAlert('error', 'Failed to duplicate templates: ' + (e.json?.message || 'Unknown error'), 'Template');
        } finally {
            $button.prop('disabled', false).text(originalText);
        }
    });

    // Export all templates
    $(document).on('click', '#mt-primelink-export-all-templates', async function(e) {
        e.preventDefault();
        e.stopPropagation();
        try {
            const res = await restGet('/import/templates');
            const templateNames = res.templates || [];
            
            if (templateNames.length === 0) {
                showToastOrAlert('warning', 'No templates to export.', 'Template');
                return;
            }

            // Load all templates
            const templates = {};
            for (const name of templateNames) {
                try {
                    const templateRes = await restPost('/import/templates/load', { name: name });
                    templates[name] = templateRes.data;
                } catch (e) {
                    console.error('Failed to load template:', name, e);
                }
            }

            // Create JSON and download
            const json = JSON.stringify(templates, null, 2);
            const blob = new Blob([json], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'primelink-templates-' + new Date().toISOString().split('T')[0] + '.json';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        } catch (e) {
            console.error('Export error:', e);
            showToastOrAlert('error', 'Failed to export templates: ' + (e.json?.message || 'Unknown error'), 'Template');
        }
    });

    // Import templates
    $(document).on('click', '#mt-primelink-import-templates', function(e) {
        e.preventDefault();
        e.stopPropagation();
        $('#mt-primelink-import-file').click();
    });

    $(document).on('change', '#mt-primelink-import-file', async function() {
        const file = this.files[0];
        if (!file) return;

        const reader = new FileReader();
        reader.onload = async function(e) {
            try {
                const templates = JSON.parse(e.target.result);
                let imported = 0;
                let failed = 0;

                for (const [name, data] of Object.entries(templates)) {
                    try {
                        // Determine type from name
                        let type = '';
                        if (name.startsWith('order:')) type = 'order';
                        else if (name.startsWith('customer:')) type = 'customer';
                        else if (name.startsWith('coupon:')) type = 'coupon';
                        else if (name.startsWith('product:')) type = 'product';
                        else type = 'product'; // Default

                        await restPost('/import/templates/save', {
                            name: name,
                            data: data,
                            type: type
                        });
                        imported++;
                    } catch (err) {
                        console.error('Failed to import template:', name, err);
                        failed++;
                    }
                }

                showToastOrAlert('success', 'Import completed: ' + imported + ' template(s) imported' + (failed > 0 ? ', ' + failed + ' failed' : '') + '.', 'Template');
                location.reload();
            } catch (e) {
                showToastOrAlert('error', 'Failed to parse import file. Please ensure it is a valid JSON file.', 'Template');
            }
        };
        reader.readAsText(file);
    });



  // ============================================
  // Export Wizard
  // ============================================

/* PrimeLink - Export Wizard
 * Handles export wizard initialization
 */

    $(document).ready(function() {
        // Set body classes for export type and wizard
        const $body = $('body');
        const $exportTypeEl = $('[data-export-type]');
        if ($exportTypeEl.length) {
            const exportType = $exportTypeEl.data('export-type') || '';
            if (exportType) {
                $body.addClass('mt_primelink-export-' + exportType);
            }
        }
        $body.addClass('mt_primelink-export-wizard');

        // Handle import type body classes
        const $importTypeEl = $('[data-import-type]');
        if ($importTypeEl.length) {
            const importType = $importTypeEl.data('import-type') || '';
            if (importType) {
                $body.addClass('mt_primelink-import-' + importType);
            }
        }
    });



  // ============================================
  // Export Steps
  // ============================================

/* PrimeLink - Export Steps
 * Handles export wizard step-specific functionality
 */

    // Step 3: CSV format options visibility
    function initStep3() {
        const $formatSelect = $('#mt_primelink-export-format');
        if (!$formatSelect.length) return;

        $formatSelect.on('change', function() {
            if ($(this).val() === 'csv') {
                $('#mt_primelink-csv-options').slideDown(200);
            } else {
                $('#mt_primelink-csv-options').slideUp(200);
            }
        });

        // Initialize
        $formatSelect.trigger('change');
    }

    // Step 4: Export execution, status checking, and progress updates
    function initStep4() {
        const $step4 = $('.mt_primelink-export-step-4');
        if (!$step4.length) return;

        const exportId = parseInt($step4.data('export-id') || 0, 10);

        function runExport(id, background) {
            const destination = $('input[name="destination"]:checked').val() || 'download';

            $('#mt_primelink-export-status-pill').text('Starting...').removeClass('success error').addClass('warning');
            $('#mt_primelink-export-progress-bar').css('width', '0%');
            $('#mt_primelink-export-progress-text').text('0%');

            // Hide start buttons, show pause button
            $('#mt_primelink-start-export').hide();
            $('#mt_primelink-start-export-bg').hide();
            $('#mt_primelink-pause-export').show();
            $('#mt_primelink-resume-export').hide();

            $.ajax({
                url: mtPrimeLink.restUrl + '/export/run/start',
                method: 'POST',
                beforeSend: function(xhr) {
                    xhr.setRequestHeader('X-WP-Nonce', mtPrimeLink.restNonce);
                },
                data: JSON.stringify({
                    export_id: id,
                    background: background,
                    destination: destination
                }),
                contentType: 'application/json',
                success: function(response) {
                    if (response.success) {
                        if (background) {
                            $('#mt_primelink-export-bg-note').show();
                        }
                        checkExportStatus(id);
                    } else {
                        $('#mt_primelink-export-status-pill').text('Error').addClass('error');
                    }
                },
                error: function(xhr) {
                    $('#mt_primelink-export-status-pill').text('Error').addClass('error');
                    $('#mt_primelink-export-log').html('<div class="error">Failed to start export.</div>');
                    // Show start buttons again on error
                    $('#mt_primelink-start-export').show();
                    $('#mt_primelink-start-export-bg').show();
                    $('#mt_primelink-pause-export').hide();
                    $('#mt_primelink-resume-export').hide();
                }
            });
        }

        function checkExportStatus(id) {
            const interval = setInterval(function() {
                $.ajax({
                    url: mtPrimeLink.restUrl + '/export/run/status',
                    method: 'POST',
                    beforeSend: function(xhr) {
                        xhr.setRequestHeader('X-WP-Nonce', mtPrimeLink.restNonce);
                    },
                    data: JSON.stringify({
                        export_id: id
                    }),
                    contentType: 'application/json',
                    success: function(response) {
                        const progress = response.progress || 0;
                        const current = response.current || 0;
                        const total = response.total || 0;

                        $('#mt_primelink-export-progress-bar').css('width', progress + '%');
                        $('#mt_primelink-export-progress-text').text(progress + '%');
                        $('#mt_primelink-export-progress-count').text(current + ' / ' + total);
                        $('#mt_primelink-export-total').text(total);
                        $('#mt_primelink-export-current').text(current);

                        // Update pause/resume buttons based on status
                        if (response.status === 'running') {
                            $('#mt_primelink-pause-export').show();
                            $('#mt_primelink-resume-export').hide();
                            $('#mt_primelink-start-export').hide();
                            $('#mt_primelink-start-export-bg').hide();
                        } else if (response.status === 'paused') {
                            $('#mt_primelink-pause-export').hide();
                            $('#mt_primelink-resume-export').show();
                            $('#mt_primelink-start-export').hide();
                            $('#mt_primelink-start-export-bg').hide();
                        } else {
                            $('#mt_primelink-pause-export').hide();
                            $('#mt_primelink-resume-export').hide();
                            $('#mt_primelink-start-export').show();
                            $('#mt_primelink-start-export-bg').show();
                        }

                        if (response.status === 'completed') {
                            clearInterval(interval);
                            $('#mt_primelink-export-status-pill').text('Completed').addClass('success');
                            $('#mt_primelink-export-progress-status').text('Completed');
                            $('#mt_primelink-pause-export').hide();
                            $('#mt_primelink-resume-export').hide();

                            // Show download link
                            if (response.file_url) {
                                $('#mt_primelink-download-export-file').attr('href', response.file_url).attr('download', '');
                            } else if (response.file_path) {
                                const downloadUrl = mtPrimeLink.restUrl + '/export/download?export_id=' + id + '&_wpnonce=' + mtPrimeLink.restNonce;
                                $('#mt_primelink-download-export-file').attr('href', downloadUrl);
                            }
                            $('#mt_primelink-export-download-link').show();

                            // Show log if available
                            if (response.log && response.log.length > 0) {
                                const logHtml = response.log.map(log => '<div>' + log + '</div>').join('');
                                $('#mt_primelink-export-log').html(logHtml);
                            }
                        } else if (response.status === 'error') {
                            clearInterval(interval);
                            $('#mt_primelink-export-status-pill').text('Error').addClass('error');
                            $('#mt_primelink-export-log').html('<div class="error">Export failed: ' + (response.error || 'Unknown error') + '</div>');
                            $('#mt_primelink-pause-export').hide();
                            $('#mt_primelink-resume-export').hide();
                        } else if (response.status === 'paused') {
                            $('#mt_primelink-export-progress-status').text('Paused');
                        } else {
                            $('#mt_primelink-export-progress-status').text(response.status || 'Running');
                        }
                    }
                });
            }, 1000);
        }

        $(document).ready(function() {
            // Start export
            $('#mt_primelink-start-export').on('click', function() {
                if (exportId === 0) {
                    alert('Please complete all previous steps first.');
                    return;
                }
                runExport(exportId, false);
            });

            // Start export in background
            $('#mt_primelink-start-export-bg').on('click', function() {
                if (exportId === 0) {
                    alert('Please complete all previous steps first.');
                    return;
                }
                const destination = $('input[name="destination"]:checked').val() || 'download';
                $.ajax({
                    url: mtPrimeLink.restUrl + '/export/run/start',
                    method: 'POST',
                    beforeSend: function(xhr) {
                        xhr.setRequestHeader('X-WP-Nonce', mtPrimeLink.restNonce);
                    },
                    data: JSON.stringify({
                        export_id: exportId,
                        background: true,
                        destination: destination
                    }),
                    contentType: 'application/json',
                    success: function(response) {
                        if (response.success) {
                            $('#mt_primelink-export-bg-note').show();
                            if ($('#mt_primelink-export-bg-notify').is(':checked')) {
                                showToastOrAlert('success', 'Export started in background. You can navigate away.', 'Export');
                            }
                        } else {
                            showToastOrAlert('error', 'Failed to start export in background.', 'Export');
                        }
                    },
                    error: function(xhr) {
                        showToastOrAlert('error', 'Failed to start export in background.', 'Export');
                    }
                });
            });

            // Schedule export
            $('#mt_primelink-schedule-export').on('click', async function() {
                if (exportId === 0) {
                    showToastOrAlert('warning', 'Please complete all previous steps first.', 'Export');
                    return;
                }
                
                const $btn = $(this);
                const originalText = $btn.text();
                $btn.prop('disabled', true).text('Scheduling...');

                try {
                    // Check if schedule is enabled in step 3
                    const step3Data = collectExportStep3State();
                    const scheduleEnabled = step3Data.schedule && step3Data.schedule.enabled;
                    
                    if (!scheduleEnabled) {
                        showToastOrAlert('warning', 'Please enable scheduling in Step 3 (Options) first.', 'Export');
                        $btn.prop('disabled', false).text(originalText);
                        return;
                    }

                    // Save step 3 data first to ensure schedule config is saved
                    await saveExportStep3();

                    // Schedule using step 3 config
                    const res = await restPost('/export/schedule', {
                        export_id: exportId
                    });

                    if (res.scheduled) {
                        const when = res.run_at || 'immediately';
                        const recurring = res.recurring ? ' (recurring: ' + res.recurring + ')' : '';
                        showToastOrAlert('success', 'Export scheduled for ' + when + recurring + '. You can manage it in Manage Exports.', 'Export');
                    } else {
                        showToastOrAlert('error', 'Failed to schedule export.', 'Export');
                    }
                } catch (e) {
                    const error = e.json?.message || 'Failed to schedule export.';
                    alert(error);
                } finally {
                    $btn.prop('disabled', false).text(originalText);
                }
            });
        });
    }

    // Initialize based on which step elements are present
    $(document).ready(function() {
        initStep3();
        initStep4();
    });



  // ============================================
  // Orders Admin
  // ============================================



  async function refreshOrderTemplateList(selectNameToKeep){
    const $select = $('#mt_primelink-load-template');
    if(!$select.length) return;

    try {
      const res = await fetch(mtPrimeLink.restUrl + '/import/templates?type=order&ts=' + Date.now(), {
        method: 'GET',
        headers: { 'X-WP-Nonce': mtPrimeLink.restNonce }
      });
      const data = await res.json();
      const names = data.templates || [];
      let html = '<option value="">Load existing template...</option>';
      names.forEach(n=>{
        // Remove prefix for display
        const displayName = n.replace(/^order:/, '');
        html += '<option value="'+n+'">'+displayName+'</option>';
      });
      $select.html(html);
      if(selectNameToKeep){
        $select.val(selectNameToKeep);
      }
    } catch(e){
      // If list fails, keep current options
    }
  }

  $(document).ready(function(){
    if(document.body.classList.contains('mt_primelink-import-orders')){
      refreshOrderTemplateList();
    }
  });

  // ============================================
  // Export Step 3 Options
  // ============================================

  function collectExportStep3State(){
    const scheduleEnabled = $('#mt_primelink-export-enable-schedule').is(':checked');
    const schedule = {};
    
    if(scheduleEnabled){
      const scheduleType = $('#mt_primelink-export-schedule-type').val() || 'preset';
      schedule.enabled = true;
      schedule.name = $('#mt_primelink-export-schedule-name').val() || '';
      schedule.type = scheduleType;
      
      if(scheduleType === 'preset'){
        schedule.interval = $('#mt_primelink-export-schedule-interval').val() || 'daily';
        schedule.start_time = $('#mt_primelink-export-schedule-start').val() || '00:00';
        
        if(schedule.interval === 'weekly'){
          const days = [];
          $('.mt_primelink-export-schedule-day:checked').each(function(){
            days.push($(this).val());
          });
          schedule.days = days;
        } else if(schedule.interval === 'monthly'){
          schedule.month_days = $('#mt_primelink-export-schedule-month-days').val() || '';
        }
      } else if(scheduleType === 'custom'){
        schedule.cron = $('#mt_primelink-export-schedule-cron').val() || '';
      } else if(scheduleType === 'advanced'){
        const times = [];
        $('.mt_primelink-export-schedule-time-slot').each(function(){
          const time = $(this).val();
          if(time) times.push(time);
        });
        schedule.times = times;
        schedule.weekday_filter = $('#mt_primelink-export-schedule-weekday-filter').val() || '';
      }
      
      schedule.timezone = $('#mt_primelink-export-schedule-timezone').val() || '';
      schedule.start_date = $('#mt_primelink-export-schedule-start-date').val() || '';
      schedule.end_date = $('#mt_primelink-export-schedule-end-date').val() || '';
      schedule.max_runs = $('#mt_primelink-export-schedule-max-runs').val() || '';
      schedule.retry_failure = $('#mt_primelink-export-schedule-retry-failure').is(':checked');
      if(schedule.retry_failure){
        schedule.retry_attempts = parseInt($('#mt_primelink-export-schedule-retry-attempts').val() || '3', 10);
        schedule.retry_delay = parseInt($('#mt_primelink-export-schedule-retry-delay').val() || '30', 10);
      }
      schedule.pause_on_error = $('#mt_primelink-export-schedule-pause-on-error').is(':checked');
    }
    
    const data = {
      format: $('#mt_primelink-export-format').val() || 'csv',
      csv_delimiter: $('#mt_primelink-csv-delimiter').val() || ',',
      csv_encoding: $('#mt_primelink-csv-encoding').val() || 'UTF-8',
      include_headers: $('#mt_primelink-export-include-headers').is(':checked'),
      limit: parseInt($('#mt_primelink-export-limit').val() || '0', 10),
      filters: {
        status: $('#mt_primelink-export-status').val() || 'publish',
        categories: $('#mt_primelink-export-categories').val() || [],
        tags: $('#mt_primelink-export-tags').val() || []
      },
      speed_optimization: $('#mt_primelink-export-speed-optimization').is(':checked'),
      iterative_processing: $('#mt_primelink-export-iterative-processing').is(':checked'),
      iteration_size: parseInt($('#mt_primelink-export-iteration-size').val() || '20', 10),
      incremental: {
        enabled: $('#mt_primelink-export-incremental-enabled').is(':checked'),
        since: $('#mt_primelink-export-incremental-since').val() || '',
        skip_unchanged: $('#mt_primelink-export-incremental-skip-unchanged').is(':checked')
      },
      test_mode: {
        enabled: $('#mt_primelink-export-test-mode').is(':checked'),
        limit: parseInt($('#mt_primelink-export-test-limit').val() || '10', 10)
      },
      notifications: {
        override: $('#mt_primelink-export-notify-override').is(':checked'),
        email: $('#mt_primelink-export-notify-email-override').val() || '',
        finish_template: $('#mt_primelink-export-notify-finish-override').val() || '',
        error_template: $('#mt_primelink-export-notify-error-override').val() || '',
        attach_file: $('#mt_primelink-export-email-attachment').is(':checked')
      },
      schedule: schedule
    };
    return data;
  }

  async function saveExportStep3(){
    const exportId = currentExportId() || parseInt($('.mt_primelink-export-step-3').data('export-id'), 10) || 0;
    if(!exportId){
      try{
        const draft = await restPost('/export/create-draft', {});
        exportId = draft.export_id || 0;
        if(exportId){
          setExportIdEverywhere(exportId);
          $('.mt_primelink-export-step-3').attr('data-export-id', exportId);
        }
      }catch(e){
        console.error('Export ID missing:', e);
        return;
      }
    }
    const data = collectExportStep3State();
    try{
      await restPost('/export/save-step', {
        export_id: exportId,
        step: 3,
        data: data
      });
    }catch(e){
      console.error('Failed to save export step 3:', e);
    }
  }

  function applyExportStep3State(data){
    data = data || {};
    
    // Format options
    if(data.format) $('#mt_primelink-export-format').val(data.format);
    if(data.csv_delimiter) $('#mt_primelink-csv-delimiter').val(data.csv_delimiter);
    if(data.csv_encoding) $('#mt_primelink-csv-encoding').val(data.csv_encoding);
    if(data.include_headers !== undefined) $('#mt_primelink-export-include-headers').prop('checked', data.include_headers);
    if(data.limit !== undefined) $('#mt_primelink-export-limit').val(data.limit);
    
    // Filters
    if(data.filters){
      if(data.filters.status) $('#mt_primelink-export-status').val(data.filters.status);
      if(Array.isArray(data.filters.categories)) $('#mt_primelink-export-categories').val(data.filters.categories);
      if(Array.isArray(data.filters.tags)) $('#mt_primelink-export-tags').val(data.filters.tags);
    }
    
    // Advanced options
    if(data.speed_optimization !== undefined) $('#mt_primelink-export-speed-optimization').prop('checked', data.speed_optimization);
    if(data.iterative_processing !== undefined) $('#mt_primelink-export-iterative-processing').prop('checked', data.iterative_processing);
    if(data.iteration_size) $('#mt_primelink-export-iteration-size').val(data.iteration_size);
    
    // Incremental export
    if(data.incremental){
      if(data.incremental.enabled !== undefined){
        $('#mt_primelink-export-incremental-enabled').prop('checked', data.incremental.enabled);
        if(data.incremental.enabled){
          $('#mt_primelink-export-incremental-options').slideDown(120);
        }
      }
      if(data.incremental.since) $('#mt_primelink-export-incremental-since').val(data.incremental.since);
      if(data.incremental.skip_unchanged !== undefined) $('#mt_primelink-export-incremental-skip-unchanged').prop('checked', data.incremental.skip_unchanged);
    }
    
    // Test mode
    if(data.test_mode){
      if(data.test_mode.enabled !== undefined){
        $('#mt_primelink-export-test-mode').prop('checked', data.test_mode.enabled);
        if(data.test_mode.enabled){
          $('#mt_primelink-export-test-mode-options').slideDown(120);
        }
      }
      if(data.test_mode.limit) $('#mt_primelink-export-test-limit').val(data.test_mode.limit);
    }
    
    // Notifications
    if(data.notifications){
      if(data.notifications.override !== undefined){
        $('#mt_primelink-export-notify-override').prop('checked', data.notifications.override);
        if(data.notifications.override){
          $('#mt_primelink-export-notify-override-wrap').slideDown(120);
        }
      }
      if(data.notifications.email) $('#mt_primelink-export-notify-email-override').val(data.notifications.email);
      if(data.notifications.finish_template) $('#mt_primelink-export-notify-finish-override').val(data.notifications.finish_template);
      if(data.notifications.error_template) $('#mt_primelink-export-notify-error-override').val(data.notifications.error_template);
      if(data.notifications.attach_file !== undefined) $('#mt_primelink-export-email-attachment').prop('checked', data.notifications.attach_file);
    }
    
    // Schedule
    if(data.schedule){
      if(data.schedule.enabled !== undefined){
        $('#mt_primelink-export-enable-schedule').prop('checked', data.schedule.enabled);
        if(data.schedule.enabled){
          $('#mt_primelink-export-schedule-wrap').slideDown(120);
        }
      }
      if(data.schedule.name) $('#mt_primelink-export-schedule-name').val(data.schedule.name);
      if(data.schedule.type) $('#mt_primelink-export-schedule-type').val(data.schedule.type);
      if(data.schedule.interval) $('#mt_primelink-export-schedule-interval').val(data.schedule.interval);
      if(data.schedule.start_time) $('#mt_primelink-export-schedule-start').val(data.schedule.start_time);
      if(data.schedule.cron) $('#mt_primelink-export-schedule-cron').val(data.schedule.cron);
      if(data.schedule.timezone) $('#mt_primelink-export-schedule-timezone').val(data.schedule.timezone);
      if(data.schedule.start_date) $('#mt_primelink-export-schedule-start-date').val(data.schedule.start_date);
      if(data.schedule.end_date) $('#mt_primelink-export-schedule-end-date').val(data.schedule.end_date);
      if(data.schedule.max_runs) $('#mt_primelink-export-schedule-max-runs').val(data.schedule.max_runs);
      if(data.schedule.retry_failure !== undefined){
        $('#mt_primelink-export-schedule-retry-failure').prop('checked', data.schedule.retry_failure);
        if(data.schedule.retry_failure){
          $('#mt_primelink-export-schedule-retry-options').slideDown(120);
        }
      }
      if(data.schedule.retry_attempts) $('#mt_primelink-export-schedule-retry-attempts').val(data.schedule.retry_attempts);
      if(data.schedule.retry_delay) $('#mt_primelink-export-schedule-retry-delay').val(data.schedule.retry_delay);
      if(data.schedule.pause_on_error !== undefined) $('#mt_primelink-export-schedule-pause-on-error').prop('checked', data.schedule.pause_on_error);
      if(data.schedule.month_days) $('#mt_primelink-export-schedule-month-days').val(data.schedule.month_days);
      if(Array.isArray(data.schedule.days)){
        $('.mt_primelink-export-schedule-day').prop('checked', false);
        data.schedule.days.forEach(day => {
          $('.mt_primelink-export-schedule-day[value="' + day + '"]').prop('checked', true);
        });
      }
      if(Array.isArray(data.schedule.times) && data.schedule.times.length > 0){
        const $wrap = $('#mt_primelink-export-schedule-times-wrap');
        $wrap.empty();
        data.schedule.times.forEach((time, idx) => {
          const $row = $(renderExportScheduleTimeRow(time, idx > 0));
          $wrap.append($row);
        });
      }
      if(data.schedule.weekday_filter) $('#mt_primelink-export-schedule-weekday-filter').val(data.schedule.weekday_filter);
      
      // Update UI based on schedule type
      updateExportScheduleTypeUI();
    }
  }

  function renderExportScheduleTimeRow(time, showRemove){
    return '<div class="mt_primelink-export-schedule-time-row" style="display:grid;grid-template-columns:1fr auto;gap:8px;margin-bottom:4px;">' +
      '<input type="time" class="mt_primelink-export-schedule-time-slot" value="' + escapeHtml(time || '00:00') + '" />' +
      '<button type="button" class="button mt_primelink-export-schedule-time-remove" ' + (showRemove ? '' : 'style="display:none;"') + '>Remove</button>' +
      '</div>';
  }

  function updateExportScheduleTypeUI(){
    const type = $('#mt_primelink-export-schedule-type').val();
    $('.mt_primelink-export-schedule-type-wrap').hide();
    
    if(type === 'preset'){
      $('#mt_primelink-export-schedule-preset-wrap').show();
      const interval = $('#mt_primelink-export-schedule-interval').val();
      if(interval === 'weekly'){
        $('#mt_primelink-export-schedule-weekly-options').show();
      } else {
        $('#mt_primelink-export-schedule-weekly-options').hide();
      }
      if(interval === 'monthly'){
        $('#mt_primelink-export-schedule-monthly-options').show();
      } else {
        $('#mt_primelink-export-schedule-monthly-options').hide();
      }
    } else if(type === 'custom'){
      $('#mt_primelink-export-schedule-custom-wrap').show();
    } else if(type === 'advanced'){
      $('#mt_primelink-export-schedule-advanced-wrap').show();
    }
  }

  // Toggle incremental export options
  $(document).on('change', '#mt_primelink-export-incremental-enabled', function(){
    if($(this).is(':checked')){
      $('#mt_primelink-export-incremental-options').slideDown(120);
    } else {
      $('#mt_primelink-export-incremental-options').slideUp(120);
    }
    saveExportStep3();
  });

  // Toggle test mode options
  $(document).on('change', '#mt_primelink-export-test-mode', function(){
    if($(this).is(':checked')){
      $('#mt_primelink-export-test-mode-options').slideDown(120);
    } else {
      $('#mt_primelink-export-test-mode-options').slideUp(120);
    }
    saveExportStep3();
  });

  // Toggle notifications override
  $(document).on('change', '#mt_primelink-export-notify-override', function(){
    if($(this).is(':checked')){
      $('#mt_primelink-export-notify-override-wrap').slideDown(120);
    } else {
      $('#mt_primelink-export-notify-override-wrap').slideUp(120);
    }
    saveExportStep3();
  });

  // Test export button
  $(document).on('click', '#mt_primelink-run-test-export', async function(){
    const exportId = currentExportId() || parseInt($('.mt_primelink-export-step-3').data('export-id'), 10) || 0;
    if(!exportId){
      alert('Please complete step 1 first.');
      return;
    }
    
    const $btn = $(this);
    const $results = $('#mt_primelink-export-test-results');
    const $resultsContent = $('#mt_primelink-export-test-results-content');
    
    $btn.prop('disabled', true).text('Running test...');
    $results.hide();
    $resultsContent.html('<p>Running test export...</p>');
    
    try{
      const testLimit = parseInt($('#mt_primelink-export-test-limit').val() || '10', 10);
      const state = collectExportStep3State();
      
      // Run test export (similar to preview but with limit)
      const res = await restPost('/export/preview', {
        export_id: exportId,
        page: 1,
        per_page: testLimit
      });
      
      const total = res.total || 0;
      const rows = res.rows || [];
      
      let html = '<div class="mt_primelink-test-results-summary">';
      html += '<p><strong>Test Results:</strong></p>';
      html += '<ul>';
      html += '<li>Total products matching filters: ' + total + '</li>';
      html += '<li>Products in test preview: ' + rows.length + '</li>';
      html += '<li>Export format: ' + escapeHtml(state.format || 'csv') + '</li>';
      html += '<li>Include headers: ' + (state.include_headers ? 'Yes' : 'No') + '</li>';
      html += '</ul>';
      html += '</div>';
      
      if(rows.length > 0){
        html += '<p style="margin-top:12px;"><strong>Preview of first ' + rows.length + ' product(s):</strong></p>';
        html += '<div style="max-height:300px;overflow-y:auto;margin-top:8px;">';
        html += '<table style="width:100%;font-size:12px;">';
        html += '<thead><tr>';
        const headers = res.headers || [];
        headers.forEach(h => {
          html += '<th style="padding:4px;border:1px solid rgba(255,255,255,0.1);">' + escapeHtml(h) + '</th>';
        });
        html += '</tr></thead><tbody>';
        rows.forEach(row => {
          html += '<tr>';
          row.forEach(cell => {
            html += '<td style="padding:4px;border:1px solid rgba(255,255,255,0.1);">' + escapeHtml(String(cell || '').substring(0, 50)) + '</td>';
          });
          html += '</tr>';
        });
        html += '</tbody></table>';
        html += '</div>';
      }
      
      $resultsContent.html(html);
      $results.slideDown(200);
    }catch(e){
      $resultsContent.html('<p style="color:#f00;">Test failed: ' + escapeHtml(e.json?.message || 'Unknown error') + '</p>');
      $results.slideDown(200);
    }finally{
      $btn.prop('disabled', false).text('Run Test Export');
    }
  });

  // Toggle schedule options
  $(document).on('change', '#mt_primelink-export-enable-schedule', function(){
    if($(this).is(':checked')){
      $('#mt_primelink-export-schedule-wrap').slideDown(120);
    } else {
      $('#mt_primelink-export-schedule-wrap').slideUp(120);
    }
    saveExportStep3();
  });

  // Schedule type change
  $(document).on('change', '#mt_primelink-export-schedule-type', function(){
    updateExportScheduleTypeUI();
    saveExportStep3();
  });

  // Schedule interval change
  $(document).on('change', '#mt_primelink-export-schedule-interval', function(){
    const interval = $(this).val();
    if(interval === 'weekly'){
      $('#mt_primelink-export-schedule-weekly-options').slideDown(120);
      $('#mt_primelink-export-schedule-monthly-options').slideUp(120);
    } else if(interval === 'monthly'){
      $('#mt_primelink-export-schedule-monthly-options').slideDown(120);
      $('#mt_primelink-export-schedule-weekly-options').slideUp(120);
    } else {
      $('#mt_primelink-export-schedule-weekly-options').slideUp(120);
      $('#mt_primelink-export-schedule-monthly-options').slideUp(120);
    }
    saveExportStep3();
  });

  // Add time slot
  $(document).on('click', '#mt_primelink-export-schedule-time-add', function(){
    const $wrap = $('#mt_primelink-export-schedule-times-wrap');
    const $rows = $wrap.find('.mt_primelink-export-schedule-time-row');
    const $row = $(renderExportScheduleTimeRow('00:00', $rows.length > 0));
    $wrap.append($row);
    $wrap.find('.mt_primelink-export-schedule-time-remove').show();
    saveExportStep3();
  });

  // Remove time slot
  $(document).on('click', '.mt_primelink-export-schedule-time-remove', function(){
    $(this).closest('.mt_primelink-export-schedule-time-row').remove();
    const $rows = $('#mt_primelink-export-schedule-times-wrap').find('.mt_primelink-export-schedule-time-row');
    if($rows.length <= 1){
      $rows.find('.mt_primelink-export-schedule-time-remove').hide();
    }
    saveExportStep3();
  });

  // Retry on failure toggle
  $(document).on('change', '#mt_primelink-export-schedule-retry-failure', function(){
    if($(this).is(':checked')){
      $('#mt_primelink-export-schedule-retry-options').slideDown(120);
    } else {
      $('#mt_primelink-export-schedule-retry-options').slideUp(120);
    }
    saveExportStep3();
  });

  // Auto-save for all step 3 inputs
  $(document).on('change blur', '.mt_primelink-export-step-3 input, .mt_primelink-export-step-3 select, .mt_primelink-export-step-3 textarea', function(){
    saveExportStep3();
  });

  // Load saved step 3 data on page load
  $(document).ready(function(){
    if($('.mt_primelink-export-step-3').length){
      const exportId = currentExportId() || parseInt($('.mt_primelink-export-step-3').data('export-id'), 10) || 0;
      if(exportId){
        restPost('/export/get-draft', { export_id: exportId }).then(draft => {
          if(draft && draft.step_data && draft.step_data[3]){
            applyExportStep3State(draft.step_data[3]);
          }
        }).catch(e => {
          console.error('Failed to load export step 3:', e);
        });
      }
    }
  });

  // Anomalies Modal Functions
  async function showAnomaliesModal(importId) {
    const $modal = $('#mt-primelink-anomalies-modal');
    if ($modal.length === 0) return;
    
    // Store import ID in modal for later use
    $modal.data('import-id', importId);
    
    $modal.show();
    $('#mt-primelink-anomalies-loading').show();
    $('#mt-primelink-anomalies-content').hide();
    $('#mt-primelink-anomalies-empty').hide();
    
    try {
      const response = await restPost('/import/anomalies', { import_id: importId });
      const anomalies = response.anomalies || [];
      
      $('#mt-primelink-anomalies-loading').hide();
      
      if (anomalies.length === 0) {
        $('#mt-primelink-anomalies-empty').show();
        $('.mt-primelink-anomalies-export-wrapper').hide();
        return;
      }
      
      $('#mt-primelink-anomalies-count').text(anomalies.length);
      $('#mt-primelink-anomalies-content').show();
      
      // Show export button
      $('.mt-primelink-anomalies-export-wrapper').show();
      
      // Store anomalies data for export
      $modal.data('anomalies-data', anomalies);
      
      // Render anomalies list as a compact table
      const $list = $('#mt-primelink-anomalies-list');
      $list.empty();

      const $table = $('<table class="mt-primelink-anomalies-table"></table>');
      const $thead = $('<thead><tr>' +
        '<th>Row</th>' +
        '<th>Item</th>' +
        '<th>Level</th>' +
        '<th>Type</th>' +
        '<th>Message</th>' +
      '</tr></thead>');
      const $tbody = $('<tbody></tbody>');

      anomalies.forEach((anomalyGroup, index) => {
        const itemData = anomalyGroup.item_data || {};
        const anomaliesList = anomalyGroup.anomalies || [];
        const itemIndex = anomalyGroup.item_index !== undefined ? anomalyGroup.item_index : index;
        const rowNumber = itemIndex + 1;

        // Extract title from various possible structures (flat and nested)
        let title = '';
        if (itemData.post && itemData.post.post_title) {
          title = itemData.post.post_title;
        } else if (itemData.post_title) {
          title = itemData.post_title;
        } else if (itemData.product && itemData.product.name) {
          title = itemData.product.name;
        } else if (itemData.name) {
          title = itemData.name;
        } else if (itemData.product && itemData.product.sku) {
          title = itemData.product.sku;
        } else if (itemData.sku) {
          title = itemData.sku;
        } else {
          title = 'Unknown Item';
        }

        anomaliesList.forEach(anomaly => {
          const level = (anomaly.level || 'info').toLowerCase();
          const type  = anomaly.type || 'Unknown';
          const msg   = anomaly.message || 'No message';

          const $tr = $('<tr></tr>');
          $tr.append(`<td class="mt-primelink-anomaly-col-row">${rowNumber}</td>`);
          
          // Make title clickable to navigate to the item
          const $itemCell = $('<td class="mt-primelink-anomaly-col-item"></td>');
          const $itemLink = $('<a href="#" class="mt-primelink-anomaly-item-link" data-item-index="' + itemIndex + '" data-import-id="' + importId + '"></a>');
          $itemLink.text(title);
          $itemCell.append($itemLink);
          $tr.append($itemCell);

          const $levelTd = $('<td class="mt-primelink-anomaly-col-level"></td>');
          const $badge   = $('<span class="mt-primelink-anomaly-badge"></span>');
          $badge.addClass(level);
          $badge.text(level.toUpperCase());
          $levelTd.append($badge);
          $tr.append($levelTd);

          $tr.append(`<td class="mt-primelink-anomaly-col-type">${type}</td>`);
          $tr.append(`<td class="mt-primelink-anomaly-col-message">${msg}</td>`);

          $tbody.append($tr);
        });
      });

      $table.append($thead);
      $table.append($tbody);
      $list.append($table);
    } catch (e) {
      $('#mt-primelink-anomalies-loading').hide();
      $('#mt-primelink-anomalies-content').hide();
      $('#mt-primelink-anomalies-empty').show();
      $('#mt-primelink-anomalies-empty p').text('Failed to load anomalies: ' + (e.message || 'Unknown error'));
    }
  }
  
  function hideAnomaliesModal() {
    $('#mt-primelink-anomalies-modal').hide();
  }
  
  // Close modal handlers
  $(document).on('click', '#mt-primelink-anomalies-modal-close, #mt-primelink-anomalies-modal-close-btn', function(e) {
    e.preventDefault();
    hideAnomaliesModal();
  });
  
  // Handle click on anomaly item link to navigate to item in import
  $(document).on('click', '.mt-primelink-anomaly-item-link', function(e) {
    e.preventDefault();
    const itemIndex = parseInt($(this).data('item-index'), 10);
    const importId = parseInt($(this).data('import-id'), 10);
    
    if (isNaN(itemIndex) || isNaN(importId) || importId < 1) {
      return;
    }
    
    // Get import type from the import row on the page
    const $importRow = $('.mt_primelink-import-row[data-id="' + importId + '"]');
    let importType = $importRow.data('type') || '';
    
    // Normalize import type for URL (convert singular to plural)
    const typeMap = {
      'product': 'products',
      'order': 'orders',
      'customer': 'customers',
      'coupon': 'coupons',
      'category': 'categories',
      'tag': 'tags',
      'attribute': 'attributes',
      'variation': 'variations',
      'review': 'reviews',
      'download': 'downloads'
    };
    if (typeMap[importType]) {
      importType = typeMap[importType];
    }
    
    // If import type not found, try to get it from draft
    if (!importType) {
      restPost('/import/get', { import_id: importId }).then(function(response) {
        if (response && response.draft) {
          const draftType = response.draft.type || (response.draft.step_data && response.draft.step_data[1] && response.draft.step_data[1].type) || '';
          const normalizedType = typeMap[draftType] || draftType;
          navigateToImportItem(importId, normalizedType, itemIndex);
        }
      }).catch(function() {
        // Fallback: navigate without type
        navigateToImportItem(importId, '', itemIndex);
      });
    } else {
      navigateToImportItem(importId, importType, itemIndex);
    }
  });
  
  function navigateToImportItem(importId, importType, itemIndex) {
    const adminUrl = (typeof mtPrimeLink !== 'undefined' && mtPrimeLink.adminUrl) ? mtPrimeLink.adminUrl : '';
    let url = adminUrl + 'admin.php?page=mt-primelink-new-import&import_id=' + importId + '&step=4';
    
    if (importType) {
      url += '&import_type=' + encodeURIComponent(importType);
    }
    
    // Add preview_index parameter to navigate to specific row
    url += '&preview_index=' + itemIndex;
    
    // Close modal and navigate
    hideAnomaliesModal();
    window.location.href = url;
  }
  
  // Export dropdown toggle
  $(document).on('click', '.mt-primelink-export-button', function(e) {
    e.stopPropagation();
    const $dropdown = $(this).closest('.mt-primelink-dropdown');
    $dropdown.toggleClass('open');
  });
  
  // Close dropdown when clicking outside
  $(document).on('click', function(e) {
    if (!$(e.target).closest('.mt-primelink-dropdown').length) {
      $('.mt-primelink-dropdown').removeClass('open');
    }
  });
  
  // Export to CSV
  $(document).on('click', '.mt-primelink-export-csv', function(e) {
    e.preventDefault();
    e.stopPropagation();
    const $modal = $('#mt-primelink-anomalies-modal');
    const anomalies = $modal.data('anomalies-data') || [];
    const importId = $modal.data('import-id') || 0;
    exportAnomaliesToCSV(anomalies, importId);
    $('.mt-primelink-dropdown').removeClass('open');
  });
  
  // Export to Excel
  $(document).on('click', '.mt-primelink-export-excel', function(e) {
    e.preventDefault();
    e.stopPropagation();
    const $modal = $('#mt-primelink-anomalies-modal');
    const anomalies = $modal.data('anomalies-data') || [];
    const importId = $modal.data('import-id') || 0;
    exportAnomaliesToExcel(anomalies, importId);
    $('.mt-primelink-dropdown').removeClass('open');
  });
  
  // Export anomalies to CSV
  function exportAnomaliesToCSV(anomalies, importId) {
    const headers = ['Row', 'Item', 'Level', 'Type', 'Message'];
    const rows = [];
    
    anomalies.forEach((anomalyGroup, index) => {
      const itemData = anomalyGroup.item_data || {};
      const anomaliesList = anomalyGroup.anomalies || [];
      const itemIndex = anomalyGroup.item_index !== undefined ? anomalyGroup.item_index : index;
      const rowNumber = itemIndex + 1;
      
      // Extract title
      let title = '';
      if (itemData.post && itemData.post.post_title) {
        title = itemData.post.post_title;
      } else if (itemData.post_title) {
        title = itemData.post_title;
      } else if (itemData.product && itemData.product.name) {
        title = itemData.product.name;
      } else if (itemData.name) {
        title = itemData.name;
      } else if (itemData.product && itemData.product.sku) {
        title = itemData.product.sku;
      } else if (itemData.sku) {
        title = itemData.sku;
      } else {
        title = 'Unknown Item';
      }
      
      anomaliesList.forEach(anomaly => {
        const level = (anomaly.level || 'info').toUpperCase();
        const type = anomaly.type || 'Unknown';
        const msg = anomaly.message || 'No message';
        rows.push([rowNumber, title, level, type, msg]);
      });
    });
    
    // Convert to CSV
    let csv = headers.map(h => escapeCSVField(h)).join(',') + '\n';
    rows.forEach(row => {
      csv += row.map(field => escapeCSVField(field)).join(',') + '\n';
    });
    
    // Create download link
    const blob = new Blob(['\ufeff' + csv], { type: 'text/csv;charset=utf-8;' });
    const link = document.createElement('a');
    const url = URL.createObjectURL(blob);
    link.setAttribute('href', url);
    link.setAttribute('download', 'anomalies-import-' + importId + '-' + new Date().toISOString().split('T')[0] + '.csv');
    link.style.visibility = 'hidden';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }
  
  // Export anomalies to Excel (XLSX) - using CSV format (Excel can open CSV files)
  function exportAnomaliesToExcel(anomalies, importId) {
    // Excel can open CSV files, so we'll export as CSV with .xlsx extension
    // For a true Excel format with formatting, you would need a library like SheetJS
    const headers = ['Row', 'Item', 'Level', 'Type', 'Message'];
    const rows = [];
    
    anomalies.forEach((anomalyGroup, index) => {
      const itemData = anomalyGroup.item_data || {};
      const anomaliesList = anomalyGroup.anomalies || [];
      const itemIndex = anomalyGroup.item_index !== undefined ? anomalyGroup.item_index : index;
      const rowNumber = itemIndex + 1;
      
      // Extract title
      let title = '';
      if (itemData.post && itemData.post.post_title) {
        title = itemData.post.post_title;
      } else if (itemData.post_title) {
        title = itemData.post_title;
      } else if (itemData.product && itemData.product.name) {
        title = itemData.product.name;
      } else if (itemData.name) {
        title = itemData.name;
      } else if (itemData.product && itemData.product.sku) {
        title = itemData.product.sku;
      } else if (itemData.sku) {
        title = itemData.sku;
      } else {
        title = 'Unknown Item';
      }
      
      anomaliesList.forEach(anomaly => {
        const level = (anomaly.level || 'info').toUpperCase();
        const type = anomaly.type || 'Unknown';
        const msg = anomaly.message || 'No message';
        rows.push([rowNumber, title, level, type, msg]);
      });
    });
    
    // Convert to CSV with comma separator (Excel can open CSV files with .xlsx extension)
    let csv = headers.map(h => escapeCSVField(h, ',')).join(',') + '\n';
    rows.forEach(row => {
      csv += row.map(field => escapeCSVField(field, ',')).join(',') + '\n';
    });
    
    // Create download link with .xlsx extension
    // Excel will open this CSV file correctly
    const blob = new Blob(['\ufeff' + csv], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8;' });
    const link = document.createElement('a');
    const url = URL.createObjectURL(blob);
    link.setAttribute('href', url);
    link.setAttribute('download', 'anomalies-import-' + importId + '-' + new Date().toISOString().split('T')[0] + '.xlsx');
    link.style.visibility = 'hidden';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }
  
  // Escape CSV field
  function escapeCSVField(field, separator = ',') {
    if (field === null || field === undefined) {
      return '';
    }
    const str = String(field);
    // If field contains separator, quote, or newline, wrap in quotes and escape quotes
    if (str.includes(separator) || str.includes('"') || str.includes('\n')) {
      return '"' + str.replace(/"/g, '""') + '"';
    }
    return str;
  }
  
  // Close on overlay click
  $(document).on('click', '#mt-primelink-anomalies-modal', function(e) {
    if ($(e.target).is('#mt-primelink-anomalies-modal')) {
      hideAnomaliesModal();
    }
  });
  
  // Close on ESC key
  $(document).on('keydown', function(e) {
    if (e.key === 'Escape' && $('#mt-primelink-anomalies-modal').is(':visible')) {
      hideAnomaliesModal();
    }
  });
  
  // Check for anomalies when manage-imports page loads for finished imports
  $(document).ready(function() {
    if ($('.mt_primelink-import-row').length > 0) {
      $('.mt_primelink-import-row').each(function() {
        const $row = $(this);
        const importId = parseInt($row.data('id'), 10);
        if (!importId) {
          return;
        }
        // Întotdeauna verificăm dacă există anomalii pentru acest import
        restPost('/import/anomalies', { import_id: importId }).then(response => {
          const anomalies = response.anomalies || [];
          ensureAnomalyButton(importId, anomalies.length);
        }).catch(() => {
          // Ignore errors
        });
      });
    }
  });
  
  // Handler for review anomalies button
  $(document).on('click', '.mt-primelink-review-anomalies', function() {
    const importId = parseInt($(this).data('id'), 10);
    if (importId > 0) {
      showAnomaliesModal(importId);
    }
  });

  // Check license status on page load
  $(document).ready(function() {
    if ($('#mt_primelink-license-status').length) {
      const $status = $('#mt_primelink-license-status');
      const activation = window.mt_primelinkSettings?.license_activation || {};
      const isActive = activation.activated || false;
      
      if (isActive) {
        $status.text('Active').removeClass('mt_primelink-status-idle').addClass('mt_primelink-status-finished');
      } else {
        $status.text('Inactive').removeClass('mt_primelink-status-finished').addClass('mt_primelink-status-idle');
      }
    }
  });

  // License test & activate handler
  $(document).on('click', '#mt-primelink-test-license', function(e) {
    e.preventDefault();
    
    const $btn = $(this);
    const $result = $('#mt-primelink-license-test-result');
    const $status = $('#mt_primelink-license-status');
    const purchaseCode = $('#mt_primelink-license-key').val().trim();
    const clientName = $('#mt_primelink-license-client-name').val().trim();
    
    if (!purchaseCode || !clientName) {
      $result.removeClass('success error').addClass('error')
        .html('<strong>' + escapeHtml('Error:') + '</strong> ' + escapeHtml('Please enter both Purchase Code and Client Name.'))
        .fadeIn();
      return;
    }
    
    const originalText = $btn.text();
    $btn.prop('disabled', true).text('Activating...');
    $result.hide();
    $status.text('Activating...').removeClass('mt_primelink-status-idle mt_primelink-status-finished').addClass('mt_primelink-status-idle');
    
    $.ajax({
      url: mtPrimeLink.restUrl + '/settings/test-license',
      method: 'POST',
      headers: {
        'X-WP-Nonce': mtPrimeLink.restNonce
      },
      data: {
        purchase_code: purchaseCode,
        client_name: clientName
      },
      success: function(response) {
        if (response.success) {
          $result.removeClass('error').addClass('success')
            .html('<strong>' + escapeHtml('Success:') + '</strong> ' + escapeHtml(response.message || 'License activated successfully!'))
            .fadeIn();
          $status.text('Active').removeClass('mt_primelink-status-idle').addClass('mt_primelink-status-finished');
          
          // Reload page after 1.5 seconds to show updated license status
          setTimeout(function() {
            window.location.reload();
          }, 1500);
        } else {
          $result.removeClass('success').addClass('error')
            .html('<strong>' + escapeHtml('Error:') + '</strong> ' + escapeHtml(response.error || 'License activation failed.'))
            .fadeIn();
          $status.text('Failed').removeClass('mt_primelink-status-finished').addClass('mt_primelink-status-idle');
          $btn.prop('disabled', false).text(originalText);
        }
      },
      error: function(xhr) {
        const error = xhr.responseJSON?.error || xhr.responseJSON?.message || 'Failed to activate license. Please try again.';
        $result.removeClass('success').addClass('error')
          .html('<strong>' + escapeHtml('Error:') + '</strong> ' + escapeHtml(error))
          .fadeIn();
        $status.text('Failed').removeClass('mt_primelink-status-finished').addClass('mt_primelink-status-idle');
        $btn.prop('disabled', false).text(originalText);
      }
    });
  });

  // License check updates handler
  $(document).on('click', '#mt-primelink-check-updates', function(e) {
    e.preventDefault();
    
    const $btn = $(this);
    const $result = $('#mt-primelink-license-test-result');
    
    const originalText = $btn.text();
    $btn.prop('disabled', true).text('Checking...');
    $result.hide();
    
    $.ajax({
      url: mtPrimeLink.restUrl + '/settings/check-updates',
      method: 'GET',
      headers: {
        'X-WP-Nonce': mtPrimeLink.restNonce
      },
      success: function(response) {
        if (response.success) {
          let message = '<strong>Update Check Results:</strong><br>';
          message += 'Current Version: ' + escapeHtml(response.current_version) + '<br>';
          
          if (response.has_update) {
            message += '<span style="color:#28a745;">✓ New version available: ' + escapeHtml(response.update_data.version || 'N/A') + '</span><br>';
            if (response.update_data.download_url) {
              message += 'Download URL: ' + escapeHtml(response.update_data.download_url) + '<br>';
            }
            if (response.update_data.changelog) {
              message += 'Changelog: ' + escapeHtml(response.update_data.changelog.substring(0, 200)) + '...<br>';
            }
          } else {
            message += '<span style="color:#6c757d;">No updates available</span><br>';
          }
          
          message += '<br><strong>Raw Response:</strong><br><pre style="font-size:11px;max-height:200px;overflow:auto;">' + escapeHtml(JSON.stringify(response.update_data, null, 2)) + '</pre>';
          
          $result.removeClass('error').addClass('success')
            .html(message)
            .fadeIn();
        } else {
          $result.removeClass('success').addClass('error')
            .html('<strong>Error:</strong> ' + escapeHtml(response.error || 'Failed to check for updates.'))
            .fadeIn();
        }
        $btn.prop('disabled', false).text(originalText);
      },
      error: function(xhr) {
        const error = xhr.responseJSON?.error || xhr.responseJSON?.message || 'Failed to check for updates. Please try again.';
        $result.removeClass('success').addClass('error')
          .html('<strong>Error:</strong> ' + escapeHtml(error))
          .fadeIn();
        $btn.prop('disabled', false).text(originalText);
      }
    });
  });

  // License deactivate handler
  $(document).on('click', '#mt-primelink-deactivate-license', function(e) {
    e.preventDefault();
    
    if (!confirm('Are you sure you want to deactivate your license? You will need to reactivate it to receive updates.')) {
      return;
    }
    
    const $btn = $(this);
    const $result = $('#mt-primelink-license-test-result');
    const $status = $('#mt_primelink-license-status');
    
    const originalText = $btn.text();
    $btn.prop('disabled', true).text('Deactivating...');
    $result.hide();
    $status.text('Deactivating...').removeClass('mt_primelink-status-idle mt_primelink-status-finished').addClass('mt_primelink-status-idle');
    
    $.ajax({
      url: mtPrimeLink.restUrl + '/settings/deactivate-license',
      method: 'POST',
      headers: {
        'X-WP-Nonce': mtPrimeLink.restNonce
      },
      success: function(response) {
        if (response.success) {
          $result.removeClass('error').addClass('success')
            .html('<strong>' + escapeHtml('Success:') + '</strong> ' + escapeHtml(response.message || 'License deactivated successfully.'))
            .fadeIn();
          $status.text('Inactive').removeClass('mt_primelink-status-finished').addClass('mt_primelink-status-idle');
          
          // Reload page after 1.5 seconds to show updated license status
          setTimeout(function() {
            window.location.reload();
          }, 1500);
        } else {
          $result.removeClass('success').addClass('error')
            .html('<strong>' + escapeHtml('Error:') + '</strong> ' + escapeHtml(response.error || 'License deactivation failed.'))
            .fadeIn();
          $status.text('Failed').removeClass('mt_primelink-status-finished').addClass('mt_primelink-status-idle');
          $btn.prop('disabled', false).text(originalText);
        }
      },
      error: function(xhr) {
        const error = xhr.responseJSON?.error || xhr.responseJSON?.message || 'Failed to deactivate license. Please try again.';
        $result.removeClass('success').addClass('error')
          .html('<strong>' + escapeHtml('Error:') + '</strong> ' + escapeHtml(error))
          .fadeIn();
        $status.text('Failed').removeClass('mt_primelink-status-finished').addClass('mt_primelink-status-idle');
        $btn.prop('disabled', false).text(originalText);
      }
    });
  });

  // Wizard restart handler (works for all PrimeLink pages using event delegation)
  $(document).on('click', '#mt-primelink-restart-wizard', function(e) {
    e.preventDefault();
    
    const $btn = $(this);
    const originalText = $btn.html();
    $btn.prop('disabled', true).html('<span class="dashicons dashicons-update spin"></span> ' + (typeof mtPrimeLink !== 'undefined' && mtPrimeLink.i18n ? mtPrimeLink.i18n.restarting : 'Restarting...'));
    
    if (typeof mtPrimeLink === 'undefined') {
      alert('Error: Plugin scripts not loaded. Please refresh the page.');
      $btn.prop('disabled', false).html(originalText);
      return;
    }
    
    $.ajax({
      url: mtPrimeLink.restUrl + '/wizard/restart',
      method: 'POST',
      headers: {
        'X-WP-Nonce': mtPrimeLink.restNonce
      },
      success: function(response) {
        if (response && response.success) {
          // Redirect to dashboard to show wizard
          const adminUrl = (typeof mtPrimeLink !== 'undefined' && mtPrimeLink.adminUrl) ? mtPrimeLink.adminUrl : window.location.origin + '/wp-admin/';
          const dashboardUrl = adminUrl + 'admin.php?page=mt-primelink';
          window.location.href = dashboardUrl;
        } else {
          alert(response.message || 'Failed to restart wizard.');
          $btn.prop('disabled', false).html(originalText);
        }
      },
      error: function(xhr) {
        const errorMsg = xhr.responseJSON && xhr.responseJSON.message ? xhr.responseJSON.message : 'Failed to restart wizard. Please try again.';
        alert(errorMsg);
        $btn.prop('disabled', false).html(originalText);
      }
    });
  });

  // ============================================
  // Live Feed Management
  // ============================================
  
  if ($('.mt-primelink-live-feed-container').length) {
    const restUrl = (typeof mtPrimeLink !== 'undefined' && mtPrimeLink.restUrl) ? mtPrimeLink.restUrl : '/wp-json/primelink/v1';
    const restNonce = (typeof mtPrimeLink !== 'undefined' && mtPrimeLink.restNonce) ? mtPrimeLink.restNonce : '';

    // REST helper functions
    async function restGet(endpoint) {
      const response = await fetch(restUrl + endpoint, {
        method: 'GET',
        headers: {
          'X-WP-Nonce': restNonce,
          'Content-Type': 'application/json',
        },
      });
      if (!response.ok) {
        const error = await response.json().catch(() => ({ message: 'Request failed' }));
        throw { status: response.status, json: error };
      }
      return await response.json();
    }

    async function restPost(endpoint, data) {
      const response = await fetch(restUrl + endpoint, {
        method: 'POST',
        headers: {
          'X-WP-Nonce': restNonce,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(data),
      });
      if (!response.ok) {
        const error = await response.json().catch(() => ({ message: 'Request failed' }));
        throw { status: response.status, json: error };
      }
      return await response.json();
    }

    async function restPut(endpoint, data) {
      const response = await fetch(restUrl + endpoint, {
        method: 'PUT',
        headers: {
          'X-WP-Nonce': restNonce,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(data),
      });
      if (!response.ok) {
        const error = await response.json().catch(() => ({ message: 'Request failed' }));
        throw { status: response.status, json: error };
      }
      return await response.json();
    }

    async function restDelete(endpoint) {
      const response = await fetch(restUrl + endpoint, {
        method: 'DELETE',
        headers: {
          'X-WP-Nonce': restNonce,
          'Content-Type': 'application/json',
        },
      });
      if (!response.ok) {
        const error = await response.json().catch(() => ({ message: 'Request failed' }));
        throw { status: response.status, json: error };
      }
      return await response.json();
    }

    // Load API Keys
    async function loadApiKeys() {
      try {
        const res = await restGet('/live-feed/api-keys');
        const keys = res.keys || [];
        const $list = $('#mt-primelink-api-keys-list');
        
        if (keys.length === 0) {
          $list.html('<p class="description">' + escapeHtml('No API keys generated yet.') + '</p>');
          return;
        }

        let html = '<table class="wp-list-table widefat fixed striped"><thead><tr><th>Name</th><th>Created</th><th>Last Used</th><th>Status</th><th>Actions</th></tr></thead><tbody>';
        keys.forEach(key => {
          const created = key.created_at ? new Date(key.created_at).toLocaleString() : 'N/A';
          const lastUsed = key.last_used ? new Date(key.last_used).toLocaleString() : 'Never';
          const statusClass = key.status === 'active' ? 'status-active' : 'status-revoked';
          html += '<tr>';
          html += '<td>' + escapeHtml(key.name) + '</td>';
          html += '<td>' + escapeHtml(created) + '</td>';
          html += '<td>' + escapeHtml(lastUsed) + '</td>';
          html += '<td><span class="' + statusClass + '">' + escapeHtml(key.status) + '</span></td>';
          html += '<td><button type="button" class="button button-small mt-primelink-revoke-key" data-key-id="' + escapeHtml(key.key_id) + '">Revoke</button></td>';
          html += '</tr>';
        });
        html += '</tbody></table>';
        $list.html(html);
      } catch (e) {
        $('#mt-primelink-api-keys-list').html('<p class="description" style="color:#dc3545;">Error loading API keys: ' + escapeHtml(e.json?.message || e.message) + '</p>');
      }
    }

    // Load Feeds
    async function loadFeeds() {
      try {
        const res = await restGet('/live-feed/feeds');
        const feeds = res.feeds || [];
        const $list = $('#mt-primelink-feeds-list');
        
        if (feeds.length === 0) {
          $list.html('<p class="description">' + escapeHtml('No feeds configured yet. Click "Add Feed" to create one.') + '</p>');
          return;
        }

        let html = '<table class="wp-list-table widefat fixed striped"><thead><tr><th>Name</th><th>Source URL</th><th>Sync Mode</th><th>Last Sync</th><th>Status</th><th>Actions</th></tr></thead><tbody>';
        feeds.forEach(feed => {
          const lastSync = feed.last_sync ? new Date(feed.last_sync).toLocaleString() : 'Never';
          const statusClass = feed.status === 'active' ? 'status-active' : 'status-inactive';
          const externalUrl = feed.external_sync_url || '';
          html += '<tr>';
          html += '<td><strong>' + escapeHtml(feed.name) + '</strong></td>';
          html += '<td>' + escapeHtml(feed.source_url) + '</td>';
          html += '<td>' + escapeHtml(feed.sync_mode) + '</td>';
          html += '<td>' + escapeHtml(lastSync) + '</td>';
          html += '<td><span class="' + statusClass + '">' + escapeHtml(feed.status) + '</span></td>';
          html += '<td>';
          html += '<button type="button" class="button button-small mt-primelink-sync-feed" data-feed-id="' + escapeHtml(feed.id) + '">Sync Now</button> ';
          html += '<button type="button" class="button button-small mt-primelink-edit-feed" data-feed-id="' + escapeHtml(feed.id) + '">Edit</button> ';
          html += '<button type="button" class="button button-small mt-primelink-delete-feed" data-feed-id="' + escapeHtml(feed.id) + '">Delete</button>';
          if (externalUrl) {
            html += '<div class="description" style="margin-top:4px;font-size:11px;word-break:break-all;">Cron URL: <code>' + escapeHtml(externalUrl) + '</code></div>';
          }
          html += '</td>';
          html += '</tr>';
        });
        html += '</tbody></table>';
        $list.html(html);
      } catch (e) {
        $('#mt-primelink-feeds-list').html('<p class="description" style="color:#dc3545;">Error loading feeds: ' + escapeHtml(e.json?.message || e.message) + '</p>');
      }
    }

    // Modal handlers
    $(document).on('click', '.mt-primelink-modal__close, .mt-primelink-modal__overlay', function() {
      $(this).closest('.mt-primelink-modal').hide();
    });

    // API Key Management
    $('#mt-primelink-create-api-key').on('click', function() {
      $('#mt-primelink-api-key-modal').show();
      $('#mt-primelink-api-key-name').val('');
      $('#mt-primelink-api-key-result').hide();
    });

    $('#mt-primelink-generate-api-key').on('click', async function() {
      const name = $('#mt-primelink-api-key-name').val().trim();
      if (!name) {
        showToast('warning', 'Please enter a key name.', 'API Key');
        return;
      }

      try {
        const res = await restPost('/live-feed/api-keys', { name: name });
        $('#mt-primelink-api-key-result').show();
        $('#mt-primelink-api-key-value').text(res.api_key);
        showToast('success', 'API key generated successfully. Save it now - it won\'t be shown again!', 'API Key');
        loadApiKeys();
      } catch (e) {
        showToast('error', 'Failed to generate API key: ' + (e.json?.message || e.message), 'API Key');
      }
    });

    $(document).on('click', '.mt-primelink-revoke-key', async function() {
      if (!confirm('Are you sure you want to revoke this API key?')) return;
      const keyId = $(this).data('key-id');
      try {
        await restDelete('/live-feed/api-keys/' + keyId);
        showToast('success', 'API key revoked.', 'API Key');
        loadApiKeys();
      } catch (e) {
        showToast('error', 'Failed to revoke API key: ' + (e.json?.message || e.message), 'API Key');
      }
    });

    // Feed Management
    $('#mt-primelink-add-feed').on('click', function() {
      $('#mt-primelink-feed-modal-title').text('Add Live Feed');
      $('#mt-primelink-feed-id').val('');
      $('#mt-primelink-feed-name').val('');
      $('#mt-primelink-feed-source-type').val('prime_woocommerce');
      $('#mt-primelink-feed-source-url').val('');
      $('#mt-primelink-feed-api-key').val('');
      $('#mt-primelink-feed-wc-consumer-key').val('');
      $('#mt-primelink-feed-wc-consumer-secret').val('');
      $('#mt-primelink-feed-sync-mode').val('auto');
      $('#mt-primelink-feed-interval').val('900'); // Default: 15 minutes
      $('#mt-primelink-feed-interval-custom').val('').hide();
      $('#mt-primelink-feed-interval-wrap').show();
      // Reset auth fields visibility
      if (typeof toggleFeedAuthFields === 'function') {
        toggleFeedAuthFields('prime_woocommerce');
      }
      // Default sync fields: all checked
      $('.mt-primelink-sync-field').prop('checked', true);
      $('#mt-primelink-feed-modal').show();
    });

    $(document).on('click', '.mt-primelink-edit-feed', async function() {
      const feedId = $(this).data('feed-id');
      try {
        const feed = await restGet('/live-feed/feeds/' + feedId);
        $('#mt-primelink-feed-modal-title').text('Edit Live Feed');
        $('#mt-primelink-feed-id').val(feed.id);
        $('#mt-primelink-feed-name').val(feed.name);
        $('#mt-primelink-feed-source-type').val(feed.source_type || 'prime_woocommerce');
        $('#mt-primelink-feed-source-url').val(feed.source_url);
        $('#mt-primelink-feed-api-key').val(feed.api_key || '');
        $('#mt-primelink-feed-wc-consumer-key').val(feed.wc_consumer_key || '');
        $('#mt-primelink-feed-wc-consumer-secret').val(feed.wc_consumer_secret || '');
        toggleFeedAuthFields($('#mt-primelink-feed-source-type').val());
        $('#mt-primelink-feed-sync-mode').val(feed.sync_mode);
        // Map interval to preset or custom
        const interval = feed.interval || 900;
        const presetMap = { 300: '300', 900: '900', 1800: '1800', 3600: '3600', 21600: '21600', 86400: '86400' };
        if (presetMap[interval]) {
          $('#mt-primelink-feed-interval').val(presetMap[interval]);
          $('#mt-primelink-feed-interval-custom').hide();
        } else {
          $('#mt-primelink-feed-interval').val('custom');
          $('#mt-primelink-feed-interval-custom').val(interval).show();
        }
        $('#mt-primelink-feed-interval-wrap').toggle(feed.sync_mode === 'auto');
        // Sync fields
        const fields = feed.sync_fields || ['price','stock','description','images','categories','tags'];
        $('.mt-primelink-sync-field').prop('checked', false);
        fields.forEach(f => {
          $('.mt-primelink-sync-field[value="'+f+'"]').prop('checked', true);
        });
        $('#mt-primelink-feed-modal').show();
      } catch (e) {
        showToast('error', 'Failed to load feed: ' + (e.json?.message || e.message), 'Live Feed');
      }
    });

    $('#mt-primelink-feed-sync-mode').on('change', function() {
      $('#mt-primelink-feed-interval-wrap').toggle($(this).val() === 'auto');
    });

    // Handle interval preset vs custom
    $('#mt-primelink-feed-interval').on('change', function() {
      if ($(this).val() === 'custom') {
        $('#mt-primelink-feed-interval-custom').show().focus();
      } else {
        $('#mt-primelink-feed-interval-custom').hide();
      }
    });

    // Toggle API key vs WooCommerce REST keys depending on source type
    function toggleFeedAuthFields(sourceType) {
      if (sourceType === 'woocommerce_rest') {
        $('#mt-primelink-feed-api-key-row').hide();
        $('#mt-primelink-feed-wc-keys-row').show();
      } else {
        $('#mt-primelink-feed-api-key-row').show();
        $('#mt-primelink-feed-wc-keys-row').hide();
      }
    }

    $('#mt-primelink-feed-source-type').on('change', function() {
      toggleFeedAuthFields($(this).val());
    });

    $('#mt-primelink-save-feed').on('click', async function() {
      const feedId = $('#mt-primelink-feed-id').val();
      const sourceType = $('#mt-primelink-feed-source-type').val();
      const data = {
        name: $('#mt-primelink-feed-name').val().trim(),
        source_url: $('#mt-primelink-feed-source-url').val().trim(),
        api_key: $('#mt-primelink-feed-api-key').val().trim(),
        source_type: sourceType,
        wc_consumer_key: $('#mt-primelink-feed-wc-consumer-key').val().trim(),
        wc_consumer_secret: $('#mt-primelink-feed-wc-consumer-secret').val().trim(),
        sync_mode: $('#mt-primelink-feed-sync-mode').val(),
        interval: (function() {
          const preset = $('#mt-primelink-feed-interval').val();
          if (preset === 'custom') {
            const custom = parseInt($('#mt-primelink-feed-interval-custom').val(), 10);
            return isNaN(custom) || custom < 60 ? 300 : custom; // Fallback to 5 min if invalid
          }
          return parseInt(preset, 10);
        })(),
        status: 'active',
        sync_fields: $('.mt-primelink-sync-field:checked').map(function(){ return $(this).val(); }).get(),
      };

      // Basic validation depending on source type
      if (!data.name || !data.source_url) {
        showToast('warning', 'Please fill in at least the Name and Source URL.', 'Live Feed');
        return;
      }

      if (sourceType === 'prime_woocommerce' && !data.api_key) {
        showToast('warning', 'Please enter the PrimeLink API Key from the source store.', 'Live Feed');
        return;
      }

      if (sourceType === 'woocommerce_rest' && (!data.wc_consumer_key || !data.wc_consumer_secret)) {
        showToast('warning', 'Please enter the WooCommerce Consumer key and Consumer secret from the supplier store.', 'Live Feed');
        return;
      }

      try {
        if (feedId) {
          await restPut('/live-feed/feeds/' + feedId, data);
          showToast('success', 'Feed updated successfully.', 'Live Feed');
        } else {
          await restPost('/live-feed/feeds', data);
          showToast('success', 'Feed created successfully.', 'Live Feed');
        }
        $('#mt-primelink-feed-modal').hide();
        loadFeeds();
      } catch (e) {
        showToast('error', 'Failed to save feed: ' + (e.json?.message || e.message), 'Live Feed');
      }
    });

    $(document).on('click', '.mt-primelink-sync-feed', async function() {
      const feedId = $(this).data('feed-id');
      const $btn = $(this);
      $btn.prop('disabled', true).text('Syncing...');
      try {
        const res = await restPost('/live-feed/feeds/' + feedId + '/sync');
        showToast('success', res.message || 'Sync completed.', 'Live Feed');
        loadFeeds();
      } catch (e) {
        showToast('error', 'Sync failed: ' + (e.json?.message || e.message), 'Live Feed');
      } finally {
        $btn.prop('disabled', false).text('Sync Now');
      }
    });

    $(document).on('click', '.mt-primelink-delete-feed', async function() {
      if (!confirm('Are you sure you want to delete this feed?')) return;
      const feedId = $(this).data('feed-id');
      try {
        await restDelete('/live-feed/feeds/' + feedId);
        showToast('success', 'Feed deleted.', 'Live Feed');
        loadFeeds();
      } catch (e) {
        showToast('error', 'Failed to delete feed: ' + (e.json?.message || e.message), 'Live Feed');
      }
    });

    // Initial load
    loadApiKeys();
    loadFeeds();
  }

})(jQuery);