/**
 * Shared modal primitive for RSM Content Widgets (focus trap, ESC, scroll lock).
 *
 * @package Rsmspark_Content_Widgets
 */
(function (window, document) {
	'use strict';

	var openModals = [];

	function getFocusable(container) {
		if (!container) {
			return [];
		}

		return Array.prototype.filter.call(
			container.querySelectorAll(
				'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
			),
			function (element) {
				return element.offsetParent !== null || element === document.activeElement;
			}
		);
	}

	function onDocumentKeydown(event) {
		var state = openModals[openModals.length - 1];
		if (!state) {
			return;
		}

		if (event.key === 'Escape') {
			event.preventDefault();
			window.RsmCwModal.close(state);
			return;
		}

		if (event.key !== 'Tab' || !state.dialog) {
			return;
		}

		var focusable = getFocusable(state.dialog);
		if (!focusable.length) {
			event.preventDefault();
			return;
		}

		var first = focusable[0];
		var last = focusable[focusable.length - 1];

		if (event.shiftKey && document.activeElement === first) {
			event.preventDefault();
			last.focus();
		} else if (!event.shiftKey && document.activeElement === last) {
			event.preventDefault();
			first.focus();
		}
	}

	function bindDocumentListener() {
		if (openModals._bound) {
			return;
		}
		document.addEventListener('keydown', onDocumentKeydown);
		openModals._bound = true;
	}

	function unbindDocumentListener() {
		if (openModals.length || !openModals._bound) {
			return;
		}
		document.removeEventListener('keydown', onDocumentKeydown);
		openModals._bound = false;
	}

	function open(state) {
		if (!state || !state.modal) {
			return;
		}

		state.trigger = state.trigger || null;
		state.onOpen = typeof state.onOpen === 'function' ? state.onOpen : null;
		state.onClose = typeof state.onClose === 'function' ? state.onClose : null;

		if (state.body && state.contentHtml !== undefined) {
			state.body.innerHTML = state.contentHtml;
		}

		if (state.dialog && state.labeledBy) {
			state.dialog.setAttribute('aria-labelledby', state.labeledBy);
		} else if (state.dialog) {
			state.dialog.removeAttribute('aria-labelledby');
		}

		state.modal.removeAttribute('hidden');
		state.modal.setAttribute('aria-hidden', 'false');
		state.modal.classList.add('is-open');

		if (state.bodyClass) {
			document.body.classList.add(state.bodyClass);
		}

		openModals.push(state);
		bindDocumentListener();

		if (state.onOpen) {
			state.onOpen(state);
		}

		var focusTarget =
			(state.closeButton && state.closeButton.focus && state.closeButton) ||
			getFocusable(state.dialog)[0] ||
			state.dialog;

		if (focusTarget && focusTarget.focus) {
			window.setTimeout(function () {
				focusTarget.focus();
			}, 0);
		}
	}

	function close(state) {
		if (!state || !state.modal) {
			return;
		}

		state.modal.setAttribute('hidden', 'hidden');
		state.modal.setAttribute('aria-hidden', 'true');
		state.modal.classList.remove('is-open');

		if (state.bodyClass) {
			document.body.classList.remove(state.bodyClass);
		}

		if (state.body) {
			state.body.innerHTML = '';
		}

		openModals = openModals.filter(function (entry) {
			return entry !== state;
		});
		unbindDocumentListener();

		if (state.onClose) {
			state.onClose(state);
		}

		if (state.trigger && state.trigger.focus) {
			state.trigger.focus();
		}
	}

	window.RsmCwModal = {
		open: open,
		close: close,
		getFocusable: getFocusable,
		isOpen: function (modal) {
			return openModals.some(function (entry) {
				return entry.modal === modal;
			});
		},
	};
})(window, document);
