(function () {
	'use strict';

	var submittingAttr = 'data-subin-submitting';
	var originalTextAttr = 'data-subin-original-text';
	var recaptchaReadyAttr = 'data-subin-recaptcha-ready';
	var recaptchaPendingAttr = 'data-subin-recaptcha-pending';
	var recaptchaErrorMessage = 'Could not verify the submission. Please try again.';
	var clientStartedAtProperty = '__subinClientStartedAt';
	var disabledByScriptProperty = '__subinDisabledByScript';
	var activeRequestProperty = '__subinActiveRequest';
	var requestSequenceProperty = '__subinRequestSequence';
	var recaptchaAttemptProperty = '__subinRecaptchaAttempt';
	var requiredCheckboxGroupSelector = '[data-subin-required-checkbox-group="1"]';

	function refreshConditionalLogic(form) {
		if (window.SubinFrontendLogic && typeof window.SubinFrontendLogic.initForm === 'function') {
			window.SubinFrontendLogic.initForm(form);
		}
		if (window.SubinFrontendLogic && typeof window.SubinFrontendLogic.refresh === 'function') {
			window.SubinFrontendLogic.refresh(form);
		}
	}

	function frontendMessage(key, fallback) {
		var messages = window.subinFrontend && window.subinFrontend.messages ? window.subinFrontend.messages : {};
		return messages[key] || fallback;
	}

	function submitButtons(form) {
		return Array.prototype.slice.call(form.querySelectorAll('button[type="submit"], input[type="submit"]'));
	}

	function buttonText(button) {
		return button.tagName === 'INPUT' ? button.value : button.textContent;
	}

	function setButtonText(button, text) {
		if (button.tagName === 'INPUT') {
			button.value = text;
			return;
		}

		button.textContent = text;
	}

	function formControls(form) {
		return Array.prototype.slice.call(form.querySelectorAll('button, input, select, textarea'));
	}

	function disableControl(control) {
		if (!control.disabled) {
			control[disabledByScriptProperty] = true;
			control.disabled = true;
		}
	}

	function restoreControls(form) {
		formControls(form).forEach(function (control) {
			if (control[disabledByScriptProperty]) {
				control.disabled = false;
				delete control[disabledByScriptProperty];
			}
		});
	}

	function freezeFormControls(form) {
		formControls(form).forEach(function (control) {
			if (control.type !== 'hidden') {
				disableControl(control);
			}
		});
	}

	function setSubmitting(form) {
		if (form.getAttribute(submittingAttr) === '1') {
			return false;
		}

		form.setAttribute(submittingAttr, '1');
		form.classList.add('subin-form--submitting');
		form.classList.remove('subin-form--success-locked');
		form.setAttribute('aria-busy', 'true');

		submitButtons(form).forEach(function (button) {
			if (!button.hasAttribute(originalTextAttr)) {
				button.setAttribute(originalTextAttr, buttonText(button));
			}
			disableControl(button);
			setButtonText(button, frontendMessage('sending', 'Sending...'));
		});

		return true;
	}

	function clearSubmitting(form) {
		form.removeAttribute(submittingAttr);
		form.classList.remove('subin-form--submitting');
		form.classList.remove('subin-form--success-locked');
		form.removeAttribute('aria-busy');
		restoreControls(form);

		submitButtons(form).forEach(function (button) {
			if (button.hasAttribute(originalTextAttr)) {
				setButtonText(button, button.getAttribute(originalTextAttr));
				button.removeAttribute(originalTextAttr);
			}
		});
	}

	function lockSuccessForm(form) {
		clearSubmitting(form);
		form.setAttribute(submittingAttr, '1');
		form.classList.add('subin-form--success-locked');
		freezeFormControls(form);
	}

	function formHasSuccess(form) {
		var message = form.querySelector('.subin-form-message--success');
		return !!(message && message.textContent.trim() !== '');
	}

	function messageElement(form) {
		return form.querySelector('.subin-form-message');
	}

	function setMessage(form, status, text) {
		var message = messageElement(form);
		if (!message) {
			return null;
		}

		message.classList.remove('subin-form-message--success', 'subin-form-message--error');
		if (status) {
			message.classList.add('subin-form-message--' + status);
		}
		message.setAttribute('role', status === 'error' ? 'alert' : 'status');
		message.setAttribute('aria-live', status === 'error' ? 'assertive' : 'polite');
		message.setAttribute('aria-atomic', 'true');
		message.textContent = text || '';
		return message;
	}

	function descriptionTokens(element) {
		return (element.getAttribute('aria-describedby') || '').split(/\s+/).filter(function (token) {
			return token !== '';
		});
	}

	function addDescription(element, id) {
		var tokens = descriptionTokens(element);
		if (tokens.indexOf(id) === -1) {
			tokens.push(id);
		}
		element.setAttribute('aria-describedby', tokens.join(' '));
	}

	function removeDescription(element, id) {
		var tokens = descriptionTokens(element).filter(function (token) {
			return token !== id;
		});
		if (tokens.length) {
			element.setAttribute('aria-describedby', tokens.join(' '));
		} else {
			element.removeAttribute('aria-describedby');
		}
	}

	function groupControls(group) {
		return Array.prototype.slice.call(group.querySelectorAll('fieldset, input, select, textarea'));
	}

	function clearFieldErrors(group) {
		if (!group) {
			return;
		}

		var errors = Array.prototype.slice.call(group.querySelectorAll('.subin-field-error--ajax, .subin-field-error--server'));
		var controls = groupControls(group);
		errors.forEach(function (error) {
			if (error.id) {
				controls.forEach(function (control) {
					removeDescription(control, error.id);
				});
			}
			if (error.parentNode) {
				error.parentNode.removeChild(error);
			}
		});

		group.classList.remove('subin-field--error', 'is-error');
		controls.forEach(function (control) {
			control.removeAttribute('aria-invalid');
		});
	}

	function clearAjaxErrors(form) {
		var groups = [];
		Array.prototype.slice.call(form.querySelectorAll('.subin-field-error--ajax, .subin-field-error--server')).forEach(function (error) {
			var group = typeof error.closest === 'function' ? error.closest('[data-subin-field-key]') : error.parentNode;
			if (group && groups.indexOf(group) === -1) {
				groups.push(group);
			}
		});
		groups.forEach(clearFieldErrors);

		Array.prototype.slice.call(form.querySelectorAll('.subin-field--error, .is-error')).forEach(function (field) {
			field.classList.remove('subin-field--error', 'is-error');
		});

		Array.prototype.slice.call(form.querySelectorAll('[aria-invalid="true"]')).forEach(function (input) {
			input.removeAttribute('aria-invalid');
		});
	}

	function fieldGroupsByKey(form, key) {
		return Array.prototype.slice.call(form.querySelectorAll('[data-subin-field-key]')).filter(function (node) {
			var part = node.getAttribute('data-subin-part');
			return node.getAttribute('data-subin-field-key') === key && (part === 'field_group' || node.classList.contains('subin-field') || node.classList.contains('subin-field-group'));
		});
	}

	function applyAjaxErrors(form, errors) {
		if (!errors || typeof errors !== 'object') {
			return null;
		}

		var firstInvalid = null;
		Object.keys(errors).forEach(function (key) {
			var groups = fieldGroupsByKey(form, key);
			groups.forEach(function (group, groupIndex) {
				group.classList.add(group.classList.contains('subin-field-group') ? 'is-error' : 'subin-field--error');
				var error = document.createElement('p');
				error.className = 'subin-field-error subin-field-error--ajax';
				error.id = (form.id || form.getAttribute('data-subin-instance') || 'subin-form') +
					'-' + String(key).replace(/[^A-Za-z0-9_-]+/g, '-') +
					'-ajax-error-' + String(groupIndex + 1);
				error.textContent = errors[key];
				groupControls(group).forEach(function (control) {
					control.setAttribute('aria-invalid', 'true');
					addDescription(control, error.id);
					if (!firstInvalid && /^(INPUT|SELECT|TEXTAREA)$/.test(control.tagName)) {
						firstInvalid = control;
					}
				});
				group.appendChild(error);
			});
		});

		return firstInvalid;
	}

	function focusElement(element) {
		if (!element || typeof element.focus !== 'function') {
			return;
		}
		try {
			element.focus({ preventScroll: false });
		} catch (error) {
			element.focus();
		}
	}

	function focusFeedback(form, invalidControl) {
		focusElement(invalidControl || messageElement(form));
	}

	function newSubmissionId() {
		if (window.crypto && typeof window.crypto.randomUUID === 'function') {
			return window.crypto.randomUUID();
		}

		if (window.crypto && typeof window.crypto.getRandomValues === 'function') {
			var bytes = new Uint8Array(16);
			window.crypto.getRandomValues(bytes);
			return Array.prototype.map.call(bytes, function (byte) {
				return byte.toString(16).padStart(2, '0');
			}).join('');
		}

		return String(Date.now()) + '-' + Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2);
	}

	function ensureSubmissionId(form) {
		var input = form.querySelector('[name="subin_submission_id"]');
		if (!input) {
			input = document.createElement('input');
			input.type = 'hidden';
			input.name = 'subin_submission_id';
			form.appendChild(input);
		}

		if (!/^[A-Za-z0-9._:-]{16,128}$/.test(input.value || '')) {
			input.value = newSubmissionId();
		}

		return input.value;
	}

	function nextRequestId(form) {
		form[requestSequenceProperty] = (form[requestSequenceProperty] || 0) + 1;
		return form[requestSequenceProperty];
	}

	function isActiveRequest(form, request) {
		return form[activeRequestProperty] === request && !request.cancelled;
	}

	function finishActiveRequest(form, request) {
		if (form[activeRequestProperty] === request) {
			form[activeRequestProperty] = null;
		}
	}

	function cancelActiveRequest(form) {
		var request = form[activeRequestProperty];
		if (!request) {
			return;
		}

		request.cancelled = true;
		if (request.timer !== null) {
			window.clearTimeout(request.timer);
		}
		if (request.controller && typeof request.controller.abort === 'function') {
			request.controller.abort();
		}
		form[activeRequestProperty] = null;
	}

	function invalidResponseError() {
		var error = new Error('subin_invalid_response');
		error.subinInvalidResponse = true;
		return error;
	}

	function parseResponsePayload(response) {
		if (!response || typeof response.json !== 'function') {
			return Promise.reject(invalidResponseError());
		}

		return response.json().then(function (payload) {
			if (!payload || typeof payload !== 'object' || !payload.result || typeof payload.result !== 'object') {
				throw invalidResponseError();
			}
			return payload;
		}, function () {
			throw invalidResponseError();
		});
	}

	function submitAjax(form) {
		refreshConditionalLogic(form);
		if (!validateRequiredCheckboxGroups(form, true)) {
			return true;
		}

		var restUrl = form.getAttribute('data-subin-rest-url');
		if (!restUrl || !window.fetch || !window.FormData) {
			return false;
		}

		if (!setSubmitting(form)) {
			return true;
		}

		clearAjaxErrors(form);
		setMessage(form, '', '');

		ensureSubmissionId(form);
		var request = {
			id: nextRequestId(form),
			timer: null,
			controller: null,
			cancelled: false
		};
		form[activeRequestProperty] = request;

		request.timer = window.setTimeout(function () {
			request.timer = null;
			if (!isActiveRequest(form, request)) {
				return;
			}

			Promise.resolve().then(function () {
				refreshConditionalLogic(form);
				var nativeValid = typeof form.checkValidity !== 'function' || form.checkValidity();
				if (!validateRequiredCheckboxGroups(form, true) || !nativeValid) {
					request.cancelled = true;
					finishActiveRequest(form, request);
					clearRecaptchaToken(form);
					clearSubmitting(form);
					if (!nativeValid && typeof form.reportValidity === 'function') {
						form.reportValidity();
					}
					throw new Error('subin_invalid_form');
				}

				var formData = new window.FormData(form);
				formData.set('subin_source_url', cleanSourceUrl(window.location.href));
				freezeFormControls(form);

				var options = {
					method: 'POST',
					body: formData,
					credentials: 'same-origin'
				};
				if (typeof window.AbortController === 'function') {
					request.controller = new window.AbortController();
					options.signal = request.controller.signal;
				}

				return window.fetch(restUrl, options);
			}).then(parseResponsePayload).then(function (payload) {
				if (!isActiveRequest(form, request)) {
					return;
				}
				finishActiveRequest(form, request);
				clearRecaptchaToken(form);
				var result = payload && payload.result ? payload.result : {};
				var status = result.status === 'success' ? 'success' : 'error';
				setMessage(
					form,
					status,
					result.message || frontendMessage('invalidResponse', 'The server returned an unexpected response. Please try again.')
				);

				if (status === 'success') {
					lockSuccessForm(form);
					focusFeedback(form);
					return;
				}

				var invalidControl = applyAjaxErrors(form, result.errors || {});
				clearSubmitting(form);
				focusFeedback(form, invalidControl);
			}).catch(function (error) {
				if (!isActiveRequest(form, request)) {
					return;
				}
				finishActiveRequest(form, request);
				clearRecaptchaToken(form);
				var message = error && error.subinInvalidResponse ?
					frontendMessage('invalidResponse', 'The server returned an unexpected response. Please try again.') :
					frontendMessage('networkError', 'Your submission could not be sent. Please check your connection and try again.');
				setMessage(form, 'error', message);
				clearSubmitting(form);
				focusFeedback(form);
			});
		}, ajaxSubmitDelay(form));

		return true;
	}

	function recaptchaConfig() {
		return window.subinFrontend && window.subinFrontend.recaptcha ? window.subinFrontend.recaptcha : {};
	}

	function recaptchaEnabled() {
		var config = recaptchaConfig();
		return !!(config.enabled && config.siteKey);
	}

	function recaptchaAction() {
		return recaptchaConfig().action || 'submission_inbox_form';
	}

	function setHiddenValue(form, name, value) {
		var input = form.querySelector('[name="' + name + '"]');
		if (!input) {
			input = document.createElement('input');
			input.type = 'hidden';
			input.name = name;
			form.appendChild(input);
		}
		input.value = value;
	}

	function clearRecaptchaToken(form) {
		form.removeAttribute(recaptchaReadyAttr);
		setHiddenValue(form, 'subin_recaptcha_token', '');
	}

	function executeRecaptcha(form) {
		var config = recaptchaConfig();

		return new Promise(function (resolve, reject) {
			if (!window.grecaptcha || !window.grecaptcha.ready || !window.grecaptcha.execute) {
				reject(new Error('recaptcha_unavailable'));
				return;
			}

			window.grecaptcha.ready(function () {
				window.grecaptcha.execute(config.siteKey, { action: recaptchaAction() }).then(function (token) {
					if (!token) {
						reject(new Error('recaptcha_empty_token'));
						return;
					}
					setHiddenValue(form, 'subin_recaptcha_token', token);
					setHiddenValue(form, 'subin_recaptcha_action', recaptchaAction());
					form.setAttribute(recaptchaReadyAttr, '1');
					resolve();
				}).catch(function () {
					reject(new Error('recaptcha_execute_failed'));
				});
			});
		});
	}

	function showRecaptchaError(form) {
		var config = recaptchaConfig();
		setMessage(form, 'error', config.errorMessage || recaptchaErrorMessage);
		focusFeedback(form);
	}

	function syncRequiredCheckboxGroup(group) {
		if (!group || typeof group.querySelectorAll !== 'function') {
			return;
		}

		var checkboxes = Array.prototype.slice.call(group.querySelectorAll('input[type="checkbox"]'));
		if (!checkboxes.length) {
			return;
		}

		var enabledCheckboxes = checkboxes.filter(function (checkbox) {
			return !checkbox.disabled;
		});
		var hasSelection = enabledCheckboxes.some(function (checkbox) {
			return checkbox.checked;
		});
		checkboxes.forEach(function (checkbox) {
			if (typeof checkbox.setCustomValidity === 'function') {
				checkbox.setCustomValidity('');
			}
		});

		var fieldGroup = typeof group.closest === 'function' ? group.closest('[data-subin-field-key]') : null;
		var hasRenderedError = fieldGroup && fieldGroup.querySelector('.subin-field-error--ajax, .subin-field-error--server');
		if (!hasRenderedError && typeof group.removeAttribute === 'function') {
			group.removeAttribute('aria-invalid');
		}

		var validationInput = enabledCheckboxes[0] || null;
		if (!hasSelection && validationInput && typeof validationInput.setCustomValidity === 'function') {
			validationInput.setCustomValidity(
				group.getAttribute('data-subin-required-message') || 'Please select at least one option.'
			);
		}

		return {
			valid: !validationInput || hasSelection,
			input: validationInput
		};
	}

	function syncRequiredCheckboxGroups(root) {
		if (!root || typeof root.querySelectorAll !== 'function') {
			return;
		}

		Array.prototype.slice.call(root.querySelectorAll(requiredCheckboxGroupSelector)).forEach(function (group) {
			syncRequiredCheckboxGroup(group);
		});
	}

	function validateRequiredCheckboxGroups(form, report) {
		if (!form || typeof form.querySelectorAll !== 'function') {
			return true;
		}

		var firstInvalidInput = null;
		var valid = true;
		Array.prototype.slice.call(form.querySelectorAll(requiredCheckboxGroupSelector)).forEach(function (group) {
			var state = syncRequiredCheckboxGroup(group);
			if (!state || state.valid) {
				return;
			}

			valid = false;
			if (typeof group.setAttribute === 'function') {
				group.setAttribute('aria-invalid', 'true');
			}
			if (!firstInvalidInput) {
				firstInvalidInput = state.input;
			}
		});

		if (!valid && report && firstInvalidInput && typeof firstInvalidInput.reportValidity === 'function') {
			firstInvalidInput.reportValidity();
		}

		return valid;
	}

	function clientClockNow() {
		if (window.performance && typeof window.performance.now === 'function') {
			return window.performance.now();
		}

		return Date.now();
	}

	function markFormReady(form) {
		if (typeof form[clientStartedAtProperty] !== 'number') {
			form[clientStartedAtProperty] = clientClockNow();
		}
	}

	function ajaxSubmitDelay(form) {
		markFormReady(form);
		var elapsed = clientClockNow() - form[clientStartedAtProperty];

		return elapsed >= 2000 ? 0 : Math.max(0, 2000 - elapsed);
	}

	function cleanSourceUrl(url) {
		try {
			var parsed = new URL(url);
			parsed.searchParams.delete('subin_form_result');
			return parsed.toString();
		} catch (error) {
			return url;
		}
	}

	syncRequiredCheckboxGroups(document);

	document.addEventListener('change', function (event) {
		var input = event.target;
		if (!input || typeof input.closest !== 'function') {
			return;
		}

		var fieldGroup = input.closest('[data-subin-field-key]');
		if (fieldGroup && fieldGroup.querySelector('.subin-field-error--ajax, .subin-field-error--server')) {
			clearFieldErrors(fieldGroup);
		}

		if (input.type !== 'checkbox') {
			return;
		}
		var group = input.closest(requiredCheckboxGroupSelector);
		if (group) {
			syncRequiredCheckboxGroup(group);
		}
	});

	document.addEventListener('reset', function (event) {
		var form = event.target && event.target.classList && event.target.classList.contains('subin-form') ? event.target : null;
		if (!form) {
			return;
		}

		cancelActiveRequest(form);
		form[recaptchaAttemptProperty] = (form[recaptchaAttemptProperty] || 0) + 1;
		form.removeAttribute(recaptchaPendingAttr);
		form.removeAttribute(recaptchaReadyAttr);
		clearAjaxErrors(form);
		setMessage(form, '', '');
		clearSubmitting(form);

		window.setTimeout(function () {
			refreshConditionalLogic(form);
			clearRecaptchaToken(form);
			var submissionId = form.querySelector('[name="subin_submission_id"]');
			if (submissionId) {
				submissionId.value = '';
			}
			ensureSubmissionId(form);
			delete form[clientStartedAtProperty];
			markFormReady(form);
			syncRequiredCheckboxGroups(form);
		}, 0);
	});

	document.addEventListener('submit', function (event) {
		var form = event.target && event.target.closest ? event.target.closest('.subin-form') : null;
		if (!form) {
			return;
		}
		markFormReady(form);
		refreshConditionalLogic(form);

		if (!validateRequiredCheckboxGroups(form, true)) {
			event.preventDefault();
			return;
		}

		if (recaptchaEnabled() && form.getAttribute(recaptchaReadyAttr) !== '1') {
			event.preventDefault();
			if (form.getAttribute(recaptchaPendingAttr) === '1' || form.getAttribute(submittingAttr) === '1') {
				return;
			}

			form.setAttribute(recaptchaPendingAttr, '1');
			var recaptchaAttempt = (form[recaptchaAttemptProperty] || 0) + 1;
			form[recaptchaAttemptProperty] = recaptchaAttempt;
			clearAjaxErrors(form);
			setMessage(form, '', '');

			if (!setSubmitting(form)) {
				form.removeAttribute(recaptchaPendingAttr);
				return;
			}

			executeRecaptcha(form).then(function () {
				if (form[recaptchaAttemptProperty] !== recaptchaAttempt) {
					return;
				}
				form.removeAttribute(recaptchaPendingAttr);
				refreshConditionalLogic(form);
				var nativeValid = typeof form.checkValidity !== 'function' || form.checkValidity();
				if (!validateRequiredCheckboxGroups(form, true) || !nativeValid) {
					clearRecaptchaToken(form);
					clearSubmitting(form);
					if (!nativeValid && typeof form.reportValidity === 'function') {
						form.reportValidity();
					}
					return;
				}
				if (form.getAttribute('data-subin-ajax') === '1') {
					clearSubmitting(form);
					submitAjax(form);
					return;
				}
				form.submit();
			}).catch(function () {
				if (form[recaptchaAttemptProperty] !== recaptchaAttempt) {
					return;
				}
				form.removeAttribute(recaptchaPendingAttr);
				form.removeAttribute(recaptchaReadyAttr);
				showRecaptchaError(form);
				clearSubmitting(form);
			});
			return;
		}

		if (form.getAttribute('data-subin-ajax') === '1' && submitAjax(form)) {
			event.preventDefault();
			return;
		}

		if (form.getAttribute(submittingAttr) === '1') {
			event.preventDefault();
			return;
		}

		setSubmitting(form);

		window.setTimeout(function () {
			if (event.defaultPrevented) {
				clearSubmitting(form);
			}
		}, 0);
	});

	document.addEventListener('invalid', function (event) {
		var form = event.target && event.target.form && event.target.form.classList.contains('subin-form') ? event.target.form : null;
		if (form) {
			clearSubmitting(form);
		}
	}, true);

	document.addEventListener('DOMContentLoaded', function () {
		Array.prototype.slice.call(document.querySelectorAll('.subin-form')).forEach(function (form) {
			refreshConditionalLogic(form);
			markFormReady(form);
			ensureSubmissionId(form);
			syncRequiredCheckboxGroups(form);
			if (formHasSuccess(form)) {
				lockSuccessForm(form);
			}
		});
	});

	window.addEventListener('pageshow', function (event) {
		if (!event.persisted) {
			return;
		}

		Array.prototype.slice.call(document.querySelectorAll('.subin-form')).forEach(function (form) {
			refreshConditionalLogic(form);
			cancelActiveRequest(form);
			form[recaptchaAttemptProperty] = (form[recaptchaAttemptProperty] || 0) + 1;
			form.removeAttribute(recaptchaPendingAttr);
			clearRecaptchaToken(form);
			syncRequiredCheckboxGroups(form);
			if (formHasSuccess(form)) {
				lockSuccessForm(form);
			} else {
				clearSubmitting(form);
				ensureSubmissionId(form);
			}
		});
	});
})();
