'use strict';

function stringifyChoiceOptions(options) {
	return JSON.stringify(normalizeChoiceOptions(options));
}

function choiceOptionsFromField(field) {
	if (field && field.options) {
		return normalizeChoiceOptions(field.options);
	}

	if (field && field.field_options) {
		return parseChoiceOptions(field.field_options);
	}

	return defaultChoiceOptions();
}

function sanitizeOptionText(value) {
	return String(value || '').replace(/[<>]/g, '').replace(/\s+/g, ' ').trim();
}

function sanitizeOptionValue(value, index) {
	var safe = String(value || '')
		.toLowerCase()
		.replace(/javascript\s*:/gi, '')
		.replace(/data\s*:/gi, '')
		.replace(/[^a-z0-9_-]+/g, '_')
		.replace(/_+/g, '_')
		.replace(/^_+|_+$/g, '');

	return safe || 'option_' + (index + 1);
}

function renderOptionsTraitInput(elInput, options) {
	var rows = normalizeChoiceOptions(options);
	var html = '<div class="subin-gjs-options-trait__rows">';

	rows.forEach(function (option) {
		html += '<div class="subin-gjs-options-trait__row" data-subin-option-row>';
		html += '<label><span>Label</span><input type="text" data-subin-option-label value="' + escapeHtml(option.label) + '" /></label>';
		html += '<label><span>Value</span><input type="text" data-subin-option-value value="' + escapeHtml(option.value) + '" /></label>';
		html += '<div class="subin-gjs-options-trait__actions">';
		html += '<button type="button" class="button button-small" data-subin-option-move="up">Up</button>';
		html += '<button type="button" class="button button-small" data-subin-option-move="down">Down</button>';
		html += '<button type="button" class="button-link-delete" data-subin-option-remove>Remove</button>';
		html += '</div>';
		html += '</div>';
	});

	html += '</div><button type="button" class="button button-small" data-subin-option-add>Add option</button>';
	elInput.innerHTML = html;
}

function renderFieldInnerStyleTraitInput(elInput) {
	elInput.innerHTML = [
		fieldStyleGroup('Label style', [
			fieldStyleControl('data-subin-label-color', 'Text color', 'color'),
			fieldStyleControl('data-subin-label-font-size', 'Font size', 'number', 'px'),
			fieldStyleSelect('data-subin-label-font-weight', 'Font weight', [
				['', 'Default'],
				['400', 'Regular'],
				['500', 'Medium'],
				['600', 'Semibold'],
				['700', 'Bold'],
			]),
			fieldStyleControl('data-subin-label-line-height', 'Line height', 'number'),
			fieldStyleControl('data-subin-label-margin-bottom', 'Margin bottom', 'number', 'px'),
		]),
		fieldStyleGroup('Input style', [
			fieldStyleControl('data-subin-input-bg-color', 'Background', 'color'),
			fieldStyleControl('data-subin-input-text-color', 'Text color', 'color'),
			fieldStyleControl('data-subin-input-border-color', 'Border color', 'color'),
			fieldStyleControl('data-subin-input-border-width', 'Border width', 'number', 'px'),
			fieldStyleControl('data-subin-input-border-radius', 'Border radius', 'number', 'px'),
			fieldStyleSelect('data-subin-input-box-shadow', 'Shadow', [
				['', 'Default'],
				['none', 'None'],
				['0 4px 12px rgba(15, 23, 42, 0.12)', 'Subtle'],
				['0 10px 24px rgba(15, 23, 42, 0.16)', 'Raised'],
				['0 18px 36px rgba(15, 23, 42, 0.22)', 'Strong'],
			]),
			fieldStyleControl('data-subin-input-padding', 'Padding', 'text', 'px'),
			fieldStyleControl('data-subin-input-min-height', 'Min height', 'number', 'px'),
		]),
		fieldStyleGroup('Placeholder style', [
			fieldStyleControl('data-subin-placeholder-color', 'Placeholder color', 'color'),
		]),
		fieldStyleGroup('Help text style', [
			fieldStyleControl('data-subin-help-color', 'Text color', 'color'),
			fieldStyleControl('data-subin-help-font-size', 'Font size', 'number', 'px'),
			fieldStyleControl('data-subin-help-line-height', 'Line height', 'number'),
			fieldStyleControl('data-subin-help-margin-top', 'Margin top', 'number', 'px'),
		]),
	].join('');
}

function fieldStyleGroup(label, controls) {
	return '<fieldset class="subin-gjs-field-style-trait__group"><legend>' + escapeHtml(label) + '</legend>' + controls.join('') + '</fieldset>';
}

function fieldStyleControl(name, label, type, suffix) {
	return '<label class="subin-gjs-field-style-trait__control"><span>' + escapeHtml(label) + '</span><input type="' + escapeHtml(type || 'text') + '" data-subin-field-style="' + escapeHtml(name) + '" ' + (type === 'number' ? 'min="0" step="1" ' : '') + ' />' + (suffix ? '<em>' + escapeHtml(suffix) + '</em>' : '') + '</label>';
}

function fieldStyleSelect(name, label, options) {
	var html = '<label class="subin-gjs-field-style-trait__control"><span>' + escapeHtml(label) + '</span><select data-subin-field-style="' + escapeHtml(name) + '">';
	options.forEach(function (option) {
		html += '<option value="' + escapeHtml(option[0]) + '">' + escapeHtml(option[1]) + '</option>';
	});
	return html + '</select></label>';
}

function sanitizeFieldStyleTraitValue(control) {
	var name = control.getAttribute('data-subin-field-style') || '';
	var value = String(control.value || '').trim();

	if (!value) {
		return '';
	}

	if (control.type === 'color' || /color/.test(name)) {
		return /^#[0-9a-f]{6}$/i.test(value) ? value : '';
	}

	if (control.type === 'number') {
		return String(Math.max(0, Math.min(999, parseInt(value, 10) || 0)));
	}

	if (name === 'data-subin-label-font-weight') {
		return ['400', '500', '600', '700'].indexOf(value) !== -1 ? value : '';
	}

	if (name === 'data-subin-input-box-shadow') {
		return [
			'none',
			'0 4px 12px rgba(15, 23, 42, 0.12)',
			'0 10px 24px rgba(15, 23, 42, 0.16)',
			'0 18px 36px rgba(15, 23, 42, 0.22)',
		].indexOf(value) !== -1 ? value : '';
	}

	if (name === 'data-subin-input-padding') {
		return sanitizeCssBoxValue(value);
	}

	if (name === 'data-subin-label-line-height' || name === 'data-subin-help-line-height') {
		return /^\d+(?:\.\d{1,2})?$/.test(value) ? value : '';
	}

	return '';
}

function sanitizeCssBoxValue(value) {
	var parts = String(value || '').trim().split(/\s+/).slice(0, 4);

	if (!parts.length) {
		return '';
	}

	for (var i = 0; i < parts.length; i++) {
		if (!/^\d+(?:\.\d+)?(?:px|rem|em|%)?$/.test(parts[i])) {
			return '';
		}
		if (/^\d/.test(parts[i]) && !/(px|rem|em|%)$/.test(parts[i])) {
			parts[i] += 'px';
		}
	}

	return parts.join(' ');
}

function readOptionsTraitInput(elInput) {
	var rows = elInput.querySelectorAll('[data-subin-option-row]');
	var options = [];

	rows.forEach(function (row, index) {
		var labelInput = row.querySelector('[data-subin-option-label]');
		var valueInput = row.querySelector('[data-subin-option-value]');
		var label = labelInput ? sanitizeOptionText(labelInput.value) : '';
		var value = valueInput ? sanitizeOptionValue(valueInput.value || label, index) : sanitizeOptionValue(label, index);

		if (label || value) {
			options.push({
				label: label || value,
				value: value,
			});
		}
	});

	return normalizeChoiceOptions(options);
}

function moveOptionRow(row, direction) {
	if (!row || !row.parentNode) {
		return;
	}

	if (direction === 'up' && row.previousElementSibling) {
		row.parentNode.insertBefore(row, row.previousElementSibling);
	}

	if (direction === 'down' && row.nextElementSibling) {
		row.parentNode.insertBefore(row.nextElementSibling, row);
	}
}

function nextChoiceOption(elInput) {
	var next = elInput.querySelectorAll('[data-subin-option-row]').length + 1;

	return {
		label: 'Option ' + next,
		value: 'option_' + next,
	};
}

function setChoiceOptionsAttribute(component, options) {
	addComponentAttribute(component, 'data-subin-options', stringifyChoiceOptions(options));
}

function lockFieldPreviewChildren(component) {
	var children = component && component.components ? component.components() : null;

	if (!children || !children.forEach) {
		return;
	}

	children.forEach(function (child) {
		lockPreviewComponent(child);
	});
}

function lockContentPreviewChildren(component) {
	var children = component && component.components ? component.components() : null;

	if (!children || !children.forEach) {
		return;
	}

	children.forEach(function (child) {
		lockPreviewComponent(child);
	});
}

function lockPreviewComponent(component) {
	if (!component || !component.set) {
		return;
	}

	component.set({
		selectable: false,
		hoverable: false,
		draggable: false,
		droppable: false,
		editable: false,
		layerable: false,
		stylable: false,
		traits: [],
	});

	if (component.components && component.components().forEach) {
		component.components().forEach(function (child) {
			lockPreviewComponent(child);
		});
	}
}

function configureFieldComponentTraits(component) {
	var attributes = component.getAttributes ? component.getAttributes() : {};
	if (!attributes['data-subin-label'] && attributes['data-subin-field-label']) {
		component.addAttributes({
			'data-subin-label': attributes['data-subin-field-label'],
		});
		attributes = component.getAttributes ? component.getAttributes() : attributes;
	}
	if (attributes['data-subin-field-type'] === 'consent' && !attributes['data-subin-consent-text']) {
		component.addAttributes({
			'data-subin-consent-text': attributes['data-subin-label'] || attributes['data-subin-field-label'] || defaultFieldLabel('consent'),
		});
		attributes = component.getAttributes ? component.getAttributes() : attributes;
	}
	if (isChoiceField(attributes['data-subin-field-type']) && !hasValidChoiceOptions(attributes['data-subin-options'])) {
		component.addAttributes({
			'data-subin-options': stringifyChoiceOptions(defaultChoiceOptions()),
		});
		attributes = component.getAttributes ? component.getAttributes() : attributes;
	}
	component.set('traits', subinFieldTraits(attributes));
	updateFieldComponentPreview(component);
	updateFieldLayerName(component);
}

function configureContentComponentTraits(component, fallbackType) {
	var attributes = component.getAttributes ? component.getAttributes() : {};
	var componentName = attributes['data-subin-component'] || fallbackType || subinComponentNameFromType(component.get ? component.get('type') : '');

	if (componentName === 'image-block') {
		updateImageBlockPreview(component);
		if (component.__subinImageHandler && component.off) {
			component.off('change:attributes:data-subin-media-url change:attributes:data-subin-media-alt change:attributes', component.__subinImageHandler);
		}
		component.__subinImageHandler = function () {
			updateImageBlockPreview(component);
		};
		component.on('change:attributes:data-subin-media-url change:attributes:data-subin-media-alt change:attributes', component.__subinImageHandler);
		return;
	}

	if (['text-block', 'html-block', 'notice', 'privacy'].indexOf(String(componentName || '')) === -1) {
		return;
	}

	if (componentName === 'html-block' && !attributes['data-subin-html-content']) {
		component.addAttributes({
			'data-subin-html-content': componentContentValue(component, componentName),
		});
		attributes = component.getAttributes ? component.getAttributes() : attributes;
	}

	if (!attributes['data-subin-content'] && componentName !== 'html-block') {
		component.addAttributes({
			'data-subin-content': componentContentValue(component, componentName),
		});
		attributes = component.getAttributes ? component.getAttributes() : attributes;
	}

	component.set('traits', subinContentTraits(componentName).concat(isBackgroundMediaComponentData(componentName) ? [backgroundMediaTrait()] : []));
	updateContentComponentPreview(component);
	if (component.__subinContentHandler && component.off) {
		component.off('change:attributes:data-subin-content change:attributes:data-subin-html-content change:attributes', component.__subinContentHandler);
	}
	component.__subinContentHandler = function () {
		updateContentComponentPreview(component);
	};
	component.on('change:attributes:data-subin-content change:attributes:data-subin-html-content change:attributes', component.__subinContentHandler);
}

function updateImageBlockPreview(component) {
	var attributes = component && component.getAttributes ? component.getAttributes() : {};
	var url = sanitizeMediaUrl(attributes['data-subin-media-url'] || '');
	var alt = String(attributes['data-subin-media-alt'] || '').replace(/<[^>]*>/g, '').trim();

	if (!component || !component.components) {
		return;
	}

	if (url) {
		component.components('<img class="subin-gjs-image-preview" src="' + escapeHtml(url) + '" alt="' + escapeHtml(alt) + '" />');
	} else {
		component.components('<div class="subin-gjs-image-placeholder" aria-hidden="true">Image</div>');
	}

	lockContentPreviewChildren(component);
}

function updateFieldComponentPreview(component) {
	var attributes = component.getAttributes ? component.getAttributes() : {};
	var fieldType = attributes['data-subin-field-type'] || 'text';
	var label = attributes['data-subin-label'] || attributes['data-subin-field-label'] || defaultFieldLabel(fieldType);
	var consentText = attributes['data-subin-consent-text'] || label;
	var placeholder = attributes['data-subin-placeholder'] || '';
	var helpText = attributes['data-subin-help-text'] || '';
	var required = attributes['data-subin-required'] === '1' || attributes['data-subin-required'] === true;
	var fieldKey = attributes['data-subin-field-key'] || '';
	var defaultValue = attributes['data-subin-default-value'] || '';
	var options = parseChoiceOptions(attributes['data-subin-options']);

	component.components(subinFieldPreview(fieldType, label, placeholder, required, fieldKey, options, helpText, consentText, defaultValue));
	lockFieldPreviewChildren(component);
	applyFieldInnerStyles(component);
	updateFieldLayerName(component);
	scheduleGrapesJSPreviewStateRefresh(window.SUBINGrapesJSEditor);
}

function applyFieldInnerStyles(component) {
	var el = component && component.view && component.view.el;
	var attributes = component && component.getAttributes ? component.getAttributes() : {};

	if (!el) {
		return;
	}

	applyInlineStyles(el.querySelectorAll('.subin-field-label'), fieldInnerStyleMap(attributes, 'label'));
	applyInlineStyles(el.querySelectorAll('.subin-field-input,.subin-field-textarea,.subin-choice-row input,.subin-field-checkbox-box'), fieldInnerStyleMap(attributes, 'input'));
	applyInlineStyles(el.querySelectorAll('.subin-field-placeholder'), fieldInnerStyleMap(attributes, 'placeholder'));
	applyInlineStyles(el.querySelectorAll('.subin-field-help'), fieldInnerStyleMap(attributes, 'help'));
}

function applyInlineStyles(nodes, styles) {
	if (!nodes || !nodes.forEach) {
		return;
	}

	nodes.forEach(function (node) {
		Object.keys(styles).forEach(function (property) {
			node.style[property] = styles[property];
		});
	});
}

function fieldInnerStyleMap(attributes, part) {
	var styles = {};

	if (part === 'label') {
		addStyleValue(styles, 'color', attributes['data-subin-label-color']);
		addPixelStyleValue(styles, 'fontSize', attributes['data-subin-label-font-size']);
		addStyleValue(styles, 'fontWeight', attributes['data-subin-label-font-weight']);
		addStyleValue(styles, 'lineHeight', attributes['data-subin-label-line-height']);
		addPixelStyleValue(styles, 'marginBottom', attributes['data-subin-label-margin-bottom']);
	} else if (part === 'input') {
		addStyleValue(styles, 'backgroundColor', attributes['data-subin-input-bg-color']);
		addStyleValue(styles, 'color', attributes['data-subin-input-text-color']);
		addStyleValue(styles, 'borderColor', attributes['data-subin-input-border-color']);
		addPixelStyleValue(styles, 'borderWidth', attributes['data-subin-input-border-width']);
		addPixelStyleValue(styles, 'borderRadius', attributes['data-subin-input-border-radius']);
		addStyleValue(styles, 'boxShadow', attributes['data-subin-input-box-shadow']);
		addStyleValue(styles, 'padding', sanitizeCssBoxValue(attributes['data-subin-input-padding']));
		addPixelStyleValue(styles, 'minHeight', attributes['data-subin-input-min-height']);
	} else if (part === 'placeholder') {
		addStyleValue(styles, 'color', attributes['data-subin-placeholder-color']);
	} else if (part === 'help') {
		addStyleValue(styles, 'color', attributes['data-subin-help-color']);
		addPixelStyleValue(styles, 'fontSize', attributes['data-subin-help-font-size']);
		addStyleValue(styles, 'lineHeight', attributes['data-subin-help-line-height']);
		addPixelStyleValue(styles, 'marginTop', attributes['data-subin-help-margin-top']);
	}

	return styles;
}

function addStyleValue(styles, property, value) {
	if (value) {
		styles[property] = value;
	}
}

function addPixelStyleValue(styles, property, value) {
	var number = parseInt(value, 10);
	if (!isNaN(number) && number >= 0) {
		styles[property] = number + 'px';
	}
}

function updateContentComponentPreview(component) {
	var attributes = component.getAttributes ? component.getAttributes() : {};
	var componentName = attributes['data-subin-component'] || subinComponentNameFromType(component.get ? component.get('type') : '');

	if (['text-block', 'html-block', 'notice', 'privacy'].indexOf(String(componentName || '')) === -1) {
		return;
	}

	component.components(contentPreviewHtml(contentComponentAttributeValue(attributes, componentName), componentName));
	lockContentPreviewChildren(component);
}

function contentComponentAttributeValue(attributes, componentName) {
	if (componentName === 'html-block') {
		return attributes['data-subin-html-content'] || attributes['data-subin-content'] || '';
	}

	return attributes['data-subin-content'] || '';
}

function updateSubmitButtonPreview(component) {
	var attributes = component.getAttributes ? component.getAttributes() : {};
	var text = attributes['data-subin-button-text'] || componentPlainText(component) || 'Submit';
	component.components(escapeHtml(text));
	scheduleGrapesJSPreviewStateRefresh(window.SUBINGrapesJSEditor);
}

function componentContentValue(component, componentName) {
	var attributes = component && component.getAttributes ? component.getAttributes() : {};
	if (componentName === 'html-block' && attributes['data-subin-html-content']) {
		return attributes['data-subin-html-content'];
	}

	if (attributes['data-subin-content']) {
		return attributes['data-subin-content'];
	}

	if (componentName === 'html-block') {
		return componentInnerHtml(component) || '<p>Safe HTML content</p>';
	}

	return componentPlainText(component) || defaultContentText(componentName);
}

function defaultContentText(componentName) {
	if (componentName === 'notice') {
		return 'Important information for visitors.';
	}
	if (componentName === 'privacy') {
		return 'We use your details only to respond to this request.';
	}
	if (componentName === 'html-block') {
		return '<p>Safe HTML content</p>';
	}

	return 'Add a short line of supporting text.';
}

function contentPreviewHtml(value, componentName) {
	var content = sanitizeContentAttribute(value, componentName);

	if (componentName === 'html-block') {
		return content || '<p>Safe HTML content</p>';
	}

	return '<p>' + escapeHtml(content || defaultContentText(componentName)) + '</p>';
}

function sanitizeContentAttribute(value, componentName) {
	var content = String(value || '');

	if (componentName === 'html-block') {
		return sanitizeSafeHtml(content);
	}

	return content.replace(/<[^>]*>/g, '').replace(/\s+/g, ' ').trim();
}

function sanitizeSafeHtml(value) {
	var wrapper = document.createElement('div');
	var allowedTags = ['P', 'BR', 'STRONG', 'EM', 'B', 'I', 'SPAN', 'DIV', 'SMALL', 'UL', 'OL', 'LI', 'A', 'HR'];
	var walker;
	var nodes = [];

	wrapper.innerHTML = String(value || '')
		.replace(/<\s*(script|iframe|object|embed|form|input|button|textarea|select|style)\b[^>]*>[\s\S]*?<\s*\/\s*\1\s*>/gi, '')
		.replace(/<\s*(script|iframe|object|embed|form|input|button|textarea|select|style)\b[^>]*\/?>/gi, '');

	walker = document.createTreeWalker(wrapper, NodeFilter.SHOW_ELEMENT, null);
	while (walker.nextNode()) {
		nodes.push(walker.currentNode);
	}

	nodes.forEach(function (node) {
		var attributes;
		var replacement;

		if (allowedTags.indexOf(node.tagName) === -1) {
			replacement = document.createTextNode(node.textContent || '');
			node.parentNode.replaceChild(replacement, node);
			return;
		}

		attributes = Array.prototype.slice.call(node.attributes || []);
		attributes.forEach(function (attribute) {
			var name = attribute.name.toLowerCase();
			var val = attribute.value || '';

			if (name.indexOf('on') === 0 || name === 'style' || name === 'srcdoc') {
				node.removeAttribute(attribute.name);
				return;
			}

			if (node.tagName === 'A' && ['href', 'title', 'target', 'rel'].indexOf(name) !== -1) {
				if (name === 'href' && /^(javascript|data)\s*:/i.test(val)) {
					node.removeAttribute(attribute.name);
				}
				return;
			}

			if (name !== 'class' && name !== 'aria-label') {
				node.removeAttribute(attribute.name);
			}
		});
	});

	return wrapper.innerHTML;
}

function componentInnerHtml(component) {
	var el = component && component.view && component.view.el ? component.view.el : null;
	if (!el) {
		return '';
	}

	return el.innerHTML || '';
}

function componentPlainText(component) {
	var text = '';
	var components = component.components && component.components();

	if (components && components.forEach) {
		components.forEach(function (child) {
			if (child.get && child.get('content')) {
				text += ' ' + child.get('content');
			} else if (child.toHTML) {
				text += ' ' + child.toHTML().replace(/<[^>]*>/g, ' ');
			}
		});
	}

	return text.replace(/\s+/g, ' ').trim();
}

function commonBoxStyleProps() {
	return [
		'width',
		'max-width',
		'min-height',
		'height',
		'margin',
		'padding',
		'background-color',
		'border-width',
		'border-style',
		'border-color',
		'border-radius',
		'box-shadow',
	];
}

function typographyStyleProps() {
	return [
		'font-size',
		'font-weight',
		'line-height',
		'text-align',
		'color',
	];
}

function addSubmissionInboxPreviewStyles(editor) {
	editor.addStyle([
		'html,body{min-height:100%;background:transparent;}',
		'body{margin:0;padding:28px;}',
		'.subin-gjs-form-preview{box-sizing:border-box;display:grid;gap:18px;width:100%;max-width:720px;margin:0 auto;padding:30px;color:#172033;background:#fff;border:1px solid #d8e2ee;border-radius:20px;box-shadow:0 14px 36px rgba(15,23,42,.075);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;}',
		'.subin-gjs-form-preview *,.subin-gjs-form-preview *:before,.subin-gjs-form-preview *:after{box-sizing:border-box;}',
		'.subin-gjs-form-preview > .subin-gjs-row{display:flex;flex-wrap:wrap;align-items:flex-start;align-content:flex-start;gap:0 16px;min-height:44px;padding:6px;border:1px dashed rgba(37,99,235,.16);border-radius:6px;background:rgba(37,99,235,.018);}',
		'.subin-gjs-form-preview > .subin-gjs-row:empty:before{content:"Drop field or block here";display:flex;align-items:center;min-height:36px;color:#94a3b8;font-size:13px;}',
		'.subin-gjs-form-preview .subin-gjs-row > .subin-form-field,.subin-gjs-form-preview .subin-gjs-row > .subin-content-block{flex:0 1 auto;width:100%;max-width:100%;min-width:min(220px,100%);margin:0;position:static!important;transform:none!important;}',
		'.subin-gjs-form-preview .subin-gjs-row > .subin-divider-block,.subin-gjs-form-preview .subin-gjs-row > .subin-privacy-block,.subin-gjs-form-preview .subin-gjs-row > .subin-section-block,.subin-gjs-form-preview .subin-gjs-row > .subin-spacer-block,.subin-gjs-form-preview .subin-gjs-row > .subin-image-block{min-width:100%;}',
		'.subin-gjs-form-preview .subin-gjs-row > .subin-submit-button{flex:0 1 auto;width:auto;min-width:140px;max-width:100%;margin:0;position:static!important;transform:none!important;}',
		'.subin-gjs-form-preview .subin-gjs-row > .subin-form-field *,.subin-gjs-form-preview .subin-gjs-row > .subin-content-block *,.subin-gjs-form-preview .subin-gjs-row > .subin-submit-button *{pointer-events:none;}',
		'.subin-gjs-form-preview.subin-gjs-runtime-preview .subin-gjs-row > .subin-form-field input,.subin-gjs-form-preview.subin-gjs-runtime-preview .subin-gjs-row > .subin-form-field textarea,.subin-gjs-form-preview.subin-gjs-runtime-preview .subin-gjs-row > .subin-form-field select,.subin-gjs-form-preview.subin-gjs-runtime-preview .subin-gjs-row > .subin-form-field label,.subin-gjs-form-preview.subin-gjs-runtime-preview .subin-gjs-row > .subin-submit-button{pointer-events:auto;}',
		'.gjs-placeholder{outline:2px solid rgba(37,99,235,.55)!important;outline-offset:2px!important;background:rgba(37,99,235,.10)!important;}',
		'.subin-gjs-form-preview .subin-content-block{min-width:0;color:#1f2933;line-height:1.55;overflow-wrap:anywhere;}',
		'.subin-gjs-form-preview .subin-content-block>:first-child{margin-top:0;}',
		'.subin-gjs-form-preview .subin-content-block>:last-child{margin-bottom:0;}',
		'.subin-gjs-form-preview .subin-form-title{margin:0 0 8px;font-size:24px;line-height:1.25;font-weight:700;letter-spacing:0;}',
		'.subin-gjs-form-preview .subin-form-description{margin:0;color:#52606d;line-height:1.5;}',
		'.subin-gjs-form-preview .subin-gjs-preview-state-message{margin:0;padding:12px 14px;border-radius:6px;font-size:14px;line-height:1.45;}',
		'.subin-gjs-form-preview .subin-gjs-preview-state-message--error{color:#8a2424;background:#fcebea;border:1px solid #f5c2c7;}',
		'.subin-gjs-form-preview .subin-gjs-preview-state-message--success{color:#135e2f;background:#edf7ed;border:1px solid #b7e2c2;}',
		'.subin-gjs-form-preview .subin-form-field{display:flex;flex-direction:column;gap:7px;min-width:0;}',
		'.subin-gjs-form-preview .subin-field-label{display:block;margin:0;font-weight:600;color:#1f2933;line-height:1.35;overflow-wrap:anywhere;}',
		'.subin-gjs-form-preview .subin-field-required{color:#b32d2e;}',
		'.subin-gjs-form-preview .subin-field-input,.subin-gjs-form-preview .subin-field-textarea{width:100%;min-height:44px;padding:10px 12px;color:#1f2933;background:#fff;border:1px solid #bcccdc;border-radius:6px;font:inherit;line-height:1.4;box-shadow:none;}',
		'.subin-gjs-form-preview .subin-form-field.is-error .subin-field-input,.subin-gjs-form-preview .subin-form-field.is-error .subin-field-textarea,.subin-gjs-form-preview .subin-form-field.is-error .subin-choice-row input,.subin-gjs-form-preview .subin-form-field.is-error .subin-field-checkbox-box{border-color:#b32d2e;box-shadow:0 0 0 1px rgba(179,45,46,.16);}',
		'.subin-gjs-form-preview .subin-field-input:disabled,.subin-gjs-form-preview .subin-field-textarea:disabled{opacity:1;color:#1f2933;background:#fff;}',
		'.subin-gjs-form-preview .subin-field-textarea{min-height:124px;}',
		'.subin-gjs-form-preview .subin-field-help{margin:0;color:#52606d;font-size:14px;line-height:1.45;}',
		'.subin-gjs-form-preview .subin-gjs-preview-field-error{margin:0;color:#b32d2e;font-size:13px;line-height:1.4;}',
		'.subin-gjs-form-preview .subin-field-placeholder{color:#8c8f94;}',
		'.subin-gjs-form-preview .subin-checkbox-field{display:flex;align-items:flex-start;gap:8px;color:#1f2933;line-height:1.45;}',
		'.subin-gjs-form-preview .subin-field-checkbox-box{flex:0 0 auto;width:16px;height:16px;margin-top:3px;background:#fff;border:1px solid #8c8f94;border-radius:3px;}',
		'.subin-gjs-form-preview .subin-field-options{display:grid;gap:8px;margin-top:2px;}',
		'.subin-gjs-form-preview .subin-choice-row{display:flex;align-items:center;gap:8px;margin:0;color:#1f2933;line-height:1.4;}',
		'.subin-gjs-form-preview .subin-choice-row input{flex:0 0 auto;width:16px;height:16px;margin:0;}',
		'.subin-gjs-form-preview .subin-choice-row input:disabled{opacity:1;}',
		'.subin-gjs-form-preview .subin-field-choice{display:flex;align-items:center;gap:8px;color:#1f2933;}',
		'.subin-gjs-form-preview .subin-field-choice-control{width:16px;height:16px;background:#fff;border:1px solid #8c8f94;border-radius:999px;}',
		'.subin-gjs-form-preview .subin-field-choice-control--checkbox{border-radius:3px;}',
		'.subin-gjs-form-preview .subin-hidden-field-preview{padding:9px 11px;color:#52606d;background:#f8fafc;border:1px dashed #bcccdc;border-radius:6px;font-size:13px;}',
		'.subin-gjs-form-preview .subin-submit-button{display:inline-flex;align-items:center;justify-content:center;min-height:44px;max-width:100%;padding:10px 18px;color:#fff;background:#1d4ed8;border:0;border-radius:6px;font:inherit;font-weight:600;line-height:1.3;text-align:center;cursor:pointer;}',
		'.subin-gjs-form-preview .subin-notice-block{padding:12px 14px;background:#f0f6fc;border:1px solid #c5d9ed;border-radius:6px;color:#17324d;}',
		'.subin-gjs-form-preview .subin-privacy-block{margin:0;color:#52606d;font-size:14px;}',
		'.subin-gjs-form-preview .subin-divider-block{margin:0;}',
		'.subin-gjs-form-preview .subin-divider-block hr{border:0;border-top:1px solid currentColor;opacity:.22;}',
		'.subin-gjs-form-preview .subin-section-block{padding:18px;margin:0;border:1px dashed #bcccdc;border-radius:8px;}',
		'.subin-gjs-form-preview .subin-gjs-spacer-preview,.subin-gjs-form-preview .subin-spacer-block{min-height:32px;}',
		'.subin-gjs-form-preview .subin-gjs-image-placeholder{display:flex;align-items:center;justify-content:center;min-height:120px;color:#52606d;background:#f8fafc;border:1px dashed #bcccdc;border-radius:6px;}',
		'.subin-gjs-form-preview .subin-gjs-image-preview{display:block;width:100%;max-width:100%;height:auto;border-radius:inherit;}',
	].join('\n'));
}

function buildSubmissionInboxBlocks() {
	return [
		subinFieldBlock('subin-field-text', 'Text field', 'text', 'text_field', 'Text field', 'Your answer', false, 'T'),
		subinFieldBlock('subin-field-email', 'Email field', 'email', 'email', 'Email address', 'you@example.com', false, '@'),
		subinFieldBlock('subin-field-phone', 'Phone field', 'phone', 'phone', 'Phone number', '(555) 010-1234', false, 'Ph'),
		subinFieldBlock('subin-field-date', 'Date field', 'date', 'date', 'Date', '', false, 'D'),
		subinFieldBlock('subin-field-textarea', 'Textarea field', 'textarea', 'message', 'Message', 'Write your message...', false, 'Tx'),
		subinFieldBlock('subin-field-select', 'Select field', 'select', 'select_field', 'Select field', 'Choose an option', false, 'v'),
		subinFieldBlock('subin-field-radio', 'Radio field', 'radio', 'radio_field', 'Radio field', '', false, 'O'),
		subinFieldBlock('subin-field-checkbox', 'Checkbox field', 'checkbox', 'checkbox_field', 'Checkbox field', '', false, 'X'),
		subinFieldBlock('subin-field-consent', 'Consent checkbox', 'consent', 'consent', 'I agree to be contacted about this request.', '', true, 'Ok'),
		subinFieldBlock('subin-field-hidden', 'Hidden field', 'hidden', 'hidden_field', 'Hidden field', '', false, 'H'),
		subinContentBlock('subin-text-block', 'Text block', 'subin-text-block', 'text-block', '<p>Add a short line of supporting text.</p>', 'Content', 'Aa'),
		subinContentBlock('subin-html-block', 'HTML block', 'subin-html-block', 'html-block', '<p><strong>Safe HTML content</strong></p>', 'Content', '</>'),
		subinContentBlock('subin-notice-block', 'Notice block', 'subin-notice-block', 'notice', '<p>Important information for visitors.</p>', 'Content', '!'),
		subinContentBlock('subin-divider-block', 'Divider', 'subin-divider-block', 'divider', '<hr />', 'Content', '-'),
		subinContentBlock('subin-privacy-block', 'Privacy note', 'subin-privacy-block', 'privacy', '<p>We use your details only to respond to this request.</p>', 'Content', 'i'),
		subinSubmitButtonBlock(),
		subinContentBlock('subin-section-block', 'Section', 'subin-section-block', 'section', '<p>Section content</p>', 'Layout', '[]'),
		subinContentBlock('subin-spacer-block', 'Spacer', 'subin-spacer-block', 'spacer', '<div class="subin-gjs-spacer-preview" aria-hidden="true"></div>', 'Layout', 'Sp'),
		subinContentBlock('subin-image-block', 'Image block', 'subin-image-block', 'image-block', '<div class="subin-gjs-image-placeholder" aria-hidden="true">Image</div>', 'Layout', 'Im'),
	];
}

function loadExistingSubmissionInboxForm(editor) {
	var formData = readSubmissionInboxFormData();

	if (!formData) {
		return;
	}

	addSubmissionInboxPreviewStyles(editor);

	if (hasSavedGrapesJSProject(formData.grapesjs_project)) {
		try {
			editor.loadProjectData(normalizeSubmissionInboxRowsInProject(formData.grapesjs_project));
			addSubmissionInboxPreviewStyles(editor);
			configureSubmissionInboxStylableComponents(editor, formData);
			return;
		} catch (error) {
			// Fall back to the canonical form fields when saved project data cannot be loaded.
		}
	}

	prepareFormPreviewWrapper(editor, formData);
	editor.setComponents(buildSubmissionInboxFormComponents(formData));
	configureSubmissionInboxStylableComponents(editor, formData);
	applyFormWrapperStyle(editor, formData);
}

function hasSavedGrapesJSProject(project) {
	return project && typeof project === 'object' && !Array.isArray(project) && Object.keys(project).length > 0;
}

function initGrapesJSSave(editor) {
	var formData = readSubmissionInboxFormData();
	var saveButton = document.querySelector('[data-subin-grapesjs-save]');

	if (!saveButton || !formData || !formData.ajax) {
		return;
	}

	saveButton.addEventListener('click', function () {
		saveGrapesJSProject(editor, formData, saveButton);
	});
}

function saveGrapesJSProject(editor, formData, button) {
	var status = document.querySelector('[data-subin-grapesjs-save-status]');
	var ajax = formData.ajax || {};
	var body = new window.URLSearchParams();
	var project;

	try {
		project = editor.getProjectData();
	} catch (error) {
		setGrapesJSSaveStatus(status, 'Unable to load editor project data.', true);
		return;
	}

	body.set('action', ajax.action || 'subin_save_grapesjs_project');
	body.set('form_id', String(formData.id || ''));
	body.set('nonce', ajax.nonce || '');
	body.set('project_json', JSON.stringify(project));

	button.disabled = true;
	setGrapesJSSaveStatus(status, 'Saving...', false);

	window.fetch(ajax.url || window.ajaxurl, {
		method: 'POST',
		credentials: 'same-origin',
		headers: {
			'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
		},
		body: body.toString(),
	})
		.then(function (response) {
			return response.json().then(function (payload) {
				if (!response.ok || !payload || payload.success !== true) {
					throw new Error(grapesJSAjaxMessage(payload) || 'Design Studio could not be saved.');
				}

				return payload;
			});
		})
		.then(function (payload) {
			setGrapesJSSaveStatus(status, grapesJSAjaxMessage(payload) || 'Saved.', false);
		})
		.catch(function (error) {
			setGrapesJSSaveStatus(status, error.message || 'Design Studio could not be saved.', true);
		})
		.finally(function () {
			button.disabled = false;
		});
}

function grapesJSAjaxMessage(payload) {
	if (payload && payload.data && payload.data.message) {
		return payload.data.message;
	}

	if (payload && payload.message) {
		return payload.message;
	}

	return '';
}

function setGrapesJSSaveStatus(status, message, isError) {
	if (!status) {
		return;
	}

	status.textContent = message;
	status.classList.toggle('subin-grapesjs-save-status--error', !!isError);
	status.classList.toggle('subin-grapesjs-save-status--success', !!message && !isError && message !== 'Saving...');
}

function prepareFormPreviewWrapper(editor, formData) {
	var wrapper = editor.getWrapper();
	var formId = formData && formData.id ? String(formData.id) : 'preview';

	addClasses(wrapper, ['subin-gjs-form-preview', 'subin-gjs-form-flow', 'subin-form', 'subin-form-' + formId]);
	wrapper.addAttributes({
		'data-subin-component': 'form-wrapper',
		'data-subin-form-id': formId,
	});
	applyFormMessageAttributes(wrapper, formData);
	wrapper.set('stylable', subinWrapperStyleProps());
	wrapper.set('droppable', true);
	wrapper.set('name', 'Form');
	configureFormWrapperTraits(wrapper);
}

function configureSubmissionInboxStylableComponents(editor, formData) {
	var wrapper = editor.getWrapper();
	var fieldMap = buildEditorFieldMap(formData);

	if (wrapper) {
		configureComponentStylable(wrapper, fieldMap, formData);
		walkComponents(wrapper.components && wrapper.components(), function (component) {
			configureComponentStylable(component, fieldMap, formData);
		});
	}
}
