(function($) {
	'use strict';

	var depsStore = {
		escapeHtml: function(value) {
			if (value === null || value === undefined) return '';
			var div = document.createElement('div');
			div.textContent = String(value);
			return div.innerHTML;
		},
		generateRandomFieldId: function() {
			return 'field_' + (10000000 + Math.floor(Math.random() * 90000000));
		},
		fieldTypeIcons: {},
		fieldLabels: {
			text: 'Text',
			textarea: 'Textarea',
			select: 'Select',
			checkbox: 'Checkbox',
			radio: 'Radio',
			number: 'Number',
			email: 'Email',
			url: 'URL',
			color: 'Color',
			image: 'Image',
			file: 'File',
			wysiwyg: 'WYSIWYG',
			date: 'Date',
			message: 'Message',
			group: 'Section',
			toggle: 'Toggle',
			link: 'Link',
			gallery: 'Gallery',
			repeater: 'Repeater'
		},
		widthLabels: {
			full: 'Full',
			'2-3': '2/3',
			'1-2': '1/2',
			'1-3': '1/3'
		},
		defaultPlaceholders: {},
		getDefaultInputHtml: null,
		parseOptionsToArray: null,
		config: {},
		autoSave: function() {},
		currentPageId: function() { return null; }
	};

	function setDeps(nextDeps) {
		nextDeps = nextDeps || {};
		depsStore.escapeHtml = nextDeps.escapeHtml || depsStore.escapeHtml;
		depsStore.generateRandomFieldId = nextDeps.generateRandomFieldId || depsStore.generateRandomFieldId;
		depsStore.fieldTypeIcons = $.extend({}, depsStore.fieldTypeIcons, nextDeps.fieldTypeIcons || {});
		depsStore.fieldLabels = $.extend({}, depsStore.fieldLabels, nextDeps.fieldLabels || {}, {
			file: 'File',
			message: 'Message'
		});
		depsStore.widthLabels = $.extend({}, depsStore.widthLabels, nextDeps.widthLabels || {});
		depsStore.defaultPlaceholders = nextDeps.defaultPlaceholders || depsStore.defaultPlaceholders;
		depsStore.getDefaultInputHtml = nextDeps.getDefaultInputHtml || depsStore.getDefaultInputHtml;
		depsStore.parseOptionsToArray = nextDeps.parseOptionsToArray || depsStore.parseOptionsToArray;
		depsStore.config = nextDeps.config || depsStore.config;
		depsStore.autoSave = nextDeps.autoSave || depsStore.autoSave;
		if (typeof nextDeps.currentPageId === 'function') {
			depsStore.currentPageId = nextDeps.currentPageId;
		}
	}

	function escapeHtml(value) {
		return depsStore.escapeHtml(value);
	}

	function getFieldTypeIconHtml(type) {
		var icons = depsStore.fieldTypeIcons || {};
		var path = icons[type] || icons.text || 'M4 6h16M4 12h16m-7 6h7';
		return '<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="' + path + '"></path></svg>';
	}

	function generateRandomFieldId() {
		return depsStore.generateRandomFieldId();
	}

	function parseOptionsToArray(value) {
		if (typeof depsStore.parseOptionsToArray === 'function') {
			return depsStore.parseOptionsToArray(value);
		}
		var out = [];
		var lines = String(value || '').split('\n');
		for (var i = 0; i < lines.length; i++) {
			var line = $.trim(lines[i]);
			if (!line) continue;
			var label = line;
			var optionValue = line;
			if (line.indexOf('|') >= 0) {
				var partsPipe = line.split('|', 2);
				optionValue = $.trim(partsPipe[0]);
				label = $.trim(partsPipe[1] || partsPipe[0]);
			} else if (line.indexOf(':') >= 0) {
				var partsColon = line.split(':', 2);
				optionValue = $.trim(partsColon[0]);
				label = $.trim(partsColon[1] || partsColon[0]);
			}
			out.push({ value: optionValue, label: label });
		}
		return out;
	}

	function getDefaultInputHtml(type, defaultValue, placeholder) {
		if (typeof depsStore.getDefaultInputHtml === 'function') {
			return depsStore.getDefaultInputHtml(type, defaultValue, placeholder);
		}
		return '<input type="text" class="opb-field-default wpps-opb-input" value="' + escapeHtml(defaultValue || '') + '" placeholder="' + escapeHtml(placeholder || '') + '">';
	}

	function isTextLikeType(type) {
		return ['text', 'textarea', 'number', 'email', 'url', 'color', 'image', 'file', 'wysiwyg', 'date'].indexOf(type) >= 0;
	}

	function isCurrentPageAvailable() {
		return !!depsStore.currentPageId();
	}

	function triggerAutoSaveIfNeeded() {
		if (isCurrentPageAvailable()) {
			depsStore.autoSave();
		}
	}

	function getTypeSwitcherHtml(currentType) {
		var types = ['text', 'textarea', 'select', 'checkbox', 'radio', 'number', 'email', 'url', 'color', 'image', 'file', 'gallery', 'wysiwyg', 'date', 'message', 'toggle', 'link', 'repeater', 'group'];
		var optionsHtml = types.map(function(type) {
			return '<option value="' + escapeHtml(type) + '"' + (type === currentType ? ' selected' : '') + '>' + escapeHtml(depsStore.fieldLabels[type] || type) + '</option>';
		}).join('');
		return '<div class="wpps-opb-field-row wpps-opb-field-row-full">' +
			'<div class="form-field">' +
			'<label>Field Type</label>' +
			'<select class="opb-field-type-change wpps-opb-select">' + optionsHtml + '</select>' +
			'</div>' +
			'</div>';
	}

	function getLayoutOptionsHtml(selectedLayout, className) {
		selectedLayout = selectedLayout || 'stacked';
		className = className || 'opb-field-radio-layout';
		return '<select class="' + escapeHtml(className) + ' wpps-opb-select">' +
			'<option value="stacked"' + (selectedLayout === 'stacked' ? ' selected' : '') + '>Stacked</option>' +
			'<option value="inline"' + (selectedLayout === 'inline' ? ' selected' : '') + '>Inline</option>' +
			'<option value="buttons"' + (selectedLayout === 'buttons' ? ' selected' : '') + '>Buttons</option>' +
			'<option value="columns-2"' + (selectedLayout === 'columns-2' ? ' selected' : '') + '>2 Columns</option>' +
			'<option value="columns-3"' + (selectedLayout === 'columns-3' ? ' selected' : '') + '>3 Columns</option>' +
			'</select>';
	}

	function getConditionalRowHtml(fieldData, isGroup) {
		if (isGroup) {
			return '';
		}
		var conditionalOperator = fieldData.conditional_operator || 'equals';
		var operators = [
			{ value: 'equals', label: 'Equals' },
			{ value: 'not_equals', label: 'Not Equals' },
			{ value: 'empty', label: 'Empty' },
			{ value: 'not_empty', label: 'Not Empty' },
			{ value: 'contains', label: 'Contains' }
		];
		var operatorOptions = operators.map(function(op) {
			return '<option value="' + escapeHtml(op.value) + '"' + (op.value === conditionalOperator ? ' selected' : '') + '>' + escapeHtml(op.label) + '</option>';
		}).join('');

		return '<div class="wpps-opb-field-row wpps-opb-field-row-3col">' +
			'<div class="form-field">' +
			'<label>Conditional Field</label>' +
			'<select class="opb-field-conditional-field wpps-opb-select" data-selected="' + escapeHtml(fieldData.conditional_field || '') + '">' +
			'<option value="">None</option>' +
			'</select>' +
			'</div>' +
			'<div class="form-field">' +
			'<label>Operator</label>' +
			'<select class="opb-field-conditional-operator wpps-opb-select">' + operatorOptions + '</select>' +
			'</div>' +
			'<div class="form-field opb-field-conditional-value-cell">' +
			'<label>Conditional Value</label>' +
			'<div class="opb-field-conditional-value-wrap" data-selected="' + escapeHtml(fieldData.conditional_value || '') + '"></div>' +
			'</div>' +
			'</div>';
	}

	function getTextLikeOptionsHtml(fieldData, type) {
		if (!isTextLikeType(type)) {
			return '';
		}
		return '<div class="wpps-opb-field-row wpps-opb-field-row-2col">' +
			'<div class="form-field">' +
			'<label>Placeholder</label>' +
			'<input type="text" class="opb-field-placeholder wpps-opb-input" value="' + escapeHtml(fieldData.placeholder || '') + '" placeholder="' + escapeHtml((depsStore.defaultPlaceholders && depsStore.defaultPlaceholders[type]) || '') + '">' +
			'</div>' +
			'<div class="form-field">' +
			'<label>CSS Class</label>' +
			'<input type="text" class="opb-field-css-class wpps-opb-input" value="' + escapeHtml(fieldData.css_class || '') + '" placeholder="custom-css-class">' +
			'</div>' +
			'</div>' +
			'<div class="wpps-opb-field-row wpps-opb-field-row-2col">' +
			'<div class="form-field">' +
			'<label>Max Length</label>' +
			'<input type="number" class="opb-field-maxlength wpps-opb-input" value="' + escapeHtml(fieldData.maxlength || '') + '" min="1" placeholder="Optional">' +
			'</div>' +
			'<div class="form-field form-field-required">' +
			'<label>Read only</label>' +
			'<label><input type="checkbox" class="opb-field-readonly" ' + (fieldData.readonly ? 'checked' : '') + '> Read only</label>' +
			'</div>' +
			'</div>';
	}

	function getTypeOptionsHtml(fieldData, type) {
		var optionsArray = parseOptionsToArray(fieldData.options || '');
		var optionsRowsHtml = '';
		if (['select', 'radio'].indexOf(type) >= 0) {
			optionsRowsHtml = optionsArray.map(function(option, index) {
				return '<div class="wpps-opb-option-row" data-idx="' + index + '">' +
					'<input type="text" class="opb-opt-value wpps-opb-input" placeholder="Value" value="' + escapeHtml(option.value) + '">' +
					'<input type="text" class="opb-opt-label wpps-opb-input" placeholder="Label" value="' + escapeHtml(option.label) + '">' +
					'<button type="button" class="opb-opt-set-default button button-small" title="Set as default">' + (String(fieldData.default || '') === String(option.value) ? '✓ Default' : 'Set default') + '</button>' +
					'<button type="button" class="opb-opt-remove button button-small" title="Remove">×</button>' +
					'</div>';
			}).join('');
		}

		if (type === 'number') {
			return '<div class="wpps-opb-field-row wpps-opb-field-row-3col">' +
				'<div class="form-field"><label>Min</label><input type="number" class="opb-field-min wpps-opb-input" value="' + escapeHtml(fieldData.min || '') + '"></div>' +
				'<div class="form-field"><label>Max</label><input type="number" class="opb-field-max wpps-opb-input" value="' + escapeHtml(fieldData.max || '') + '"></div>' +
				'<div class="form-field"><label>Step</label><input type="number" class="opb-field-step wpps-opb-input" value="' + escapeHtml(fieldData.step || '') + '" step="any"></div>' +
				'</div>' +
				'<div class="wpps-opb-field-row wpps-opb-field-row-2col">' +
				'<div class="form-field"><label>Prefix</label><input type="text" class="opb-field-prefix wpps-opb-input" value="' + escapeHtml(fieldData.prefix || '') + '" placeholder="$"></div>' +
				'<div class="form-field"><label>Suffix</label><input type="text" class="opb-field-suffix wpps-opb-input" value="' + escapeHtml(fieldData.suffix || '') + '" placeholder="kg"></div>' +
				'</div>';
		}

		if (type === 'checkbox') {
			return '<div class="wpps-opb-field-row wpps-opb-field-row-full">' +
				'<div class="form-field">' +
				'<label>Checkbox Label</label>' +
				'<input type="text" class="opb-field-checkbox-label wpps-opb-input" value="' + escapeHtml(fieldData.checkbox_label || '') + '" placeholder="e.g. Enable feature">' +
				'</div>' +
				'</div>';
		}

		if (type === 'select') {
			return '<div class="wpps-opb-field-row wpps-opb-field-row-full wpps-opb-options-editor">' +
				'<div class="form-field">' +
				'<label>Options</label>' +
				'<div class="wpps-opb-options-list">' + optionsRowsHtml + '</div>' +
				'<button type="button" class="opb-opt-add button button-secondary">+ Add option</button>' +
				'<textarea class="opb-field-options wpps-opb-input" style="display:none;">' + escapeHtml(fieldData.options || '') + '</textarea>' +
				'</div>' +
				'</div>' +
				'<div class="wpps-opb-field-row wpps-opb-field-row-3col">' +
				'<div class="form-field form-field-required"><label>Allow Empty</label><label><input type="checkbox" class="opb-field-allow-empty" ' + (fieldData.allow_empty ? 'checked' : '') + '> Allow empty option</label></div>' +
				'<div class="form-field form-field-required"><label>Multiple</label><label><input type="checkbox" class="opb-field-multiple" ' + (fieldData.multiple ? 'checked' : '') + '> Allow multiple</label></div>' +
				'<div class="form-field"><label>Layout</label>' + getLayoutOptionsHtml(fieldData.select_layout || fieldData.radio_layout || 'stacked', 'opb-field-select-layout') + '<p class="description">Button and column layouts apply to single-select only.</p></div>' +
				'</div>';
		}

		if (type === 'radio') {
			return '<div class="wpps-opb-field-row wpps-opb-field-row-full wpps-opb-options-editor">' +
				'<div class="form-field">' +
				'<label>Options</label>' +
				'<div class="wpps-opb-options-list">' + optionsRowsHtml + '</div>' +
				'<button type="button" class="opb-opt-add button button-secondary">+ Add option</button>' +
				'<textarea class="opb-field-options wpps-opb-input" style="display:none;">' + escapeHtml(fieldData.options || '') + '</textarea>' +
				'</div>' +
				'</div>' +
				'<div class="wpps-opb-field-row wpps-opb-field-row-2col">' +
				'<div class="form-field form-field-required"><label>Allow None</label><label><input type="checkbox" class="opb-field-allow-none" ' + (fieldData.allow_none ? 'checked' : '') + '> Show no selection option</label></div>' +
				'<div class="form-field"><label>Layout</label>' + getLayoutOptionsHtml(fieldData.radio_layout || 'stacked', 'opb-field-radio-layout') + '</div>' +
				'</div>';
		}

		if (type === 'wysiwyg') {
			return '<div class="wpps-opb-field-row wpps-opb-field-row-3col">' +
				'<div class="form-field"><label>Rows</label><input type="number" class="opb-field-rows wpps-opb-input" value="' + escapeHtml(fieldData.rows || '') + '" min="2" max="50" placeholder="12"></div>' +
				'<div class="form-field form-field-required"><label>Media Buttons</label><label><input type="checkbox" class="opb-field-media-buttons" ' + (fieldData.media_buttons === false ? '' : 'checked') + '> Show media buttons</label></div>' +
				'<div class="form-field form-field-required"><label>Teeny</label><label><input type="checkbox" class="opb-field-teeny" ' + (fieldData.teeny ? 'checked' : '') + '> Use teeny editor</label></div>' +
				'</div>';
		}

		if (type === 'image' || type === 'file') {
			var returnFormat = fieldData.return_format || 'id';
			var previewSize = fieldData.preview_size || 'thumbnail';
			return '<div class="wpps-opb-field-row wpps-opb-field-row-3col">' +
				'<div class="form-field"><label>Return Format</label><select class="opb-field-return-format wpps-opb-select"><option value="id"' + (returnFormat === 'id' ? ' selected' : '') + '>ID</option><option value="url"' + (returnFormat === 'url' ? ' selected' : '') + '>URL</option></select></div>' +
				'<div class="form-field"><label>Preview Size</label><select class="opb-field-preview-size wpps-opb-select"><option value="thumbnail"' + (previewSize === 'thumbnail' ? ' selected' : '') + '>Thumbnail</option><option value="medium"' + (previewSize === 'medium' ? ' selected' : '') + '>Medium</option><option value="large"' + (previewSize === 'large' ? ' selected' : '') + '>Large</option><option value="full"' + (previewSize === 'full' ? ' selected' : '') + '>Full</option></select></div>' +
				'<div class="form-field form-field-required"><label>Multiple</label><label><input type="checkbox" class="opb-field-multiple" ' + (fieldData.multiple ? 'checked' : '') + '> Allow multiple</label></div>' +
				'</div>';
		}

		if (type === 'date') {
			var dateType = fieldData.date_type || 'date';
			return '<div class="wpps-opb-field-row wpps-opb-field-row-3col">' +
				'<div class="form-field"><label>Date Type</label><select class="opb-field-date-type wpps-opb-select"><option value="date"' + (dateType === 'date' ? ' selected' : '') + '>Date</option><option value="time"' + (dateType === 'time' ? ' selected' : '') + '>Time</option><option value="datetime-local"' + (dateType === 'datetime-local' ? ' selected' : '') + '>Date Time</option></select></div>' +
				'<div class="form-field"><label>Min</label><input type="text" class="opb-field-min-date wpps-opb-input" value="' + escapeHtml(fieldData.min_date || '') + '" placeholder="YYYY-MM-DD"></div>' +
				'<div class="form-field"><label>Max</label><input type="text" class="opb-field-max-date wpps-opb-input" value="' + escapeHtml(fieldData.max_date || '') + '" placeholder="YYYY-MM-DD"></div>' +
				'</div>';
		}

		if (type === 'color') {
			return '<div class="wpps-opb-field-row wpps-opb-field-row-full">' +
				'<div class="form-field">' +
				'<label>Color Palette</label>' +
				'<textarea class="opb-field-color-palette wpps-opb-input" rows="2" placeholder="#ff0000,#00ff00,#0000ff">' + escapeHtml(fieldData.color_palette || '') + '</textarea>' +
				'</div>' +
				'</div>';
		}

		if (type === 'toggle') {
			return '<div class="wpps-opb-field-row wpps-opb-field-row-full"><p class="description">Renders as an on/off switch. Stores <code>1</code> or empty.</p></div>';
		}

		if (type === 'link') {
			return '<div class="wpps-opb-field-row wpps-opb-field-row-full"><p class="description">Stores URL, link text, and optional new-tab target.</p></div>';
		}

		if (type === 'gallery') {
			var galleryPreview = fieldData.preview_size || 'thumbnail';
			return '<div class="wpps-opb-field-row wpps-opb-field-row-full">' +
				'<div class="form-field"><label>Preview Size</label><select class="opb-field-preview-size wpps-opb-select">' +
				'<option value="thumbnail"' + (galleryPreview === 'thumbnail' ? ' selected' : '') + '>Thumbnail</option>' +
				'<option value="medium"' + (galleryPreview === 'medium' ? ' selected' : '') + '>Medium</option>' +
				'<option value="large"' + (galleryPreview === 'large' ? ' selected' : '') + '>Large</option>' +
				'</select></div></div>';
		}

		if (type === 'repeater') {
			var subFields = fieldData.sub_fields || [];
			var subTypes = ['text', 'textarea', 'url', 'email', 'number', 'image', 'select', 'checkbox', 'toggle'];
			var subRowsHtml = subFields.map(function(sub, index) {
				var subName = sub.name || '';
				var subLabel = sub.label || '';
				var subType = sub.type || 'text';
				var typeOptions = subTypes.map(function(st) {
					return '<option value="' + escapeHtml(st) + '"' + (st === subType ? ' selected' : '') + '>' + escapeHtml(depsStore.fieldLabels[st] || st) + '</option>';
				}).join('');
				return '<div class="wpps-opb-subfield-row" data-idx="' + index + '">' +
					'<input type="text" class="opb-sub-name wpps-opb-input" placeholder="name" value="' + escapeHtml(subName) + '">' +
					'<input type="text" class="opb-sub-label wpps-opb-input" placeholder="Label" value="' + escapeHtml(subLabel) + '">' +
					'<select class="opb-sub-type wpps-opb-select">' + typeOptions + '</select>' +
					'<button type="button" class="opb-sub-remove button button-small" title="Remove">×</button>' +
					'</div>';
			}).join('');
			return '<div class="wpps-opb-field-row wpps-opb-field-row-full">' +
				'<div class="form-field"><label>Sub-fields</label>' +
				'<div class="wpps-opb-subfields-editor">' + subRowsHtml + '</div>' +
				'<button type="button" class="opb-sub-add button button-secondary">+ Add sub-field</button>' +
				'<textarea class="opb-field-sub-fields wpps-opb-input" style="display:none;">' + escapeHtml(JSON.stringify(subFields)) + '</textarea>' +
				'</div></div>' +
				'<div class="wpps-opb-field-row wpps-opb-field-row-3col">' +
				'<div class="form-field"><label>Min Rows</label><input type="number" class="opb-field-min wpps-opb-input" value="' + escapeHtml(fieldData.min || '') + '" min="0"></div>' +
				'<div class="form-field"><label>Max Rows</label><input type="number" class="opb-field-max wpps-opb-input" value="' + escapeHtml(fieldData.max || '') + '" min="0" placeholder="Unlimited"></div>' +
				'<div class="form-field"><label>Add Row Label</label><input type="text" class="opb-field-button-label wpps-opb-input" value="' + escapeHtml(fieldData.button_label || '') + '" placeholder="Add Row"></div>' +
				'</div>';
		}

		if (type === 'message') {
			return '<div class="wpps-opb-field-row wpps-opb-field-row-full">' +
				'<div class="form-field">' +
				'<label>Message Content</label>' +
				'<textarea class="opb-field-message-content wpps-opb-input" rows="6" placeholder="Content to display">' + escapeHtml(fieldData.message_content || '') + '</textarea>' +
				'</div>' +
				'</div>' +
				'<div class="wpps-opb-field-row wpps-opb-field-row-full">' +
				'<div class="form-field">' +
				'<label>CSS Class</label>' +
				'<input type="text" class="opb-field-css-class wpps-opb-input" value="' + escapeHtml(fieldData.css_class || '') + '" placeholder="custom-css-class">' +
				'</div>' +
				'</div>';
		}

		if (type === 'textarea') {
			return '<div class="wpps-opb-field-row wpps-opb-field-row-full"><div class="form-field"><label>Rows</label><input type="number" class="opb-field-rows wpps-opb-input" value="' + escapeHtml(fieldData.rows || '') + '" min="2" max="50" placeholder="5"></div></div>';
		}

		return '';
	}

	function getMetaRowHtml(fieldData, type) {
		var isGroup = type === 'group';
		var isMessage = type === 'message';
		if (isGroup || isMessage || type === 'repeater') {
			return type === 'repeater'
				? '<div class="wpps-opb-field-row wpps-opb-field-row-full"><div class="form-field form-field-required"><label>Options</label><label><input type="checkbox" class="opb-field-required" ' + (fieldData.required ? 'checked' : '') + '> Required field</label></div></div>'
				: '';
		}
		var width = fieldData.width || 'full';
		var required = !!fieldData.required;
		var defaultValue = fieldData.default || '';
		var placeholder = (depsStore.defaultPlaceholders && depsStore.defaultPlaceholders[type]) || 'Pre-filled when no value saved';
		var optionsArray = parseOptionsToArray(fieldData.options || '');
		var defaultInputHtml = '';

		if (['select', 'radio'].indexOf(type) >= 0) {
			var optionsHtml = '<option value="">— None —</option>' + optionsArray.map(function(option) {
				return '<option value="' + escapeHtml(option.value) + '"' + (String(defaultValue) === String(option.value) ? ' selected' : '') + '>' + escapeHtml(option.label || option.value) + '</option>';
			}).join('');
			defaultInputHtml = '<select class="opb-field-default wpps-opb-select opb-field-default-select">' + optionsHtml + '</select>';
		} else {
			defaultInputHtml = getDefaultInputHtml(type, defaultValue, placeholder);
		}

		return '<div class="wpps-opb-field-row wpps-opb-field-row-3col">' +
			'<div class="form-field"><label>Default Value</label>' + defaultInputHtml + '</div>' +
			'<div class="form-field"><label>Width</label><select class="opb-field-width wpps-opb-select">' +
			'<option value="full"' + (width === 'full' ? ' selected' : '') + '>Full Width</option>' +
			'<option value="2-3"' + (width === '2-3' ? ' selected' : '') + '>2/3</option>' +
			'<option value="1-2"' + (width === '1-2' ? ' selected' : '') + '>1/2</option>' +
			'<option value="1-3"' + (width === '1-3' ? ' selected' : '') + '>1/3</option>' +
			'</select></div>' +
			'<div class="form-field form-field-required"><label>Options</label><label><input type="checkbox" class="opb-field-required" ' + (required ? 'checked' : '') + '> Required field</label></div>' +
			'</div>';
	}

	function getFieldHtml(fieldData) {
		fieldData = fieldData || {};
		var type = fieldData.type || 'text';
		var isGroup = type === 'group';
		var id = fieldData.field_id || fieldData.id || generateRandomFieldId();
		var label = fieldData.label || (isGroup ? 'New Section' : (depsStore.fieldLabels[type] || 'Field'));
		var description = fieldData.description || '';
		var typeLabel = isGroup ? 'Section' : (depsStore.fieldLabels[type] || type);
		var width = fieldData.width || 'full';
		var widthBadge = (!isGroup && type !== 'message' && width !== 'full') ? '<span class="wpps-opb-field-width-badge">' + escapeHtml(depsStore.widthLabels[width] || width) + '</span>' : '';

		var bodyHtml = getTypeSwitcherHtml(type) +
			'<div class="wpps-opb-field-row wpps-opb-field-row-2col">' +
			'<div class="form-field"><label>Field Label <span class="required">*</span></label><input type="text" class="opb-field-label wpps-opb-input" value="' + escapeHtml(label) + '" placeholder="e.g. Text Field"></div>' +
			'<div class="form-field"><label>Field ID <span class="required">*</span></label><input type="text" class="opb-field-id wpps-opb-input" value="' + escapeHtml(id) + '" placeholder="e.g. field_name"><span class="wpps-opb-help">Use lowercase letters, numbers, and underscores only</span></div>' +
			'</div>';

		if (type !== 'message') {
			bodyHtml += '<div class="wpps-opb-field-row wpps-opb-field-row-full"><div class="form-field"><label>Description</label><textarea class="opb-field-desc wpps-opb-input" rows="2">' + escapeHtml(description) + '</textarea></div></div>';
		}

		bodyHtml += getTextLikeOptionsHtml(fieldData, type);
		bodyHtml += getTypeOptionsHtml(fieldData, type);
		bodyHtml += getConditionalRowHtml(fieldData, isGroup);
		bodyHtml += getMetaRowHtml(fieldData, type);

		return '<div class="wpps-opb-field-item collapsed' + (isGroup ? ' wpps-opb-field-group' : '') + '" data-type="' + escapeHtml(type) + '" data-id="' + escapeHtml(id) + '">' +
			'<div class="wpps-opb-field-header">' +
			'<span class="wpps-opb-field-drag dashicons dashicons-menu"></span>' +
			'<button type="button" class="wpps-opb-field-toggle" aria-label="Toggle"><span class="dashicons dashicons-arrow-down-alt2"></span></button>' +
			'<span class="wpps-opb-field-type-icon" aria-hidden="true">' + getFieldTypeIconHtml(type) + '</span>' +
			'<span class="wpps-opb-field-title">' + escapeHtml(label) + '</span>' +
			'<span class="wpps-opb-field-type">' + escapeHtml(typeLabel) + '</span>' +
			widthBadge +
			'<span class="wpps-opb-field-actions">' +
			'<button type="button" class="opb-field-duplicate" aria-label="Duplicate field" title="Duplicate field"><span class="dashicons dashicons-admin-page" aria-hidden="true"></span></button>' +
			'<button type="button" class="opb-field-delete" aria-label="Delete field" title="Delete field"><span class="dashicons dashicons-trash" aria-hidden="true"></span></button>' +
			'</span>' +
			'</div>' +
			'<div class="wpps-opb-field-body">' + bodyHtml + '</div>' +
			'</div>';
	}

	function collectFieldFromElement($el, index) {
		var type = String($el.data('type') || $el.find('.opb-field-type-change').val() || 'text');
		var row = {
			id: 'field_' + index,
			type: type,
			label: $el.find('.opb-field-label').val() || '',
			field_id: $el.find('.opb-field-id').val() || '',
			description: $el.find('.opb-field-desc').val() || '',
			default: $el.find('.opb-field-default').length ? ($el.find('.opb-field-default').val() || '') : '',
			options: $el.find('.opb-field-options').length ? ($el.find('.opb-field-options').val() || '') : '',
			required: $el.find('.opb-field-required').length ? $el.find('.opb-field-required').is(':checked') : false,
			width: $el.find('.opb-field-width').length ? ($el.find('.opb-field-width').val() || 'full') : 'full',
			order: index
		};

		function assignIfPresent(selector, key, parser) {
			var $field = $el.find(selector);
			if (!$field.length) return;
			if (typeof parser === 'function') {
				row[key] = parser($field);
				return;
			}
			row[key] = $field.val() || '';
		}

		assignIfPresent('.opb-field-placeholder', 'placeholder');
		assignIfPresent('.opb-field-css-class', 'css_class');
		assignIfPresent('.opb-field-maxlength', 'maxlength', function($field) {
			var parsed = parseInt($field.val(), 10);
			return isNaN(parsed) ? '' : parsed;
		});
		assignIfPresent('.opb-field-readonly', 'readonly', function($field) { return $field.is(':checked'); });

		assignIfPresent('.opb-field-conditional-field', 'conditional_field');
		assignIfPresent('.opb-field-conditional-operator', 'conditional_operator');
		assignIfPresent('.opb-field-conditional-value', 'conditional_value');

		assignIfPresent('.opb-field-rows', 'rows', function($field) {
			var parsed = parseInt($field.val(), 10);
			return isNaN(parsed) ? '' : parsed;
		});
		assignIfPresent('.opb-field-min', 'min');
		assignIfPresent('.opb-field-max', 'max');
		assignIfPresent('.opb-field-step', 'step');
		assignIfPresent('.opb-field-prefix', 'prefix');
		assignIfPresent('.opb-field-suffix', 'suffix');

		assignIfPresent('.opb-field-checkbox-label', 'checkbox_label');
		assignIfPresent('.opb-field-radio-layout', 'radio_layout');
		assignIfPresent('.opb-field-select-layout', 'select_layout');
		assignIfPresent('.opb-field-allow-empty', 'allow_empty', function($field) { return $field.is(':checked'); });
		assignIfPresent('.opb-field-allow-none', 'allow_none', function($field) { return $field.is(':checked'); });
		assignIfPresent('.opb-field-multiple', 'multiple', function($field) { return $field.is(':checked'); });

		assignIfPresent('.opb-field-media-buttons', 'media_buttons', function($field) { return $field.is(':checked'); });
		assignIfPresent('.opb-field-teeny', 'teeny', function($field) { return $field.is(':checked'); });

		assignIfPresent('.opb-field-return-format', 'return_format');
		assignIfPresent('.opb-field-preview-size', 'preview_size');

		assignIfPresent('.opb-field-date-type', 'date_type');
		assignIfPresent('.opb-field-min-date', 'min_date');
		assignIfPresent('.opb-field-max-date', 'max_date');
		assignIfPresent('.opb-field-color-palette', 'color_palette');
		assignIfPresent('.opb-field-message-content', 'message_content');
		assignIfPresent('.opb-field-button-label', 'button_label');

		if ($el.find('.opb-field-sub-fields').length) {
			try {
				row.sub_fields = JSON.parse($el.find('.opb-field-sub-fields').val() || '[]');
			} catch (err) {
				row.sub_fields = [];
			}
		}

		return row;
	}

	function collectFields() {
		var collected = [];
		$('#opb-fields-list .wpps-opb-field-item').each(function(index) {
			collected.push(collectFieldFromElement($(this), index));
		});
		return collected;
	}

	function updateFieldHeader($field) {
		var label = $field.find('.opb-field-label').val() || '';
		var type = String($field.data('type') || $field.find('.opb-field-type-change').val() || 'text');
		var width = $field.find('.opb-field-width').val();
		$field.find('.wpps-opb-field-type-icon').html(getFieldTypeIconHtml(type));
		$field.find('.wpps-opb-field-title').text(label);
		$field.find('.wpps-opb-field-type').text(type === 'group' ? 'Section' : (depsStore.fieldLabels[type] || type));
		$field.find('.wpps-opb-field-width-badge').remove();
		if (width && width !== 'full' && type !== 'group' && type !== 'message') {
			$field.find('.wpps-opb-field-type').after('<span class="wpps-opb-field-width-badge">' + escapeHtml(depsStore.widthLabels[width] || width) + '</span>');
		}
	}

	function ensureUniqueCopyFieldId(baseFieldId) {
		var candidate = (baseFieldId || generateRandomFieldId()) + '_copy';
		var suffix = 2;
		while ($('#opb-fields-list .opb-field-id').filter(function() {
			return $(this).val() === candidate;
		}).length) {
			candidate = (baseFieldId || generateRandomFieldId()) + '_copy_' + suffix;
			suffix++;
		}
		return candidate;
	}

	function getFieldItemType($field) {
		return String($field.attr('data-type') || $field.data('type') || $field.find('.opb-field-type-change').val() || '');
	}

	function getFieldItemId($field) {
		var fieldId = String($field.find('.opb-field-id').val() || '').trim();
		return fieldId || String($field.attr('data-id') || '').trim();
	}

	function operatorNeedsConditionalValue(operator) {
		return operator !== 'empty' && operator !== 'not_empty';
	}

	function getDependencyFieldElement(fieldId) {
		var found = null;
		if (!fieldId) return found;
		$('#opb-fields-list .wpps-opb-field-item').each(function() {
			if (getFieldItemId($(this)) === fieldId) {
				found = $(this);
				return false;
			}
		});
		return found;
	}

	function getDependencyFieldOptionsFromRows($depField) {
		var choices = [];
		$depField.find('.wpps-opb-option-row').each(function() {
			var value = String($(this).find('.opb-opt-value').val() || '').trim();
			var label = String($(this).find('.opb-opt-label').val() || '').trim();
			if (value) {
				choices.push({
					value: value,
					label: label || value
				});
			}
		});
		return choices;
	}

	function getDependencyFieldValueChoices($depField) {
		if (!$depField || !$depField.length) return [];
		var type = getFieldItemType($depField);
		if (type === 'checkbox' || type === 'toggle') {
			return [
				{ value: '1', label: 'Checked' },
				{ value: '0', label: 'Unchecked' }
			];
		}
		if (type === 'select' || type === 'radio') {
			var rowChoices = getDependencyFieldOptionsFromRows($depField);
			if (rowChoices.length) {
				return rowChoices;
			}
			var optionsText = $depField.find('.opb-field-options').val() || '';
			return parseOptionsToArray(optionsText).map(function(opt) {
				return {
					value: String(opt.value),
					label: String(opt.label || opt.value)
				};
			});
		}
		var defaultVal = String($depField.find('.opb-field-default-select').val() || $depField.find('.opb-field-default').val() || '').trim();
		if (defaultVal !== '') {
			return [{ value: defaultVal, label: defaultVal }];
		}
		return [];
	}

	function refreshConditionalValueControl($field) {
		var $wrap = $field.find('.opb-field-conditional-value-wrap');
		if (!$wrap.length) return;

		var depId = String($field.find('.opb-field-conditional-field').val() || '').trim();
		var operator = String($field.find('.opb-field-conditional-operator').val() || 'equals');
		var selected = String($field.find('.opb-field-conditional-value').val() || $wrap.attr('data-selected') || '').trim();

		$wrap.empty();

		if (!operatorNeedsConditionalValue(operator)) {
			$wrap.append('<input type="hidden" class="opb-field-conditional-value" value="">');
			$wrap.append('<p class="description opb-field-conditional-value-hint">Not used for this operator.</p>');
			return;
		}

		if (!depId) {
			$wrap.append('<select class="opb-field-conditional-value wpps-opb-select" disabled><option value="">Select a conditional field first</option></select>');
			return;
		}

		var $depField = getDependencyFieldElement(depId);
		var choices = getDependencyFieldValueChoices($depField);
		if (!choices.length) {
			$wrap.append('<input type="text" class="opb-field-conditional-value wpps-opb-input" value="' + escapeHtml(selected) + '" placeholder="Enter value to match">');
			$wrap.append('<p class="description opb-field-conditional-value-hint">No preset values on trigger field. Enter a value manually.</p>');
			return;
		}

		var hasSelected = false;
		var optionsHtml = '<option value="">Select value</option>';
		for (var i = 0; i < choices.length; i++) {
			var isSelected = selected === String(choices[i].value);
			if (isSelected) hasSelected = true;
			optionsHtml += '<option value="' + escapeHtml(choices[i].value) + '"' + (isSelected ? ' selected' : '') + '>' + escapeHtml(choices[i].label) + '</option>';
		}
		$wrap.append('<select class="opb-field-conditional-value wpps-opb-select">' + optionsHtml + '</select>');
		if (selected && !hasSelected) {
			$wrap.find('.opb-field-conditional-value').val('');
		}
	}

	function refreshConditionalValueControls() {
		$('#opb-fields-list .wpps-opb-field-item').each(function() {
			refreshConditionalValueControl($(this));
		});
	}

	function refreshConditionalFieldOptions() {
		var allFields = [];
		$('#opb-fields-list .wpps-opb-field-item').each(function() {
			var $field = $(this);
			allFields.push({
				id: getFieldItemId($field),
				label: String($field.find('.opb-field-label').val() || '').trim(),
				type: getFieldItemType($field)
			});
		});

		$('#opb-fields-list .wpps-opb-field-item').each(function() {
			var $field = $(this);
			var ownId = getFieldItemId($field);
			var $select = $field.find('.opb-field-conditional-field');
			if (!$select.length) return;
			var selected = $select.val() || $select.attr('data-selected') || $select.data('selected') || '';
			var optionsHtml = '<option value="">None</option>';
			for (var i = 0; i < allFields.length; i++) {
				if (!allFields[i].id || allFields[i].id === ownId || allFields[i].type === 'group') continue;
				optionsHtml += '<option value="' + escapeHtml(allFields[i].id) + '"' + (selected === allFields[i].id ? ' selected' : '') + '>' + escapeHtml(allFields[i].label || allFields[i].id) + '</option>';
			}
			$select.html(optionsHtml);
			refreshConditionalValueControl($field);
		});
	}

	function bindDuplicate() {
		$(document).off('click.opbExtrasDuplicate', '.opb-field-duplicate').on('click.opbExtrasDuplicate', '.opb-field-duplicate', function(event) {
			event.preventDefault();
			event.stopPropagation();
			var $field = $(this).closest('.wpps-opb-field-item');
			var index = $field.index();
			var fieldData = collectFieldFromElement($field, index);
			fieldData.field_id = ensureUniqueCopyFieldId(fieldData.field_id);
			fieldData.id = fieldData.field_id;
			fieldData.label = (fieldData.label || 'Field') + ' Copy';

			var html = getFieldHtml(fieldData);
			var $newField = $(html);
			$field.after($newField);
			if ($('#opb-fields-list').sortable('instance')) {
				$('#opb-fields-list').sortable('refresh');
			}
			refreshConditionalFieldOptions();
			triggerAutoSaveIfNeeded();
		});
	}

	function bindTypeSwitcher() {
		$(document).off('change.opbExtrasTypeChange', '.opb-field-type-change').on('change.opbExtrasTypeChange', '.opb-field-type-change', function() {
			var $field = $(this).closest('.wpps-opb-field-item');
			var nextType = String($(this).val() || 'text');
			var currentData = collectFieldFromElement($field, $field.index());
			var rebuiltData = $.extend({}, currentData, {
				type: nextType,
				id: currentData.field_id
			});
			var wasCollapsed = $field.hasClass('collapsed');
			var $newField = $(getFieldHtml(rebuiltData));
			if (!wasCollapsed) {
				$newField.removeClass('collapsed');
			}
			$field.replaceWith($newField);
			if ($('#opb-fields-list').sortable('instance')) {
				$('#opb-fields-list').sortable('refresh');
			}
			refreshConditionalFieldOptions();
			triggerAutoSaveIfNeeded();
		});
	}

	function syncSubFieldsEditor($field) {
		var arr = [];
		$field.find('.wpps-opb-subfield-row').each(function() {
			var name = $.trim($(this).find('.opb-sub-name').val());
			var label = $.trim($(this).find('.opb-sub-label').val());
			var type = $(this).find('.opb-sub-type').val() || 'text';
			if (name) {
				arr.push({ name: name, label: label || name, type: type });
			}
		});
		$field.find('.opb-field-sub-fields').val(JSON.stringify(arr));
	}

	function bindSubFieldsEditor() {
		$(document).off('click.opbSubAdd', '.opb-sub-add').on('click.opbSubAdd', '.opb-sub-add', function(e) {
			e.preventDefault();
			var $field = $(this).closest('.wpps-opb-field-item');
			var $editor = $field.find('.wpps-opb-subfields-editor');
			var subTypes = ['text', 'textarea', 'url', 'email', 'number', 'image', 'select', 'checkbox', 'toggle'];
			var typeOptions = subTypes.map(function(st) {
				return '<option value="' + escapeHtml(st) + '">' + escapeHtml(depsStore.fieldLabels[st] || st) + '</option>';
			}).join('');
			$editor.append(
				'<div class="wpps-opb-subfield-row">' +
				'<input type="text" class="opb-sub-name wpps-opb-input" placeholder="name">' +
				'<input type="text" class="opb-sub-label wpps-opb-input" placeholder="Label">' +
				'<select class="opb-sub-type wpps-opb-select">' + typeOptions + '</select>' +
				'<button type="button" class="opb-sub-remove button button-small" title="Remove">×</button>' +
				'</div>'
			);
			syncSubFieldsEditor($field);
			triggerAutoSaveIfNeeded();
		});

		$(document).off('click.opbSubRemove', '.opb-sub-remove').on('click.opbSubRemove', '.opb-sub-remove', function(e) {
			e.preventDefault();
			var $field = $(this).closest('.wpps-opb-field-item');
			$(this).closest('.wpps-opb-subfield-row').remove();
			syncSubFieldsEditor($field);
			triggerAutoSaveIfNeeded();
		});

		$(document).off('input change.opbSubFields', '.opb-sub-name, .opb-sub-label, .opb-sub-type, .opb-field-button-label')
			.on('input change.opbSubFields', '.opb-sub-name, .opb-sub-label, .opb-sub-type, .opb-field-button-label', function() {
				syncSubFieldsEditor($(this).closest('.wpps-opb-field-item'));
				triggerAutoSaveIfNeeded();
			});
	}

	function bindGeneralChangeHandlers() {
		var selectors = [
			'#opb-fields-list .opb-field-label',
			'#opb-fields-list .opb-field-id',
			'#opb-fields-list .opb-field-desc',
			'#opb-fields-list .opb-field-default',
			'#opb-fields-list .opb-field-options',
			'#opb-fields-list .opb-field-required',
			'#opb-fields-list .opb-field-width',
			'#opb-fields-list .opb-field-placeholder',
			'#opb-fields-list .opb-field-css-class',
			'#opb-fields-list .opb-field-maxlength',
			'#opb-fields-list .opb-field-readonly',
			'#opb-fields-list .opb-field-rows',
			'#opb-fields-list .opb-field-min',
			'#opb-fields-list .opb-field-max',
			'#opb-fields-list .opb-field-step',
			'#opb-fields-list .opb-field-prefix',
			'#opb-fields-list .opb-field-suffix',
			'#opb-fields-list .opb-field-checkbox-label',
			'#opb-fields-list .opb-field-radio-layout',
			'#opb-fields-list .opb-field-select-layout',
			'#opb-fields-list .opb-field-allow-empty',
			'#opb-fields-list .opb-field-allow-none',
			'#opb-fields-list .opb-field-multiple',
			'#opb-fields-list .opb-field-media-buttons',
			'#opb-fields-list .opb-field-teeny',
			'#opb-fields-list .opb-field-return-format',
			'#opb-fields-list .opb-field-preview-size',
			'#opb-fields-list .opb-field-date-type',
			'#opb-fields-list .opb-field-min-date',
			'#opb-fields-list .opb-field-max-date',
			'#opb-fields-list .opb-field-color-palette',
			'#opb-fields-list .opb-field-message-content',
			'#opb-fields-list .opb-field-button-label',
			'#opb-fields-list .opb-field-conditional-field',
			'#opb-fields-list .opb-field-conditional-operator',
			'#opb-fields-list .opb-field-conditional-value'
		].join(', ');

		$(document).off('change.opbExtrasInput keyup.opbExtrasInput input.opbExtrasInput', selectors)
			.on('change.opbExtrasInput keyup.opbExtrasInput input.opbExtrasInput', selectors, function() {
				var $field = $(this).closest('.wpps-opb-field-item');
				updateFieldHeader($field);
				if ($(this).is('.opb-field-id, .opb-field-label')) {
					refreshConditionalFieldOptions();
				} else if ($(this).is('.opb-field-options, .opb-field-default, .opb-field-default-select')) {
					refreshConditionalValueControls();
				}
				triggerAutoSaveIfNeeded();
			});

		$(document).off('change.opbCondFieldValue', '.opb-field-conditional-field, .opb-field-conditional-operator')
			.on('change.opbCondFieldValue', '.opb-field-conditional-field, .opb-field-conditional-operator', function() {
				refreshConditionalValueControl($(this).closest('.wpps-opb-field-item'));
				triggerAutoSaveIfNeeded();
			});

		$(document).off('input change.opbCondValueOpts', '.opb-opt-value, .opb-opt-label')
			.on('input change.opbCondValueOpts', '.opb-opt-value, .opb-opt-label', function() {
				refreshConditionalValueControls();
			});

		$(document).off('click.opbExtrasDelete', '.opb-field-delete').on('click.opbExtrasDelete', '.opb-field-delete', function() {
			setTimeout(function() {
				refreshConditionalFieldOptions();
			}, 0);
		});

		$(document).off('click.opbExtrasAdd', '.opb-add-field').on('click.opbExtrasAdd', '.opb-add-field', function() {
			setTimeout(function() {
				refreshConditionalFieldOptions();
			}, 0);
		});

		$('#opb-fields-list').off('sortupdate.opbExtras').on('sortupdate.opbExtras', function() {
			refreshConditionalFieldOptions();
		});
	}

	function initFieldBuilderExtras(deps) {
		setDeps(deps || {});
		bindDuplicate();
		bindTypeSwitcher();
		bindSubFieldsEditor();
		bindGeneralChangeHandlers();
		refreshConditionalFieldOptions();
	}

	window.wppsOpbGetFieldHtml = getFieldHtml;
	window.wppsOpbCollectFields = collectFields;
	window.wppsOpbRefreshConditionalFieldOptions = refreshConditionalFieldOptions;
	window.wppsOpbRefreshConditionalValueControls = refreshConditionalValueControls;
	window.wppsOpbInitFieldBuilderExtras = initFieldBuilderExtras;

})(jQuery);
