'use strict';

function registerSubmissionInboxTraits(editor) {
	var traitManager = editor && editor.TraitManager;

	if (!traitManager || !traitManager.addType) {
		return;
	}

	traitManager.addType('subin-text', {
		eventCapture: ['input', 'change', 'blur'],
		createInput: function () {
			var input = document.createElement('input');
			input.type = 'text';
			input.className = 'subin-gjs-text-trait';
			return input;
		},
		onEvent: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var trait = props.trait;
			var event = props.event || {};
			var name = trait && trait.get ? trait.get('name') : '';

			if (!elInput || !component || !name) {
				return;
			}

			if (event.type === 'input') {
				scheduleTextTraitFlush(elInput, component, name);
			} else {
				flushTextTraitValue(elInput, component, name);
			}
		},
		onUpdate: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var trait = props.trait;
			var name = trait && trait.get ? trait.get('name') : '';
			var attributes = component && component.getAttributes ? component.getAttributes() : {};

			if (!elInput || !name || document.activeElement === elInput) {
				return;
			}

			elInput.value = attributes[name] || '';
		},
	});

	traitManager.addType('subin-content-text', {
		eventCapture: ['input', 'change', 'blur'],
		createInput: function () {
			var textarea = document.createElement('textarea');
			textarea.className = 'subin-gjs-text-trait subin-gjs-text-trait--multiline';
			textarea.rows = 4;
			return textarea;
		},
		onEvent: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var trait = props.trait;
			var event = props.event || {};
			var name = trait && trait.get ? trait.get('name') : '';

			if (!elInput || !component || !name) {
				return;
			}

			if (event.type === 'input') {
				scheduleTextTraitFlush(elInput, component, name);
			} else {
				flushTextTraitValue(elInput, component, name);
			}
		},
		onUpdate: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var trait = props.trait;
			var name = trait && trait.get ? trait.get('name') : '';
			var attributes = component && component.getAttributes ? component.getAttributes() : {};

			if (!elInput || !name || document.activeElement === elInput) {
				return;
			}

			elInput.value = attributes[name] || '';
		},
	});

	traitManager.addType('subin-html-content', {
		eventCapture: ['input', 'change', 'blur', 'click'],
		createInput: function () {
			var wrapper = document.createElement('div');
			var textarea = document.createElement('textarea');
			var button = document.createElement('button');

			wrapper.className = 'subin-gjs-html-trait-wrap';
			textarea.className = 'subin-gjs-text-trait subin-gjs-html-trait';
			textarea.rows = 12;
			textarea.spellcheck = false;
			button.type = 'button';
			button.className = 'button subin-gjs-html-trait-button';
			button.setAttribute('data-subin-open-wp-html-editor', '1');
			button.textContent = 'Open WordPress editor';
			wrapper.appendChild(textarea);
			wrapper.appendChild(button);
			return wrapper;
		},
		onEvent: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var trait = props.trait;
			var event = props.event || {};
			var name = trait && trait.get ? trait.get('name') : '';
			var textarea = htmlTraitTextarea(elInput);

			if (!elInput || !component || !name || !textarea) {
				return;
			}

			if (event.type === 'click' && event.target && event.target.closest && event.target.closest('[data-subin-open-wp-html-editor]')) {
				openSubmissionInboxHtmlEditorModal(component, textarea, name);
				return;
			}

			if (event.type === 'input') {
				scheduleTextTraitFlush(textarea, component, name);
			} else {
				flushTextTraitValue(textarea, component, name);
			}
		},
		onUpdate: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var trait = props.trait;
			var name = trait && trait.get ? trait.get('name') : '';
			var attributes = component && component.getAttributes ? component.getAttributes() : {};
			var textarea = htmlTraitTextarea(elInput);

			if (!textarea || !name || document.activeElement === textarea) {
				return;
			}

			textarea.value = attributes[name] || attributes['data-subin-content'] || '';
		},
	});

	traitManager.addType('subin-options', {
		eventCapture: ['input', 'change', 'click'],
		createInput: function () {
			var el = document.createElement('div');
			el.className = 'subin-gjs-options-trait';
			return el;
		},
		onEvent: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var event = props.event;
			var target = event && event.target;

			if (!elInput || !component) {
				return;
			}

			if (target && target.matches && target.matches('[data-subin-option-label], [data-subin-option-value]')) {
				if (event.type === 'input') {
					scheduleChoiceOptionsFlush(elInput, component);
				} else {
					flushChoiceOptionsAttribute(elInput, component);
				}
				return;
			}

			if (target && target.closest && target.closest('[data-subin-option-add]')) {
				if (event.preventDefault) {
					event.preventDefault();
				}
				renderOptionsTraitInput(elInput, readOptionsTraitInput(elInput).concat([nextChoiceOption(elInput)]));
			}

			if (target && target.closest && target.closest('[data-subin-option-remove]')) {
				if (event.preventDefault) {
					event.preventDefault();
				}
				var row = target.closest('[data-subin-option-row]');
				if (row && row.parentNode) {
					row.parentNode.removeChild(row);
				}
			}

			if (target && target.closest && target.closest('[data-subin-option-move]')) {
				if (event.preventDefault) {
					event.preventDefault();
				}
				moveOptionRow(target.closest('[data-subin-option-row]'), target.closest('[data-subin-option-move]').getAttribute('data-subin-option-move'));
			}

			setChoiceOptionsAttribute(component, readOptionsTraitInput(elInput));
		},
		onUpdate: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var attributes = component && component.getAttributes ? component.getAttributes() : {};

			if (!elInput) {
				return;
			}

			if (traitInputContainsFocus(elInput)) {
				return;
			}

			renderOptionsTraitInput(elInput, parseChoiceOptions(attributes['data-subin-options']));
		},
	});

	traitManager.addType('subin-field-inner-styles', {
		eventCapture: ['input', 'change'],
		createInput: function () {
			var el = document.createElement('div');
			el.className = 'subin-gjs-field-style-trait';
			return el;
		},
		onEvent: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var target = props.event && props.event.target;

			if (!elInput || !component || !target || !target.matches || !target.matches('[data-subin-field-style]')) {
				return;
			}

			addComponentAttribute(component, target.getAttribute('data-subin-field-style'), sanitizeFieldStyleTraitValue(target));
			applyFieldInnerStyles(component);
		},
		onUpdate: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var attributes = component && component.getAttributes ? component.getAttributes() : {};

			if (!elInput) {
				return;
			}

			if (!elInput.__subinFieldStyleRendered) {
				renderFieldInnerStyleTraitInput(elInput);
				elInput.__subinFieldStyleRendered = true;
			}

			if (traitInputContainsFocus(elInput)) {
				return;
			}

			elInput.querySelectorAll('[data-subin-field-style]').forEach(function (control) {
				var name = control.getAttribute('data-subin-field-style');
				control.value = attributes[name] || '';
			});
		},
	});

	traitManager.addType('subin-readonly', {
		createInput: function () {
			var input = document.createElement('input');
			input.type = 'text';
			input.readOnly = true;
			input.className = 'subin-gjs-readonly-trait';
			return input;
		},
		onUpdate: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var attributes = component && component.getAttributes ? component.getAttributes() : {};

			if (elInput) {
				elInput.value = fieldTypeLabel(attributes['data-subin-field-type'] || '');
			}
		},
	});

	traitManager.addType('subin-row-actions', {
		eventCapture: ['click'],
		createInput: function () {
			var el = document.createElement('div');
			el.className = 'subin-gjs-row-actions-trait';
			el.innerHTML = [
				'<button type="button" class="button button-small" data-subin-row-action="above">Add row above</button>',
				'<button type="button" class="button button-small" data-subin-row-action="below">Add row below</button>',
				'<button type="button" class="button button-small" data-subin-row-action="delete-empty">Delete empty row</button>',
			].join('');
			return el;
		},
		onEvent: function (props) {
			var target = props.event && props.event.target;
			var action = target && target.getAttribute ? target.getAttribute('data-subin-row-action') : '';

			if (!target || !action) {
				return;
			}

			if (props.event.preventDefault) {
				props.event.preventDefault();
			}

			if (action === 'above' || action === 'below') {
				addRowNear(props.component, action);
			} else if (action === 'delete-empty') {
				deleteRowIfEmpty(props.component);
			}
		},
		onUpdate: function (props) {
			var elInput = props.elInput;
			var row = selectedRow(props.component);
			var deleteButton = elInput && elInput.querySelector('[data-subin-row-action="delete-empty"]');
			var children = row && row.components ? row.components() : null;

			if (deleteButton) {
				deleteButton.disabled = !!(children && children.length);
			}
		},
	});

	traitManager.addType('subin-background-media', {
		eventCapture: ['click', 'change'],
		createInput: function () {
			var el = document.createElement('div');
			el.className = 'subin-gjs-media-trait';
			renderBackgroundMediaTrait(el, {});
			return el;
		},
		onEvent: function (props) {
			var elInput = props.elInput;
			var component = props.component;
			var event = props.event || {};
			var target = event.target;

			if (!elInput || !component || !target) {
				return;
			}

			if (target.closest && target.closest('[data-subin-bg-select]')) {
				if (event.preventDefault) {
					event.preventDefault();
				}
				openBackgroundMediaFrame(component, elInput);
				return;
			}

			if (target.closest && target.closest('[data-subin-bg-remove]')) {
				if (event.preventDefault) {
					event.preventDefault();
				}
				removeBackgroundMedia(component);
				renderBackgroundMediaTrait(elInput, component.getAttributes ? component.getAttributes() : {});
				return;
			}

			if (target.matches && target.matches('[data-subin-bg-setting]')) {
				setBackgroundMediaSetting(component, target.getAttribute('data-subin-bg-setting'), target.value);
			}
		},
		onUpdate: function (props) {
			var elInput = props.elInput;
			var component = props.component;

			if (!elInput || traitInputContainsFocus(elInput)) {
				return;
			}

			renderBackgroundMediaTrait(elInput, component && component.getAttributes ? component.getAttributes() : {});
		},
	});
}

function buildSubmissionInboxStyleManager() {
	return {
		sectors: [
			styleSector('subin-size', 'Size', true, [
				'width',
				'max-width',
				'min-height',
				'height',
			], [
					sizeProperty('width', 'Width'),
					sizeProperty('max-width', 'Max width'),
					sizeProperty('min-height', 'Min height'),
					sizeProperty('height', 'Height'),
			]),
			styleSector('subin-spacing', 'Spacing', true, [
				'margin',
				'padding',
				'gap',
				'align-items',
				'justify-content',
			], [
					spacingProperty('margin', 'Margin'),
					spacingProperty('padding', 'Padding'),
					sizeProperty('gap', 'Gap'),
					{
						property: 'align-items',
						name: 'Vertical alignment',
						type: 'select',
						defaults: 'flex-start',
						options: [
							{ id: 'flex-start', label: 'Top' },
							{ id: 'center', label: 'Middle' },
							{ id: 'flex-end', label: 'Bottom' },
							{ id: 'stretch', label: 'Stretch' },
						],
					},
					{
						property: 'justify-content',
						name: 'Horizontal alignment',
						type: 'select',
						defaults: 'flex-start',
						options: [
							{ id: 'flex-start', label: 'Left' },
							{ id: 'center', label: 'Center' },
							{ id: 'flex-end', label: 'Right' },
							{ id: 'space-between', label: 'Spread' },
						],
					},
			]),
			styleSector('subin-typography', 'Typography', true, [
				'font-size',
				'font-weight',
				'line-height',
				'text-align',
				'color',
			], [
					{
						property: 'font-size',
						name: 'Font size',
						type: 'integer',
						units: ['px', 'rem', 'em'],
						min: 0,
					},
					{
						property: 'font-weight',
						name: 'Font weight',
						type: 'select',
						defaults: '400',
						options: [
							{ id: '300', label: 'Light' },
							{ id: '400', label: 'Regular' },
							{ id: '500', label: 'Medium' },
							{ id: '600', label: 'Semibold' },
							{ id: '700', label: 'Bold' },
							{ id: '800', label: 'Extra bold' },
						],
					},
					{
						property: 'line-height',
						name: 'Line height',
						type: 'number',
						min: 1,
						max: 2.2,
						step: 0.1,
					},
					{
						property: 'text-align',
						name: 'Text align',
						type: 'radio',
						defaults: 'left',
						options: [
							{ id: 'left', label: 'Left' },
							{ id: 'center', label: 'Center' },
							{ id: 'right', label: 'Right' },
						],
					},
					{
						property: 'color',
						name: 'Text color',
						type: 'color',
					},
			]),
			styleSector('subin-background', 'Background', false, [
				'background-color',
			], [
					{
						property: 'background-color',
						name: 'Background color',
						type: 'color',
					},
			]),
			styleSector('subin-border', 'Border & Radius', false, [
				'border-width',
				'border-style',
				'border-color',
				'border-radius',
			], [
					{
						property: 'border-width',
						name: 'Border width',
						type: 'integer',
						units: ['px'],
						min: 0,
					},
					{
						property: 'border-style',
						name: 'Border style',
						type: 'select',
						defaults: 'solid',
						options: [
							{ id: 'none', label: 'None' },
							{ id: 'solid', label: 'Solid' },
							{ id: 'dashed', label: 'Dashed' },
							{ id: 'dotted', label: 'Dotted' },
						],
					},
					{
						property: 'border-color',
						name: 'Border color',
						type: 'color',
					},
					{
						property: 'border-radius',
						name: 'Border radius',
						type: 'integer',
						units: ['px', '%'],
						min: 0,
					},
			]),
			styleSector('subin-shadow', 'Shadow', false, [
				'box-shadow',
			], [
					{
						property: 'box-shadow',
						name: 'Shadow',
						type: 'select',
						defaults: 'none',
						options: [
							{ id: 'none', label: 'None' },
							{ id: '0 4px 12px rgba(15, 23, 42, 0.12)', label: 'Subtle' },
							{ id: '0 10px 24px rgba(15, 23, 42, 0.16)', label: 'Raised' },
							{ id: '0 18px 36px rgba(15, 23, 42, 0.22)', label: 'Strong' },
						],
					},
			]),
		],
	};
}

function styleSector(id, label, open, buildProps, properties) {
	return {
		id: id,
		name: label,
		open: open,
		buildProps: buildProps,
		properties: properties.map(function (property) {
			if (property.property && !property.id) {
				property.id = property.property;
			}

			return property;
		}),
	};
}

function sizeProperty(property, label) {
	return {
		property: property,
		name: label,
		type: 'integer',
		units: ['px', '%', 'rem', 'em'],
		min: 0,
	};
}

function spacingProperty(property, label) {
	return {
		property: property,
		name: label,
		type: 'integer',
		units: ['px', 'rem', 'em'],
	};
}

function subinFieldStyleProps() {
	return commonBoxStyleProps().concat(typographyStyleProps());
}

function subinFlowResizableOptions() {
	return {
		tl: false,
		tc: false,
		tr: false,
		cl: true,
		cr: true,
		bl: false,
		bc: true,
		br: true,
		minDim: 32,
		keyWidth: 'width',
		keyHeight: 'min-height',
	};
}

function subinButtonStyleProps() {
	return commonBoxStyleProps().concat(typographyStyleProps());
}

function subinContentStyleProps(componentName) {
	if (componentName === 'spacer') {
		return ['height', 'min-height', 'margin'];
	}

	if (componentName === 'divider') {
		return ['margin', 'width', 'max-width', 'border-color', 'border-width'];
	}

	if (componentName === 'image-block') {
		return ['width', 'max-width', 'height', 'margin', 'padding', 'background-color', 'border-width', 'border-style', 'border-color', 'border-radius', 'box-shadow'];
	}

	return commonBoxStyleProps().concat(typographyStyleProps());
}

function subinWrapperStyleProps() {
	return commonBoxStyleProps();
}

function subinRowStyleProps() {
	return [
		'min-height',
		'margin',
		'padding',
		'gap',
		'align-items',
		'justify-content',
		'background-color',
		'border-width',
		'border-style',
		'border-color',
		'border-radius',
	];
}

function backgroundMediaTrait() {
	return {
		type: 'subin-background-media',
		name: 'subin-background-media',
		label: 'Background image',
	};
}

function withBackgroundMediaTrait(traits) {
	var current = normalizeTraitList(traits);
	var hasTrait = current.some(function (trait) {
		return trait && trait.type === 'subin-background-media';
	});

	if (!hasTrait) {
		current.push(backgroundMediaTrait());
	}

	return current;
}

function normalizeTraitList(traits) {
	if (Array.isArray(traits)) {
		return traits.slice();
	}

	if (traits && Array.isArray(traits.models)) {
		return traits.models.map(function (trait) {
			return trait && trait.attributes ? Object.assign({}, trait.attributes) : trait;
		});
	}

	return [];
}

function subinFieldTraits(attributes) {
	var fieldType = attributes['data-subin-field-type'] || 'text';
	var traits;

	if (fieldType === 'hidden') {
		return [
			{
				type: 'subin-readonly',
				name: 'data-subin-field-type',
				label: 'Field type',
			},
			textTrait('data-subin-field-key', 'Field key'),
			textTrait('data-subin-default-value', 'Default value'),
		];
	}

	if (fieldType === 'consent') {
		return [
			{
				type: 'subin-readonly',
				name: 'data-subin-field-type',
				label: 'Field type',
			},
			textTrait('data-subin-consent-text', 'Consent text'),
			textTrait('data-subin-help-text', 'Help/privacy text'),
			{
				type: 'checkbox',
				name: 'data-subin-required',
				label: 'Required',
				valueTrue: '1',
				valueFalse: '0',
			},
			fieldInnerStyleTrait(),
		];
	}

	traits = [
		{
			type: 'subin-readonly',
			name: 'data-subin-field-type',
			label: 'Field type',
		},
		textTrait('data-subin-label', 'Label'),
	];

	if (supportsPlaceholderTrait(fieldType)) {
		traits.push(textTrait('data-subin-placeholder', 'Placeholder'));
	}

	if (supportsHelpTextTrait(fieldType)) {
		traits.push(textTrait('data-subin-help-text', 'Help text'));
	}

	traits.push({
		type: 'checkbox',
		name: 'data-subin-required',
		label: 'Required',
		valueTrue: '1',
		valueFalse: '0',
	});
	traits.push(textTrait('data-subin-required-message', 'Required error message'));

	if (isChoiceField(fieldType)) {
		traits.push({
			type: 'subin-options',
			name: 'data-subin-options',
			label: 'Options',
		});
	}

	traits.push(fieldInnerStyleTrait());

	return traits;
}

function fieldInnerStyleTrait() {
	return {
		type: 'subin-field-inner-styles',
		name: 'subin-field-inner-styles',
		label: 'Field part styles',
	};
}

function textTrait(name, label) {
	return {
		type: 'subin-text',
		name: name,
		label: label,
	};
}

function contentTextTrait(name, label) {
	return {
		type: 'subin-content-text',
		name: name,
		label: label,
	};
}

function htmlContentTrait() {
	return {
		type: 'subin-html-content',
		name: 'data-subin-html-content',
		label: 'HTML content',
	};
}

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

	if (componentName === 'html-block') {
		return [
			htmlContentTrait(),
		];
	}

	return [
		contentTextTrait('data-subin-content', contentTraitLabel(componentName)),
	];
}

function contentTraitLabel(componentName) {
	if (componentName === 'notice') {
		return 'Notice text';
	}
	if (componentName === 'privacy') {
		return 'Privacy text';
	}
	if (componentName === 'html-block') {
		return 'HTML content';
	}

	return 'Text content';
}

function scheduleTextTraitFlush(elInput, component, name) {
	if (!elInput) {
		return;
	}

	if (elInput.__subinTextTraitTimer) {
		window.clearTimeout(elInput.__subinTextTraitTimer);
	}

	elInput.__subinTextTraitTimer = window.setTimeout(function () {
		flushTextTraitValue(elInput, component, name);
	}, 300);
}

function flushTextTraitValue(elInput, component, name) {
	var value = elInput ? elInput.value : '';

	if (elInput && elInput.__subinTextTraitTimer) {
		window.clearTimeout(elInput.__subinTextTraitTimer);
		elInput.__subinTextTraitTimer = null;
	}

	addComponentAttribute(component, name, value);
}

function flushChoiceOptionsAttribute(elInput, component) {
	if (elInput && elInput.__subinOptionsTraitTimer) {
		window.clearTimeout(elInput.__subinOptionsTraitTimer);
		elInput.__subinOptionsTraitTimer = null;
	}

	setChoiceOptionsAttribute(component, readOptionsTraitInput(elInput));
}

function scheduleChoiceOptionsFlush(elInput, component) {
	if (!elInput) {
		return;
	}

	if (elInput.__subinOptionsTraitTimer) {
		window.clearTimeout(elInput.__subinOptionsTraitTimer);
	}

	elInput.__subinOptionsTraitTimer = window.setTimeout(function () {
		flushChoiceOptionsAttribute(elInput, component);
	}, 300);
}

function traitInputContainsFocus(elInput) {
	return !!(elInput && document.activeElement && elInput.contains(document.activeElement));
}

function addComponentAttribute(component, name, value) {
	var attributes = component && component.getAttributes ? component.getAttributes() : {};

	if (!component || !component.addAttributes || attributes[name] === value) {
		return false;
	}

	var next = {};
	next[name] = value;
	component.addAttributes(next);
	return true;
}

function supportsPlaceholderTrait(fieldType) {
	return ['text', 'email', 'phone', 'textarea', 'select'].indexOf(String(fieldType || '')) !== -1;
}

function supportsHelpTextTrait(fieldType) {
	return ['text', 'email', 'phone', 'date', 'textarea', 'select', 'radio', 'checkbox'].indexOf(String(fieldType || '')) !== -1;
}

function isChoiceField(fieldType) {
	return ['select', 'radio', 'checkbox'].indexOf(String(fieldType || '')) !== -1;
}

function defaultChoiceOptions() {
	return [
		{
			label: 'Option 1',
			value: 'option_1',
		},
		{
			label: 'Option 2',
			value: 'option_2',
		},
	];
}

function hasValidChoiceOptions(value) {
	var parsed;

	if (!value) {
		return false;
	}

	if (Array.isArray(value)) {
		return normalizeChoiceOptions(value).length > 0;
	}

	try {
		parsed = JSON.parse(String(value));
	} catch (error) {
		return false;
	}

	return Array.isArray(parsed) && normalizeChoiceOptions(parsed).length > 0;
}

function parseChoiceOptions(value) {
	var parsed;

	if (!value) {
		return defaultChoiceOptions();
	}

	if (Array.isArray(value)) {
		return normalizeChoiceOptions(value);
	}

	try {
		parsed = JSON.parse(String(value));
	} catch (error) {
		return defaultChoiceOptions();
	}

	return normalizeChoiceOptions(parsed);
}

function normalizeChoiceOptions(options) {
	var normalized = [];

	if (!Array.isArray(options)) {
		return defaultChoiceOptions();
	}

	options.forEach(function (option, index) {
		var label;
		var value;

		if (option === null || option === undefined) {
			return;
		}

		if (typeof option === 'object' && !Array.isArray(option)) {
			label = sanitizeOptionText(option.label || '');
			value = sanitizeOptionValue(option.value || label, index);
		} else {
			label = sanitizeOptionText(option);
			value = sanitizeOptionValue(label, index);
		}

		if (!label && value) {
			label = value;
		}

		if (label && value) {
			normalized.push({
				label: label,
				value: value,
			});
		}
	});

	return normalized.length ? normalized : defaultChoiceOptions();
}
