/* global grecaptcha, jQuery */
/**
 * Refresh reCAPTCHA v2 widgets after AJAX form submissions.
 *
 * v2 tokens are single-use: after an AJAX submission the checkbox still shows as
 * solved but its token is redeemed, so the next attempt fails verification
 * ("works the first time, fails after that"). Listens for each supported form
 * plugin's post-submission signal and resets the widget(s) inside that form.
 *
 * Explicitly rendered widgets carry their widget id in `data-wpps-gr-wid`.
 * Widgets rendered by Google's own implicit scan have no retrievable id;
 * `grecaptcha.reset()` without arguments targets the first widget, which is
 * only safe when it is the sole widget on the page. Otherwise we rebuild the
 * container so wppsGrecaptchaV2Init can render a tracked widget.
 *
 * The WooCommerce checkout widget is excluded — the checkout script owns it.
 * v3 needs nothing here: it fetches a fresh token on every submit.
 */
(function () {
	function widgetsWithin(root) {
		if (!root || typeof root.querySelectorAll !== 'function') {
			root = document;
		}
		return Array.prototype.filter.call(
			root.querySelectorAll('div.wpps-g-recaptcha-v2'),
			function (el) {
				return el.id !== 'wpps-grecaptcha-woo-checkout';
			}
		);
	}

	/**
	 * Clear disable-submit unlock styles so the stylesheet lock applies again
	 * until the visitor solves the fresh challenge.
	 */
	function relockSubmits(root) {
		var form = root;
		if (root && root.nodeType === 1 && root.tagName !== 'FORM') {
			form = root.closest ? root.closest('form') : null;
		}
		if (!form || typeof form.querySelectorAll !== 'function') {
			return;
		}
		form.querySelectorAll('button, input[type="submit"], .wpps-bf-submit').forEach(function (el) {
			el.style.removeProperty('pointer-events');
			el.style.removeProperty('opacity');
		});
	}

	function rebuild(el) {
		while (el.firstChild) {
			el.removeChild(el.firstChild);
		}
		el.removeAttribute('data-wpps-grecaptcha-done');
		el.removeAttribute('data-wpps-gr-wid');
		if (typeof window.wppsGrecaptchaV2Init === 'function') {
			try {
				window.wppsGrecaptchaV2Init();
			} catch (err) {}
		}
	}

	function refresh(root) {
		if (typeof grecaptcha === 'undefined' || typeof grecaptcha.reset !== 'function') {
			return;
		}
		widgetsWithin(root).forEach(function (el) {
			var wid = el.getAttribute('data-wpps-gr-wid');
			try {
				if (wid !== null && wid !== '') {
					grecaptcha.reset(parseInt(wid, 10));
				} else if (widgetsWithin(document).length === 1) {
					grecaptcha.reset();
				} else {
					rebuild(el);
				}
			} catch (e) {
				rebuild(el);
			}
		});
		relockSubmits(root);
	}

	// Basic Forms fires both a jQuery event and a native CustomEvent — collapse duplicates.
	var lastRefreshAt = 0;
	var lastRefreshRoot = null;
	function refreshOnce(root) {
		var now = Date.now();
		if (root === lastRefreshRoot && now - lastRefreshAt < 150) {
			return;
		}
		lastRefreshRoot = root;
		lastRefreshAt = now;
		refresh(root);
	}

	// Contact Form 7: real DOM event, fires after every AJAX submission outcome.
	document.addEventListener('wpcf7submit', function (e) {
		refreshOnce(e.target);
	});

	// Basic Forms also dispatches a native CustomEvent (works even if jQuery loads late).
	document.addEventListener('wpps_bf_submit_complete', function (e) {
		refreshOnce(e.target);
	});

	function bindJqueryHandlers() {
		if (typeof jQuery === 'undefined') {
			return;
		}
		// Basic Forms (jQuery event from frontend.js).
		jQuery(document).on('wpps_bf_submit_complete', function (e) {
			refreshOnce(e.target);
		});

		// WPForms with AJAX submissions enabled.
		jQuery(document).on('wpformsAjaxSubmitFailed wpformsAjaxSubmitSuccess', function (e) {
			refreshOnce(e.target);
		});

		// Elementor Pro forms (events are jQuery-triggered on the form and bubble).
		jQuery(document).on('submit_success error', 'form.elementor-form', function () {
			refreshOnce(this);
		});

		// Fluent Forms.
		jQuery(document).on('fluentform_submission_failed fluentform_submission_success', function (e) {
			refreshOnce(e.target);
		});

		// Gravity Forms (AJAX mode): fires after the replaced form markup lands.
		// The fresh container is re-rendered by the v2 bootstrap; only reset here.
		jQuery(document).on('gform_post_render', function (e, formId) {
			var wrapper = formId ? document.getElementById('gform_wrapper_' + formId) : null;
			if (typeof window.wppsGrecaptchaV2Init === 'function') {
				try {
					window.wppsGrecaptchaV2Init();
				} catch (err) {}
			}
			refreshOnce(wrapper || document);
		});
	}

	if (typeof jQuery !== 'undefined') {
		bindJqueryHandlers();
	} else {
		document.addEventListener('DOMContentLoaded', bindJqueryHandlers);
	}
})();
