(function($) {
	'use strict';

	$(function() {
		
		// Wizard state object
		var wizardState = {
			currentStep: 1,
			sourceType: 'existing',
			sourcePageId: '',
			sourcePageData: {},
			csvData: [],
			csvHeaders: [],
			hasHeaders: true,
			columnMapping: {},
			overrides: {},
			jsonFieldSettings: {},
			validationErrors: [],
			validationWarnings: []
		};

		// Initialize wizard
		initWizard();

		function initWizard() {
			// Step 1: Source type change
			$('input[name="source_type"]').on('change', function() {
				wizardState.sourceType = $(this).val();
				if (wizardState.sourceType === 'existing') {
					$('#existing_source_row').show();
				} else {
					$('#existing_source_row').hide();
				}
			});

			// Step 1: Source page selection
			$('#source_page_select').on('change', function() {
				var $selected = $(this).find('option:selected');
				wizardState.sourcePageId = $(this).val();
				
				if (!wizardState.sourcePageId || wizardState.sourcePageId === '') {
					// Clear source page data and overrides if no selection
					wizardState.sourcePageData = {};
					delete wizardState.overrides.pageid;
					delete wizardState.overrides.pagename;
					delete wizardState.overrides.type;
					delete wizardState.overrides.from_url;
					delete wizardState.overrides.from_logo;
					delete wizardState.overrides.from_name;
				} else {
					var isCustom = $selected.data('iscustom') === 'yes' || $selected.data('iscustom') === true;
					var iconUrl = $selected.data('icon-url') || '';
					
					wizardState.sourcePageData = {
						id: $selected.val(),
						site_type: $selected.data('sitetype'),
						reviewlistpageid: $selected.data('reviewlistpageid'),
						url: $selected.data('url'),
						title: $selected.data('title'),
						iscustom: isCustom,
						icon_url: iconUrl
					};
					
					// Automatically set override values for Step 3 when source page is selected
					if (wizardState.sourcePageData.reviewlistpageid) {
						wizardState.overrides.pageid = wizardState.sourcePageData.reviewlistpageid;
					}
					if (wizardState.sourcePageData.title) {
						wizardState.overrides.pagename = wizardState.sourcePageData.title;
					}
					if (wizardState.sourcePageData.site_type) {
						wizardState.overrides.type = wizardState.sourcePageData.site_type;
					}
					if (wizardState.sourcePageData.url) {
						wizardState.overrides.from_url = wizardState.sourcePageData.url;
					}
					
					// Handle custom pages differently
					if (isCustom) {
						// Set from_logo from custom source icon_url
						if (iconUrl) {
							wizardState.overrides.from_logo = iconUrl;
						}
						// Set from_name to "Custom" for custom pages
						wizardState.overrides.from_name = 'Custom';
					} else {
						// For non-custom pages, clear from_name override (don't auto-fill)
						delete wizardState.overrides.from_name;
						delete wizardState.overrides.from_logo;
					}
				}
			});

			// Step 2: CSV file upload
			$('#csv_file_input').on('change', handleCSVUpload);
			$('#csv_has_headers').on('change', function() {
				wizardState.hasHeaders = $(this).is(':checked');
				if (wizardState.csvData.length > 0) {
					showCSVPreview();
				}
			});

			// Navigation buttons
			$('#wizard_btn_next').on('click', handleNext);
			$('#wizard_btn_back').on('click', handleBack);
			$('#wizard_btn_import').on('click', handleImport);
		}

		function handleNext() {
			// Validate current step
			if (!validateStep(wizardState.currentStep)) {
				return;
			}

			// Move to next step
			if (wizardState.currentStep < 5) {
				goToStep(wizardState.currentStep + 1);
			}
		}

		function handleBack() {
			if (wizardState.currentStep > 1) {
				goToStep(wizardState.currentStep - 1);
			}
		}

		function validateStep(step) {
			switch(step) {
				case 1:
					if (wizardState.sourceType === 'existing' && !wizardState.sourcePageId) {
						alert(wprevpro_import_vars.strings.select_source);
						return false;
					}
					return true;

				case 2:
					if (wizardState.csvData.length === 0) {
						alert(wprevpro_import_vars.strings.select_file);
						return false;
					}
					return true;

				case 3:
					// Validate required fields are mapped or overridden
					var requiredFields = ['reviewer_name', 'review_text', 'rating'];
					for (var i = 0; i < requiredFields.length; i++) {
						var field = requiredFields[i];
						var mapping = wizardState.columnMapping[field];
						var override = wizardState.overrides[field];
						
						// Field must have either a column mapping OR an override
						var hasMappingOrOverride = (mapping !== undefined && mapping !== null && mapping !== '') || 
													(override !== undefined && override !== null && override !== '');
						
						if (!hasMappingOrOverride) {
							alert('Please map or override the required field: ' + field);
							return false;
						}
					}
					return true;

				case 4:
					// Process and validate special fields
					processSpecialFields();
					return true;

				default:
					return true;
			}
		}

		function goToStep(stepNumber) {
			// Update state
			wizardState.currentStep = stepNumber;

			// Update progress indicators
			$('.wizard_step').removeClass('active completed');
			$('.wizard_step').each(function() {
				var $step = $(this);
				var stepNum = parseInt($step.data('step'));
				if (stepNum < stepNumber) {
					$step.addClass('completed');
				} else if (stepNum === stepNumber) {
					$step.addClass('active');
				}
			});

			// Show/hide content
			$('.wizard_step_content').hide();
			$('#step_' + stepNumber).show();

			// Update navigation buttons
			if (stepNumber === 1) {
				$('#wizard_btn_back').hide();
			} else {
				$('#wizard_btn_back').show();
			}

			if (stepNumber === 5) {
				$('#wizard_btn_next').hide();
				$('#wizard_btn_import').show();
			} else {
				$('#wizard_btn_next').show();
				$('#wizard_btn_import').hide();
			}

			// Prepare step content
			prepareStepContent(stepNumber);
		}

		function prepareStepContent(stepNumber) {
			switch(stepNumber) {
				case 3:
					buildColumnMapping();
					break;
				case 4:
					buildSpecialFieldsUI();
					break;
				case 5:
					buildPreviewAndValidate();
					break;
			}
		}

		// ===== CSV PARSING =====

		function handleCSVUpload(e) {
			var file = e.target.files[0];
			if (!file) return;

			if (!file.name.toLowerCase().endsWith('.csv')) {
				alert('Please select a CSV file.');
				$(this).val('');
				return;
			}

			showLoading(wprevpro_import_vars.strings.parsing_file);

			var reader = new FileReader();
			reader.onload = function(ev) {
				try {
					var csvText = ev.target.result;
					var rows = parseCSV(csvText);
					
					if (rows.length === 0) {
						alert('No data found in CSV file.');
						hideLoading();
						return;
					}

					wizardState.csvData = rows;
					wizardState.csvHeaders = wizardState.hasHeaders ? rows[0] : [];
					
					// Validate that all rows have the same number of columns
					if (wizardState.hasHeaders && rows.length > 0) {
						var expectedCols = rows[0].length;
						var problematicRows = [];
						for (var r = 1; r < rows.length; r++) {
							if (rows[r].length !== expectedCols) {
								problematicRows.push({
									row: r + 1,
									expected: expectedCols,
									actual: rows[r].length
								});
							}
						}
						
						if (problematicRows.length > 0) {
							console.warn('CSV parsing warning: Some rows have different column counts:', problematicRows);
							// Try to pad rows with fewer columns
							for (var i = 0; i < problematicRows.length; i++) {
								var pr = problematicRows[i];
								var rowIndex = pr.row - 1;
								while (rows[rowIndex].length < expectedCols) {
									rows[rowIndex].push('');
								}
							}
						}
						
						// Debug: Log first few rows to check parsing
						console.log('CSV parsing debug - First row (headers):', rows[0]);
						if (rows.length > 1) console.log('CSV parsing debug - Second row:', rows[1]);
						if (rows.length > 5) console.log('CSV parsing debug - Row 5:', rows[5]);
						if (rows.length > 10) console.log('CSV parsing debug - Row 10:', rows[10]);
					}
					
					showCSVPreview();
					hideLoading();
					
				} catch(err) {
					console.error('CSV parsing error:', err);
					alert('Error parsing CSV file. Please check the format.');
					hideLoading();
				}
			};
			reader.onerror = function() {
				alert('Error reading file.');
				hideLoading();
			};
			reader.readAsText(file);
		}

		function parseCSV(text) {
			var rows = [];
			var currentRow = [];
			var currentField = '';
			var inQuotes = false;
			var i = 0;

			// Process character by character to handle multi-line quoted fields
			while (i < text.length) {
				var char = text[i];
				var nextChar = i + 1 < text.length ? text[i + 1] : '';

				if (char === '"') {
					if (inQuotes && nextChar === '"') {
						// Escaped quote ("")
						currentField += '"';
						i += 2;
						continue;
					} else if (inQuotes && (nextChar === ',' || nextChar === '\r' || nextChar === '\n' || i + 1 === text.length)) {
						// End of quoted field - close quotes, the comma/newline will be handled next iteration
						inQuotes = false;
						i++;
						continue;
					} else if (!inQuotes) {
						// Start of quoted field - don't add quote to field
						inQuotes = true;
						i++;
						continue;
					} else {
						// Quote inside quoted field (part of content, rare but possible)
						currentField += char;
						i++;
						continue;
					}
				}

				if (!inQuotes) {
					if (char === ',') {
						// End of field
						currentRow.push(currentField.trim());
						currentField = '';
						i++;
						continue;
					} else if (char === '\r' && nextChar === '\n') {
						// Windows line ending
						currentRow.push(currentField.trim());
						if (currentRow.length > 0 && currentRow.some(function(f) { return f.length > 0; })) {
							rows.push(currentRow);
						}
						currentRow = [];
						currentField = '';
						i += 2;
						continue;
					} else if (char === '\n' || char === '\r') {
						// Unix/Mac line ending
						currentRow.push(currentField.trim());
						if (currentRow.length > 0 && currentRow.some(function(f) { return f.length > 0; })) {
							rows.push(currentRow);
						}
						currentRow = [];
						currentField = '';
						i++;
						continue;
					}
				}

				// Add character to current field (including newlines inside quoted fields)
				currentField += char;
				i++;
			}

			// Add last field and row if exists
			if (currentField.trim() || currentRow.length > 0) {
				currentRow.push(currentField.trim());
				if (currentRow.length > 0 && currentRow.some(function(f) { return f.length > 0; })) {
					rows.push(currentRow);
				}
			}

			// Normalize all rows to have the same number of columns
			if (rows.length > 0) {
				// Find maximum column count
				var maxCols = 0;
				for (var r = 0; r < rows.length; r++) {
					if (rows[r].length > maxCols) {
						maxCols = rows[r].length;
					}
				}
				
				// Pad all rows to have the same number of columns
				for (var r = 0; r < rows.length; r++) {
					while (rows[r].length < maxCols) {
						rows[r].push('');
					}
				}
			}

			return rows;
		}

		function showCSVPreview() {
			var startRow = wizardState.hasHeaders ? 1 : 0;
			var endRow = Math.min(startRow + 3, wizardState.csvData.length);
			
			var html = '<table class="widefat" style="font-size:12px;">';
			
			// Headers
			html += '<thead><tr>';
			if (wizardState.hasHeaders && wizardState.csvHeaders.length > 0) {
				for (var i = 0; i < wizardState.csvHeaders.length; i++) {
					html += '<th>' + escapeHtml(wizardState.csvHeaders[i]) + '</th>';
				}
			} else {
				for (var i = 0; i < wizardState.csvData[0].length; i++) {
					html += '<th>Column ' + (i + 1) + '</th>';
				}
			}
			html += '</tr></thead>';
			
			// Data rows
			html += '<tbody>';
			for (var r = startRow; r < endRow; r++) {
				html += '<tr>';
				for (var c = 0; c < wizardState.csvData[r].length; c++) {
					var cellValue = (wizardState.csvData[r][c] || '').substring(0, 50);
					if ((wizardState.csvData[r][c] || '').length > 50) cellValue += '...';
					html += '<td>' + escapeHtml(cellValue) + '</td>';
				}
				html += '</tr>';
			}
			html += '</tbody></table>';
			
			$('#csv_preview_table').html(html);
			$('#csv_preview_section').show();
		}

		// ===== COLUMN MAPPING =====

		function buildColumnMapping() {
			showLoading(wprevpro_import_vars.strings.mapping_columns);

			// Define all fields
			var fields = getFieldDefinitions();
			
			// Sort fields: required fields first, then optional
			fields.sort(function(a, b) {
				if (a.required && !b.required) return -1;
				if (!a.required && b.required) return 1;
				return 0;
			});
			
			// Track which columns have been mapped to prevent conflicts
			var mappedColumns = {};
			
			var html = '<table class="widefat">';
			html += '<thead><tr>';
			html += '<th style="width:20%;">Review Field</th>';
			html += '<th style="width:30%;">CSV Column / Override</th>';
			html += '<th style="width:20%;">Override Value</th>';
			html += '<th style="width:30%;">Preview</th>';
			html += '</tr></thead><tbody>';

			for (var i = 0; i < fields.length; i++) {
				var field = fields[i];
				var hasOverride = wizardState.overrides[field.name] !== undefined && wizardState.overrides[field.name] !== '';
				var overrideValue = hasOverride ? wizardState.overrides[field.name] : '';
				
				html += '<tr>';
				html += '<td>';
				html += '<strong>' + field.label + '</strong>';
				if (field.required) {
					html += ' <span class="field_required">*</span>';
				}
				if (field.description) {
					html += '<br><small class="description">' + field.description + '</small>';
				}
				html += '</td>';
				html += '<td>';
				html += '<select class="column_map_select" data-field="' + field.name + '">';
				html += '<option value="">' + wprevpro_import_vars.strings.skip_field + '</option>';
				
				// Find best matching column for this field (skip already-mapped columns and if field has override)
				var bestMatchIndex = -1;
				if (!hasOverride) {
					bestMatchIndex = findBestColumnMatch(field.name, mappedColumns);
				}
				
				// Add column options
				for (var c = 0; c < wizardState.csvHeaders.length; c++) {
					var columnLabel = wizardState.csvHeaders[c] || ('Column ' + (c + 1));
					var selected = '';
					
					// Select if this is the best match (and no override)
					if (!hasOverride && bestMatchIndex === c) {
						selected = ' selected';
						wizardState.columnMapping[field.name] = c;
						mappedColumns[c] = field.name; // Mark this column as taken
					}
					
					html += '<option value="' + c + '"' + selected + '>' + escapeHtml(columnLabel) + '</option>';
				}
				
				// Add Override option
				var overrideSelected = hasOverride ? ' selected' : '';
				html += '<option value="override"' + overrideSelected + '>-- Override Value --</option>';
				
				html += '</select>';
				html += '</td>';
				html += '<td>';
				html += '<input type="text" class="override_value_input" data-field="' + field.name + '" placeholder="Enter override value" value="' + escapeHtml(overrideValue) + '" style="width:100%;' + (hasOverride ? '' : ' display:none;') + '">';
				html += '</td>';
				html += '<td><span class="field_preview" data-field="' + field.name + '"></span></td>';
				html += '</tr>';
			}

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

			$('#column_mapping_container').html(html);

			// Update preview on change
			$('.column_map_select').on('change', function() {
				var field = $(this).data('field');
				var colIndex = $(this).val();
				var $overrideInput = $('.override_value_input[data-field="' + field + '"]');
				
				if (colIndex === 'override') {
					// Show override input
					$overrideInput.show();
					delete wizardState.columnMapping[field];
					
					// Set override value if input has value
					var overrideValue = $overrideInput.val();
					if (overrideValue) {
						wizardState.overrides[field] = overrideValue;
					}
					updateColumnPreview(field);
				} else {
					// Hide override input and clear override
					$overrideInput.hide();
					delete wizardState.overrides[field];
					
					if (colIndex === '') {
						delete wizardState.columnMapping[field];
					} else {
						wizardState.columnMapping[field] = parseInt(colIndex);
					}
					updateColumnPreview(field);
				}
			});

			// Handle override input changes
			$('.override_value_input').on('input', function() {
				var field = $(this).data('field');
				var value = $(this).val();
				wizardState.overrides[field] = value;
				updateColumnPreview(field);
			});

			// Initial preview update
			updateAllColumnPreviews();

			hideLoading();
		}

		function getFieldDefinitions() {
			var sourceType = wizardState.sourceType === 'submitted' ? 'submitted' : (wizardState.sourcePageData.site_type || '');
			
			var fields = [
				{name: 'pageid', label: 'Page ID', description: 'Source page identifier (auto-filled if not provided)'},
				{name: 'pagename', label: 'Page Name', description: 'Source page name (auto-filled if not provided)'},
				{name: 'type', label: 'Review Source Type', description: 'Type of review source (auto-filled if not provided)'},
				{name: 'reviewer_name', label: 'Reviewer Name', required: true},
				{name: 'review_text', label: 'Review Text', required: true},
				{name: 'rating', label: 'Rating (1-5)', required: true, description: 'Must be a number between 1 and 5'},
				{name: 'created_time', label: 'Review Date', description: 'Format: YYYY-MM-DD or MM/DD/YYYY'},
				{name: 'review_title', label: 'Review Title'},
				{name: 'reviewer_email', label: 'Reviewer Email'},
				{name: 'reviewer_id', label: 'Reviewer ID', description: 'External reviewer ID from source'},
				{name: 'userpic', label: 'Avatar URL', description: 'Full URL to reviewer avatar image'},
				{name: 'userpiclocal', label: 'Local Avatar Path', description: 'Local file path for cached avatar'},
				{name: 'from_name', label: 'From Name', description: 'Source name for display (auto-filled if not provided)'},
				{name: 'from_logo', label: 'From Logo URL', description: 'Source logo URL (auto-filled if not provided)'},
				{name: 'from_url_review', label: 'Direct Review URL', description: 'Direct link to the review'},
				{name: 'location', label: 'Location', description: 'Reviewer location'},
				{name: 'language_code', label: 'Language Code', description: 'e.g., en, es, fr'},
				{name: 'verified_order', label: 'Verified Order', description: 'Verified purchase indicator'},
				{name: 'recommendation_type', label: 'Recommendation Type', description: 'Type of recommendation'},
				{name: 'unique_id', label: 'Unique ID', description: 'Unique identifier from source'},
				{name: 'company_name', label: 'Company Name'},
				{name: 'company_title', label: 'Company Title'},
				{name: 'company_url', label: 'Company URL'},
				{name: 'categories', label: 'Categories', description: 'Comma-separated IDs: 1,2,3 (will be converted to JSON)'},
				{name: 'posts', label: 'Post IDs', description: 'Comma-separated IDs: 18,221 (will be converted to JSON)'},
				{name: 'tags', label: 'Tags', description: 'Comma-separated tags or JSON array'},
				{name: 'sort_weight', label: 'Sort Weight', description: 'Numeric value for custom sorting'},
				{name: 'hide', label: 'Hide Review', description: 'Set to "yes" to hide the review'},
				{name: 'hidestars', label: 'Hide Stars', description: 'Set to "yes" to hide star rating'},
				{name: 'consent', label: 'Consent', description: 'Consent status'},
				{name: 'mediaurlsarrayjson', label: 'Media URLs', description: 'Comma-separated URLs or JSON array'},
				{name: 'mediathumburlsarrayjson', label: 'Media Thumbnail URLs', description: 'Comma-separated URLs or JSON array'},
				{name: 'owner_response', label: 'Owner Response', description: 'JSON object with name, date, comment'}
			];

			// Show from_url only for submitted reviews
			if (sourceType === 'submitted') {
				fields.splice(3, 0, {name: 'from_url', label: 'Review Source URL', description: 'URL of the review page'});
			}

			return fields;
		}

		function autoDetectColumn(fieldName, columnName) {
			var field = fieldName.toLowerCase();
			var column = columnName.toLowerCase();

			// Direct exact matches (highest priority)
			if (column === field) {
				return { score: 100, match: 'exact' };
			}

			// Common variations
			var variations = {
				'pageid': ['pageid', 'page_id', 'source_id'],
				'pagename': ['pagename', 'page_name', 'source_name'],
				'type': ['type', 'source_type', 'source'],
				'reviewer_name': ['name', 'reviewer', 'author', 'customer', 'user'],
				'review_text': ['text', 'review', 'comment', 'message', 'content', 'description'],
				'rating': ['rating', 'stars', 'score'],
				'created_time': ['date', 'time', 'created', 'posted', 'review_date'],
				'review_title': ['title', 'subject', 'headline'],
				'reviewer_email': ['email', 'e-mail', 'mail'],
				'reviewer_id': ['reviewer_id', 'reviewerid', 'user_id', 'userid'],
				'userpic': ['avatar', 'photo', 'picture', 'image', 'pic'],
				'userpiclocal': ['userpiclocal', 'local_avatar', 'cached_avatar'],
				'from_name': ['from_name', 'source_name', 'platform'],
				'from_logo': ['from_logo', 'source_logo', 'logo', 'icon'],
				'from_url_review': ['from_url_review', 'review_url', 'reviewurl', 'fromurlreview'],
				'location': ['location', 'city', 'place', 'address'],
				'verified_order': ['verified', 'verified_purchase', 'verified_order'],
				'recommendation_type': ['recommendation', 'rec_type', 'recommendation_type'],
				'unique_id': ['unique_id', 'uniqueid', 'id', 'external_id'],
				'categories': ['categories', 'category', 'cats', 'cat'],
				'posts': ['posts', 'post', 'postid', 'post_id'],
				'tags': ['tags', 'tag', 'labels'],
				'company_name': ['company', 'business', 'organization'],
				'owner_response': ['response', 'reply', 'owner_reply'],
				'hide': ['hide', 'hidden', 'visible'],
				'hidestars': ['hidestars', 'hide_stars', 'hide_rating'],
				'consent': ['consent', 'permission', 'approved']
			};

			if (variations[field]) {
				for (var i = 0; i < variations[field].length; i++) {
					var variation = variations[field][i];
					
					// Exact match with variation (high priority)
					if (column === variation) {
						return { score: 90 - i, match: 'exact_variation' };
					}
					
					// Starts with variation (medium-high priority)
					if (column.indexOf(variation + '_') === 0 || column.indexOf(variation + ' ') === 0) {
						return { score: 70 - i, match: 'prefix_match' };
					}
					
					// Ends with variation (medium priority)
					if (column.endsWith('_' + variation) || column.endsWith(' ' + variation) || column.endsWith(variation)) {
						return { score: 60 - i, match: 'suffix_match' };
					}
					
					// Contains variation (lower priority, but only if it's a longer word)
					// Avoid matching single words like "url" that are too generic
					if (variation.length >= 4 && column.indexOf(variation) !== -1) {
						return { score: 50 - i, match: 'contains_match' };
					}
					
					// For shorter variations (3 chars or less), require exact word match
					if (variation.length < 4) {
						var regex = new RegExp('\\b' + variation + '\\b', 'i');
						if (regex.test(column)) {
							return { score: 55 - i, match: 'word_match' };
						}
					}
				}
			}

			return null;
		}

		function findBestColumnMatch(fieldName, mappedColumns) {
			mappedColumns = mappedColumns || {};
			var bestMatch = null;
			var bestScore = 0;
			var bestIndex = -1;

			for (var c = 0; c < wizardState.csvHeaders.length; c++) {
				// Skip if this column is already mapped to another field
				if (mappedColumns[c]) {
					continue;
				}
				
				var columnLabel = wizardState.csvHeaders[c] || ('Column ' + (c + 1));
				var matchResult = autoDetectColumn(fieldName, columnLabel);
				
				if (matchResult && matchResult.score > bestScore) {
					bestScore = matchResult.score;
					bestMatch = matchResult;
					bestIndex = c;
				}
			}

			return bestIndex;
		}

		function updateColumnPreview(field) {
			var $preview = $('.field_preview[data-field="' + field + '"]');
			
			// Check if this field has an override
			if (wizardState.overrides[field] !== undefined && wizardState.overrides[field] !== '') {
				var overrideValue = wizardState.overrides[field];
				var displayValue = overrideValue.substring(0, 30);
				if (overrideValue.length > 30) displayValue += '...';
				$preview.html('<strong>[Override]</strong> ' + escapeHtml(displayValue || '(empty)'));
				return;
			}
			
			var colIndex = wizardState.columnMapping[field];
			
			if (colIndex === undefined || colIndex === null || colIndex === '') {
				$preview.text('(skipped)');
				return;
			}

			var startRow = wizardState.hasHeaders ? 1 : 0;
			if (wizardState.csvData.length <= startRow) {
				$preview.text('(no data)');
				return;
			}

			var value = wizardState.csvData[startRow][colIndex] || '';
			var displayValue = value.substring(0, 30);
			if (value.length > 30) displayValue += '...';
			
			$preview.text(displayValue || '(empty)');
		}

		function updateAllColumnPreviews() {
			// Update previews for mapped columns
			for (var field in wizardState.columnMapping) {
				updateColumnPreview(field);
			}
			// Update previews for overrides
			for (var field in wizardState.overrides) {
				updateColumnPreview(field);
			}
		}

		// ===== SPECIAL FIELDS =====

		function buildSpecialFieldsUI() {
			var html = '<h3>JSON Field Settings</h3>';
			html += '<p class="description">Review your JSON field mappings. The wizard will automatically convert comma-separated values to the proper JSON format.</p>';
			
			html += '<table class="form-table">';
			
			// Show which JSON fields are mapped
			var jsonFields = ['categories', 'posts', 'tags', 'mediaurlsarrayjson', 'mediathumburlsarrayjson', 'owner_response'];
			var hasJsonFields = false;
			
			for (var i = 0; i < jsonFields.length; i++) {
				var field = jsonFields[i];
				if (wizardState.columnMapping[field] !== undefined || wizardState.overrides[field] !== undefined) {
					hasJsonFields = true;
					html += '<tr>';
					html += '<th scope="row" style="width:25%;">' + field + '</th>';
					html += '<td>';
					
					if (wizardState.overrides[field] !== undefined) {
						html += '<span class="description">Using override value: <strong>' + escapeHtml(wizardState.overrides[field]) + '</strong></span>';
					} else {
						var colIndex = wizardState.columnMapping[field];
						var columnLabel = wizardState.csvHeaders[colIndex] || ('Column ' + (colIndex + 1));
						html += '<span class="description">Mapped to CSV column: <strong>' + escapeHtml(columnLabel) + '</strong></span>';
					}
					
					html += '<br><small>';
					if (field === 'categories' || field === 'posts') {
						html += 'Comma-separated IDs will be converted to JSON format: ["-1-","-2-","-3-"]';
					} else if (field === 'tags') {
						html += 'Comma-separated tags will be converted to JSON array';
					} else if (field === 'mediaurlsarrayjson' || field === 'mediathumburlsarrayjson') {
						html += 'Comma-separated URLs will be converted to JSON array';
					} else if (field === 'owner_response') {
						html += 'Will be processed as JSON object with name, date, and comment';
					}
					html += '</small>';
					html += '</td>';
					html += '</tr>';
				}
			}
			
			if (!hasJsonFields) {
				html += '<tr><td colspan="2"><em>No JSON fields are currently mapped.</em></td></tr>';
			}

			html += '</table>';
			
			html += '<p class="description" style="margin-top:20px; padding:12px; background:#f0f0f0; border-left:4px solid #2271b1;">';
			html += '<strong>Note:</strong> You can go back to Step 3 if you need to adjust any field mappings or overrides.';
			html += '</p>';

			$('#special_fields_container').html(html);
		}

		function processSpecialFields() {
			// This function processes JSON fields and validates them
			// Will be called before moving to step 5
		}

		// ===== PREVIEW & VALIDATE =====

		function buildPreviewAndValidate() {
			showLoading(wprevpro_import_vars.strings.validating);

			wizardState.validationErrors = [];
			wizardState.validationWarnings = [];

			var startRow = wizardState.hasHeaders ? 1 : 0;
			var previewRows = [];
			var allProcessedRows = [];
			var totalRows = wizardState.csvData.length - startRow;
			var errorCount = 0;
			var warningCount = 0;

			// Process all data first
			for (var r = startRow; r < wizardState.csvData.length; r++) {
				var row = wizardState.csvData[r];
				var processedRow = processRow(row, r);
				
				if (processedRow.errors.length > 0) {
					errorCount++;
				}
				if (processedRow.warnings.length > 0) {
					warningCount++;
				}

				allProcessedRows.push(processedRow);
				
				// Keep first 10 for preview
				if (previewRows.length < 10) {
					previewRows.push(processedRow);
				}
			}

			// Check for duplicates within CSV
			checkForDuplicatesInCSV(allProcessedRows);
			
			// Check for duplicates against existing database reviews
			checkForDuplicatesInDatabase(allProcessedRows);

			// Recount warnings after duplicate checks (since they add warnings to rows)
			warningCount = 0;
			for (var i = 0; i < allProcessedRows.length; i++) {
				if (allProcessedRows[i].warnings.length > 0) {
					warningCount++;
				}
			}

			// Display summary
			var summaryHtml = '<h3>Import Summary</h3>';
			summaryHtml += '<p><strong>Total rows to import:</strong> ' + totalRows + '</p>';
			summaryHtml += '<p><strong>Rows with errors (will be skipped):</strong> ' + errorCount + '</p>';
			summaryHtml += '<p><strong>Rows with warnings (will import):</strong> ' + warningCount + '</p>';
			$('#import_summary').html(summaryHtml);

			// Display errors and warnings
			var messagesHtml = '';
			
			if (wizardState.validationWarnings.length > 0) {
				messagesHtml += '<div class="warning_message"><strong>Warnings:</strong><ul>';
				for (var i = 0; i < Math.min(10, wizardState.validationWarnings.length); i++) {
					messagesHtml += '<li>' + escapeHtml(wizardState.validationWarnings[i]) + '</li>';
				}
				if (wizardState.validationWarnings.length > 10) {
					messagesHtml += '<li>... and ' + (wizardState.validationWarnings.length - 10) + ' more warnings</li>';
				}
				messagesHtml += '</ul></div>';
			}
			
			if (wizardState.validationErrors.length > 0) {
				messagesHtml += '<div class="error_message"><strong>Validation Errors:</strong><ul>';
				for (var i = 0; i < Math.min(10, wizardState.validationErrors.length); i++) {
					messagesHtml += '<li>' + escapeHtml(wizardState.validationErrors[i]) + '</li>';
				}
				if (wizardState.validationErrors.length > 10) {
					messagesHtml += '<li>... and ' + (wizardState.validationErrors.length - 10) + ' more errors</li>';
				}
				messagesHtml += '</ul></div>';

				// Disable import button if critical errors
				if (errorCount === totalRows) {
					$('#wizard_btn_import').prop('disabled', true);
					messagesHtml += '<p class="error_message">All rows have errors. Please fix the data and try again.</p>';
				}
			}
			
			if (!messagesHtml) {
				messagesHtml = '<div class="success_message"><strong>No validation errors or warnings found!</strong> Ready to import.</div>';
			}
			
			$('#validation_errors').html(messagesHtml);
			$('#wizard_btn_import').prop('disabled', false);

			// Display preview table
			displayPreviewTable(previewRows);

			hideLoading();
		}

		function processRow(row, rowIndex) {
			var processed = {
				data: {},
				errors: [],
				warnings: [],
				rowNumber: rowIndex + 1
			};

			// Map columns to fields
			for (var field in wizardState.columnMapping) {
				var colIndex = wizardState.columnMapping[field];
				
				// Ensure colIndex is a valid number
				if (colIndex === null || colIndex === undefined || colIndex === '') {
					continue;
				}
				
				colIndex = parseInt(colIndex);
				if (isNaN(colIndex) || colIndex < 0 || colIndex >= row.length) {
					continue;
				}
				
				var value = row[colIndex];
				if (value === undefined || value === null) {
					value = '';
				}
				value = String(value).trim();

				// Apply overrides
				if (wizardState.overrides[field] !== undefined && wizardState.overrides[field] !== '') {
					value = wizardState.overrides[field];
				}

				processed.data[field] = value;
			}

			// Validate required fields
			if (!processed.data.reviewer_name || processed.data.reviewer_name.trim() === '') {
				processed.errors.push('Row ' + processed.rowNumber + ': Reviewer name is required');
				wizardState.validationErrors.push('Row ' + processed.rowNumber + ': Reviewer name is required');
			}

			if (!processed.data.review_text || processed.data.review_text.trim() === '') {
				processed.errors.push('Row ' + processed.rowNumber + ': Review text is required');
				wizardState.validationErrors.push('Row ' + processed.rowNumber + ': Review text is required');
			}

			// Validate rating
			var rating = parseInt(processed.data.rating);
			if (isNaN(rating) || rating < 1 || rating > 5) {
				processed.errors.push('Row ' + processed.rowNumber + ': Rating must be between 1 and 5');
				wizardState.validationErrors.push('Row ' + processed.rowNumber + ': Rating must be between 1 and 5');
			} else {
				processed.data.rating = rating;
			}

			// Process date
			if (processed.data.created_time) {
				var parsedDate = parseDate(processed.data.created_time);
				if (parsedDate) {
					processed.data.created_time = parsedDate;
				} else {
					processed.warnings.push('Row ' + processed.rowNumber + ': Invalid date format, will use current date');
					processed.data.created_time = getCurrentDate();
				}
			} else {
				processed.data.created_time = getCurrentDate();
			}

			// Process JSON fields
			if (processed.data.categories) {
				processed.data.categories = convertToJSONArray(processed.data.categories, 'categories');
			}

			if (processed.data.posts) {
				processed.data.posts = convertToJSONArray(processed.data.posts, 'posts');
			}

			if (processed.data.tags) {
				processed.data.tags = convertToJSONArray(processed.data.tags, 'tags');
			}

			if (processed.data.mediaurlsarrayjson) {
				processed.data.mediaurlsarrayjson = convertToJSONArray(processed.data.mediaurlsarrayjson, 'media');
			}

			if (processed.data.mediathumburlsarrayjson) {
				processed.data.mediathumburlsarrayjson = convertToJSONArray(processed.data.mediathumburlsarrayjson, 'media');
			}

			if (processed.data.owner_response) {
				processed.data.owner_response = processOwnerResponse(processed.data.owner_response);
			}

			return processed;
		}

		function displayPreviewTable(rows) {
			var html = '<table class="widefat" style="font-size:12px;">';
			html += '<thead><tr>';
			html += '<th>Row</th>';
			html += '<th>Status</th>';
			html += '<th>Reviewer</th>';
			html += '<th>Rating</th>';
			html += '<th>Date</th>';
			html += '<th>Review Text (Preview)</th>';
			html += '</tr></thead><tbody>';

			for (var i = 0; i < rows.length; i++) {
				var row = rows[i];
				var statusClass = row.errors.length > 0 ? 'error' : (row.warnings.length > 0 ? 'warning' : 'success');
				var statusText = row.errors.length > 0 ? 'Error' : (row.warnings.length > 0 ? 'Warning' : 'OK');
				
				html += '<tr style="background:' + (statusClass === 'error' ? '#fef5f5' : (statusClass === 'warning' ? '#fffbf0' : '#f0f6f0')) + ';">';
				html += '<td>' + row.rowNumber + '</td>';
				html += '<td><strong>' + statusText + '</strong>';
				if (row.errors.length > 0 || row.warnings.length > 0) {
					html += '<br><small>';
					if (row.errors.length > 0) html += row.errors[0];
					else html += row.warnings[0];
					html += '</small>';
				}
				html += '</td>';
				html += '<td>' + escapeHtml(row.data.reviewer_name || '') + '</td>';
				html += '<td>' + (row.data.rating || 'N/A') + '</td>';
				html += '<td>' + (row.data.created_time || '') + '</td>';
				html += '<td>' + escapeHtml((row.data.review_text || '').substring(0, 100)) + (row.data.review_text && row.data.review_text.length > 100 ? '...' : '') + '</td>';
				html += '</tr>';
			}

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

		function checkForDuplicatesInCSV(allProcessedRows) {
			// Check for duplicates within the CSV file itself
			var seen = {};
			var duplicateCount = 0;

			for (var i = 0; i < allProcessedRows.length; i++) {
				var row = allProcessedRows[i];
				var name = (row.data.reviewer_name || '').trim().toLowerCase();
				var text = (row.data.review_text || '').trim().toLowerCase();
				var date = (row.data.created_time || '').trim();
				
				// Create a unique key for duplicate detection
				var key = name + '|' + date + '|' + text;
				
				if (seen[key]) {
					duplicateCount++;
					wizardState.validationWarnings.push('Row ' + row.rowNumber + ': Duplicate review found in CSV (matches Row ' + seen[key] + ')');
					row.warnings.push('Duplicate within CSV (matches Row ' + seen[key] + ')');
				} else {
					seen[key] = row.rowNumber;
				}
			}

			if (duplicateCount > 0) {
				wizardState.validationWarnings.push('Found ' + duplicateCount + ' duplicate(s) within the CSV file');
			}
		}

		function checkForDuplicatesInDatabase(allProcessedRows) {
			// Build array of reviews to check
			var reviewsToCheck = [];
			for (var i = 0; i < allProcessedRows.length; i++) {
				var row = allProcessedRows[i];
				reviewsToCheck.push({
					reviewer_name: (row.data.reviewer_name || '').trim(),
					review_text: (row.data.review_text || '').trim(),
					created_time: (row.data.created_time || '').trim(),
					type: wizardState.sourcePageData.site_type || 'submitted',
					rowNumber: row.rowNumber
				});
			}

			// Make AJAX call to check for duplicates
			$.ajax({
				url: wprevpro_import_vars.ajax_url,
				type: 'POST',
				async: false, // Make synchronous to ensure we have results before displaying
				data: {
					action: 'wprevpro_check_duplicate_reviews',
					nonce: wprevpro_import_vars.nonce,
					reviews: reviewsToCheck
				},
				success: function(response) {
					if (response.success && response.data.duplicates) {
						var duplicates = response.data.duplicates;
						if (duplicates.length > 0) {
							wizardState.validationWarnings.push('Found ' + duplicates.length + ' potential duplicate(s) in the database');
							
							for (var i = 0; i < duplicates.length; i++) {
								var dup = duplicates[i];
								wizardState.validationWarnings.push('Row ' + dup.rowNumber + ': Potential duplicate found in database (Review ID: ' + dup.existing_id + ')');
								
								// Add warning to the specific row
								for (var j = 0; j < allProcessedRows.length; j++) {
									if (allProcessedRows[j].rowNumber === dup.rowNumber) {
										allProcessedRows[j].warnings.push('Potential duplicate in database (ID: ' + dup.existing_id + ')');
										break;
									}
								}
							}
						}
					}
				},
				error: function() {
					console.error('Failed to check for duplicates in database');
				}
			});
		}

		// ===== IMPORT =====

		function handleImport() {
			if (!confirm('Are you sure you want to import these reviews? This action cannot be undone.')) {
				return;
			}

			showLoading(wprevpro_import_vars.strings.importing);
			$('#wizard_btn_import').prop('disabled', true);

			// Prepare data for import
			var importData = {
				action: 'wprevpro_import_reviews_wizard',
				nonce: wprevpro_import_vars.nonce,
				source_type: wizardState.sourceType,
				source_data: wizardState.sourcePageData,
				column_mapping: wizardState.columnMapping,
				overrides: wizardState.overrides,
				csv_data: wizardState.csvData,
				has_headers: wizardState.hasHeaders
			};

			$.post(wprevpro_import_vars.ajax_url, importData, function(response) {
				hideLoading();
				
				if (response.success) {
					var message = response.data.message || wprevpro_import_vars.strings.import_complete;
					message += '\n\nImported: ' + (response.data.imported || 0) + ' reviews';
					if (response.data.skipped > 0) {
						message += '\nSkipped: ' + response.data.skipped + ' rows (due to errors)';
					}
					
					alert(message);
					
					// Redirect to reviews page
					window.location.href = response.data.redirect_url || wprevpro_import_vars.ajax_url.replace('admin-ajax.php', 'admin.php?page=wp_pro-reviews');
				} else {
					alert(response.data || wprevpro_import_vars.strings.import_error);
					$('#wizard_btn_import').prop('disabled', false);
				}
			}).fail(function() {
				hideLoading();
				alert(wprevpro_import_vars.strings.import_error);
				$('#wizard_btn_import').prop('disabled', false);
			});
		}

		// ===== HELPER FUNCTIONS =====

		function isValidJSON(str) {
			try {
				JSON.parse(str);
				return true;
			} catch (e) {
				return false;
			}
		}

		function convertToJSONArray(value, fieldType) {
			if (!value || value.trim() === '') {
				return '';
			}

			// Remove surrounding quotes if present (e.g., "[\"-12-\",\"-56-\"]" -> [\"-12-\",\"-56-\"])
			var cleaned = value.trim();
			if ((cleaned.charAt(0) === '"' && cleaned.charAt(cleaned.length - 1) === '"') || 
			    (cleaned.charAt(0) === "'" && cleaned.charAt(cleaned.length - 1) === "'")) {
				cleaned = cleaned.substring(1, cleaned.length - 1);
			}

			// First, try to unescape escaped quotes (common in CSV exports)
			// Replace \" with " to handle escaped quotes
			var unescaped = cleaned.replace(/\\"/g, '"');
			
			// Try to parse as JSON
			if (isValidJSON(unescaped)) {
				// Valid JSON - parse and re-stringify to ensure proper format
				try {
					var parsed = JSON.parse(unescaped);
					return JSON.stringify(parsed);
				} catch (e) {
					// If re-stringify fails, return the unescaped value
					return unescaped;
				}
			}

			// Also try the original cleaned value in case it's already valid
			if (isValidJSON(cleaned)) {
				try {
					var parsed = JSON.parse(cleaned);
					return JSON.stringify(parsed);
				} catch (e) {
					return cleaned;
				}
			}

			// Convert comma-separated to JSON array
			if (fieldType === 'categories' || fieldType === 'posts') {
				// Format: ["-1-","-2-","-3-"]
				var items = unescaped.split(',').map(function(item) {
					return '"-' + item.trim().replace(/^["']|["']$/g, '') + '-"';
				});
				return '[' + items.join(',') + ']';
			} else if (fieldType === 'tags') {
				// Format: ["tag1","tag2","tag3"]
				var items = unescaped.split(',').map(function(item) {
					return '"' + item.trim().replace(/^["']|["']$/g, '') + '"';
				});
				return '[' + items.join(',') + ']';
			} else if (fieldType === 'media') {
				// Format: ["url1","url2","url3"]
				var items = unescaped.split(',').map(function(item) {
					return '"' + item.trim().replace(/^["']|["']$/g, '') + '"';
				});
				return '[' + items.join(',') + ']';
			}

			return unescaped;
		}

		function processOwnerResponse(value) {
			if (!value || value.trim() === '') {
				return '';
			}

			// First, try to unescape escaped quotes (common in CSV exports)
			var unescaped = value.replace(/\\"/g, '"');

			// If already valid JSON, use it
			if (isValidJSON(unescaped)) {
				try {
					var parsed = JSON.parse(unescaped);
					return JSON.stringify(parsed);
				} catch (e) {
					return unescaped;
				}
			}

			// Also try the original value
			if (isValidJSON(value)) {
				try {
					var parsed = JSON.parse(value);
					return JSON.stringify(parsed);
				} catch (e) {
					return value;
				}
			}

			// Try to parse as plain text and create JSON
			return '{"id":"","name":"Owner","comment":"' + unescaped.replace(/"/g, '\\"') + '","date":"' + getCurrentDate() + '"}';
		}

		function parseDate(dateString) {
			// Try multiple date formats
			var date = null;
			
			// YYYY-MM-DD
			if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
				return dateString;
			}
			
			// MM/DD/YYYY or M/D/YYYY
			var match = dateString.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
			if (match) {
				var month = ('0' + match[1]).slice(-2);
				var day = ('0' + match[2]).slice(-2);
				return match[3] + '-' + month + '-' + day;
			}

			// Try JavaScript Date parser
			date = new Date(dateString);
			if (!isNaN(date.getTime())) {
				var year = date.getFullYear();
				var month = ('0' + (date.getMonth() + 1)).slice(-2);
				var day = ('0' + date.getDate()).slice(-2);
				return year + '-' + month + '-' + day;
			}

			return null;
		}

		function getCurrentDate() {
			var now = new Date();
			var year = now.getFullYear();
			var month = ('0' + (now.getMonth() + 1)).slice(-2);
			var day = ('0' + now.getDate()).slice(-2);
			return year + '-' + month + '-' + day;
		}

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

		function showLoading(text) {
			$('#wizard_loading_text').text(text || 'Processing...');
			$('#wizard_loading').show();
			$('#wizard_btn_next, #wizard_btn_back, #wizard_btn_import').prop('disabled', true);
		}

		function hideLoading() {
			$('#wizard_loading').hide();
			$('#wizard_btn_next, #wizard_btn_back, #wizard_btn_import').prop('disabled', false);
		}

	});

})(jQuery);

