(function ($) {
	'use strict';

	const settings = window.WPMDEmailEditor || {};
	const ajaxUrl = settings.ajaxUrl || window.ajaxurl || '';
	const nonces = settings.nonces || {};
	const previewNonce = nonces.preview || '';
	const sendTestNonce = nonces.sendTest || '';
	const $workspace = $('#wpmd-editor-workspace');

	if (!$workspace.length || !ajaxUrl) {
		return;
	}

	function getString(key, fallback) {
		if (settings.i18n && Object.prototype.hasOwnProperty.call(settings.i18n, key)) {
			return settings.i18n[key];
		}

		return fallback;
	}

	const state = {
		mode: $workspace.data('initial-mode') === 'visual' ? 'visual' : 'code',
		editors: {
			html: null,
			css: null,
		},
		visualReady: false,
		previewRequest: null,
		pendingValidationFocus: false,
	};

	const $form = $('#wpmd-email-template-form');
	const $subject = $('#wpmd-template-subject');
	const $heading = $('#wpmd-template-heading');
	const $htmlTextarea = $('#wpmd-template-html');
	const $cssTextarea = $('#wpmd-template-css');
	const $visualTextarea = $('#wpmd-template-html-visual');
	const $modeInput = $('#wpmd-editor-mode');
	const $tabs = $('.wpmd-editor-tab');
	const $modes = $('.wpmd-editor-mode');
	const $previewFrame = $('#wpmd-live-preview-frame');
	const $previewWrapper = $previewFrame.parent();
	const $previewOverlay = $previewWrapper.find('.wpmd-preview-overlay');
	const $localeSelect = $('#wpmd-preview-locale');
	const $statusSelect = $('#wpmd-preview-status');
	const $orderInput = $('#wpmd-preview-order');
	const $refreshButton = $('.wpmd-preview-refresh');
	const $cacheDiagnostics = $('#wpmd-cache-diagnostics');
	const $warningsPanel = $('#wpmd-preview-warnings');
	const $mergeTagSearch = $('#wpmd-merge-tag-search');
	const $mergeTagsContainer = $('#wpmd-merge-tags');
	const $validateButton = $('.wpmd-validate-button');
	const $modal = $('#wpmd-send-test-modal');
	const $modalForm = $('#wpmd-send-test-form');
	const $modalClose = $modal.find('.wpmd-modal-close');

	const debounce = window._ && typeof window._.debounce === 'function' ? window._.debounce : function (fn) {
		let timer = null;
		return function () {
			const args = arguments;
			clearTimeout(timer);
			timer = setTimeout(function () {
				fn.apply(null, args);
			}, 400);
		};
	};

	function speak(message) {
		if (window.wp && window.wp.a11y && typeof window.wp.a11y.speak === 'function') {
			window.wp.a11y.speak(message);
		} else {
			console.log(message);
		}
	}

	function initCodeEditors() {
		if (window.wp && wp.codeEditor && window.wpmdCodeEditorSettings) {
			if (!state.editors.html) {
				state.editors.html = wp.codeEditor.initialize('wpmd-template-html', window.wpmdCodeEditorSettings.html || {});
				if (state.editors.html && state.editors.html.codemirror) {
					state.editors.html.codemirror.on('change', triggerPreview);
				}
			}

			if (!state.editors.css && window.wpmdCodeEditorSettings.css) {
				state.editors.css = wp.codeEditor.initialize('wpmd-template-css', window.wpmdCodeEditorSettings.css || {});
				if (state.editors.css && state.editors.css.codemirror) {
					state.editors.css.codemirror.on('change', triggerPreview);
				}
			}
		}
	}

	function initVisualEditor() {
		if (state.visualReady || !window.wp || !wp.editor || !$('#wpmd-template-html-visual').length) {
			return;
		}

		wp.editor.initialize('wpmd-template-html-visual', {
			quicktags: true,
			tinymce: {
				height: 420,
				menubar: false,
				statusbar: true,
				plugins: 'lists,link,paste,hr',
				toolbar1: 'formatselect,bold,italic,underline,link,unlink,bullist,numlist,blockquote,hr,undo,redo',
				setup(editor) {
					editor.on('change keyup paste', triggerPreview);
				}
			},
		});

		state.visualReady = true;
	}

	function getVisualContent() {
		if (state.visualReady && window.wp && wp.editor && typeof wp.editor.getContent === 'function') {
			return wp.editor.getContent('wpmd-template-html-visual');
		}

		return $visualTextarea.val();
	}

	function syncVisualToCode() {
		if ('visual' !== state.mode) {
			return;
		}

		const content = getVisualContent();

		$htmlTextarea.val(content);
		if (state.editors.html && state.editors.html.codemirror) {
			const editor = state.editors.html.codemirror;
			if (content !== editor.getValue()) {
				editor.setValue(content);
			}
		}
	}

	function syncCodeToVisual() {
		if ('visual' !== state.mode || !state.visualReady) {
			return;
		}

		const content = state.editors.html && state.editors.html.codemirror ? state.editors.html.codemirror.getValue() : $htmlTextarea.val();
		if (typeof wp.editor.setContent === 'function') {
			wp.editor.setContent('wpmd-template-html-visual', content);
		}
	}

	function setMode(nextMode) {
		const mode = nextMode === 'visual' ? 'visual' : 'code';
		state.mode = mode;
		$modeInput.val(mode);

		$tabs.each(function () {
			const $tab = $(this);
			const isActive = $tab.data('mode') === mode;
			$tab.toggleClass('is-active', isActive);
			$tab.attr('aria-selected', isActive ? 'true' : 'false');
		});

		$modes.each(function () {
			const $panel = $(this);
			const isActive = $panel.data('mode') === mode;
			$panel.toggleClass('is-active', isActive);
			if (isActive) {
				$panel.removeAttr('aria-hidden');
			} else {
				$panel.attr('aria-hidden', 'true');
			}
		});

		if ('visual' === mode) {
			initVisualEditor();
			syncCodeToVisual();
		} else {
			syncVisualToCode();
		}
	}

	function collectTemplateData() {
		syncVisualToCode();

		const htmlEditor = state.editors.html && state.editors.html.codemirror ? state.editors.html.codemirror.getValue() : $htmlTextarea.val();
		const cssEditor = state.editors.css && state.editors.css.codemirror ? state.editors.css.codemirror.getValue() : $cssTextarea.val();

		return {
			subject: $subject.val() || '',
			heading: $heading.val() || '',
			html: htmlEditor || '',
			css: cssEditor || '',
			is_active: $('#wpmd-template-active').is(':checked') ? 1 : 0,
		};
	}

	function buildPreviewPayload(mode) {
		const templateData = collectTemplateData();

		return {
			action: 'wpmd_live_preview',
			nonce: previewNonce,
			emailId: $('#wpmd-email-type').val(),
			templateId: $('#wpmd-template-id').val(),
			locale: $localeSelect.val(),
			status: $statusSelect.val(),
			orderId: $orderInput.val(),
			mode: mode || 'html',
			template: templateData,
		};
	}

	function setPreviewLoading(isLoading, message) {
		if (isLoading) {
			$previewWrapper.addClass('is-loading');
			$previewOverlay.text(message || getString('rendering', 'Rendering…'));
		} else {
			$previewWrapper.removeClass('is-loading');
			$previewOverlay.empty();
		}
	}

	function updatePreviewIframe(html) {
		try {
			const iframeDoc = $previewFrame[0].contentWindow || $previewFrame[0].contentDocument;
			if (iframeDoc.document) {
				iframeDoc.document.open();
				iframeDoc.document.write(html || '');
				iframeDoc.document.close();
			} else {
				iframeDoc.open();
				iframeDoc.write(html || '');
				iframeDoc.close();
			}
		} catch (error) {
			console.error('Preview update failed', error);
		}
	}

	function updateCacheDiagnostics(cache) {
		if (!$cacheDiagnostics.length || !cache) {
			return;
		}

		const version = cache.version || $cacheDiagnostics.data('version') || cacheVersionFallback();
		const hits = typeof cache.hits !== 'undefined' ? cache.hits : 0;
		const misses = typeof cache.misses !== 'undefined' ? cache.misses : 0;

		const text = 'Version ' + version + ' — hits ' + hits + ' / misses ' + misses;

		$cacheDiagnostics
			.attr('data-version', version)
			.text(text);
	}

	function cacheVersionFallback() {
		const attr = $cacheDiagnostics.data('version');
		return attr || 'v1';
	}

	function handlePreviewResponse(response) {
		setPreviewLoading(false);

		if (!response || !response.success) {
			const message = response && response.data && response.data.message ? response.data.message : getString('previewError', 'Unable to render preview.');
			$previewOverlay.text(message);
			renderWarnings([]);
			return;
		}

		const data = response.data || {};
		updatePreviewIframe(data.html || '');
		updateCacheDiagnostics(data.cache);
		renderWarnings(Array.isArray(data.warnings) ? data.warnings : []);
	}

	function triggerPreview() {
		requestPreview();
	}

	const requestPreview = debounce(function () {
		setPreviewLoading(true, getString('rendering', 'Rendering…'));

		if (state.previewRequest && typeof state.previewRequest.abort === 'function') {
			state.previewRequest.abort();
		}

		state.previewRequest = $.post(ajaxUrl, buildPreviewPayload('html'), null, 'json')
			.done(handlePreviewResponse)
			.fail(function (jqXHR) {
				setPreviewLoading(false);
				const message = jqXHR.responseJSON && jqXHR.responseJSON.data && jqXHR.responseJSON.data.message
					? jqXHR.responseJSON.data.message
					: getString('previewError', 'Unable to render preview.');
				$previewOverlay.text(message);
			})
			.always(function () {
				state.previewRequest = null;
			});
	});

	function handleTabClick(event) {
		event.preventDefault();
		const nextMode = $(event.currentTarget).data('mode');
		setMode(nextMode);
	}

	function filterMergeTags() {
		const query = ($mergeTagSearch.val() || '').toLowerCase();

		$mergeTagsContainer.find('.wpmd-merge-tag-group').each(function () {
			const $group = $(this);
			let visibleCount = 0;

			$group.find('.wpmd-merge-tag').each(function () {
				const $tag = $(this);
				const text = $tag.text().toLowerCase();
				const matches = !query || text.indexOf(query) !== -1;
				$tag.closest('li').toggle(matches);
				if (matches) {
					visibleCount++;
				}
			});

			$group.toggle(visibleCount > 0);
		});
	}

	function copyMergeTag(event) {
		const tag = $(event.currentTarget).data('tag');
		if (!tag) {
			speak(getString('nothingToCopy', 'Nothing to copy.'));
			return;
		}

		const value = '{{ ' + tag + ' }}';

		if (navigator.clipboard && navigator.clipboard.writeText) {
			navigator.clipboard.writeText(value).then(function () {
				speak(getString('copySuccess', 'Merge tag copied.'));
			}).catch(function () {
				speak(getString('copyError', 'Unable to copy merge tag.'));
			});
		} else {
			const temp = document.createElement('textarea');
			temp.value = value;
			temp.setAttribute('readonly', '');
			temp.style.position = 'absolute';
			temp.style.left = '-9999px';
			document.body.appendChild(temp);
			temp.select();
			try {
				document.execCommand('copy');
				speak(getString('copySuccess', 'Merge tag copied.'));
			} catch (error) {
				speak(getString('copyError', 'Unable to copy merge tag.'));
			}
			document.body.removeChild(temp);
		}
	}

	function openModal() {
		$modal.removeAttr('hidden').addClass('is-open');
		$('body').addClass('modal-open');
	}

	function handleSendTestButtonClick(event) {
		event.preventDefault();
		event.stopPropagation();
		if (typeof event.stopImmediatePropagation === 'function') {
			event.stopImmediatePropagation(); // Prevent legacy handlers from freezing the UI.
		}
		openModal();
	}

	function closeModal() {
		$modal.attr('hidden', 'hidden').removeClass('is-open');
		$('body').removeClass('modal-open');
	}

	function handleSendTestSubmit(event) {
		event.preventDefault();

		const $submit = $modalForm.find('button[type="submit"]');
		$submit.prop('disabled', true);

		const payload = {
			action: 'wpmd_send_test',
			nonce: sendTestNonce,
			email_type: $('#wpmd-email-type').val(),
			recipient: $('#wpmd-send-test-recipient').val(),
			order_id: $('#wpmd-send-test-order').val(),
			template: collectTemplateData(),
		};

		$.post(ajaxUrl, payload, null, 'json')
			.done(function (response) {
				if (response && response.success) {
					speak(getString('sendSuccess', 'Test email sent.'));
					closeModal();
				} else {
					const message = response && response.data && response.data.message ? response.data.message : getString('sendError', 'Unable to send the test email.');
					speak(message);
				}
			})
			.fail(function (jqXHR) {
				const message = jqXHR.responseJSON && jqXHR.responseJSON.data && jqXHR.responseJSON.data.message
					? jqXHR.responseJSON.data.message
					: getString('sendError', 'Unable to send the test email.');
				speak(message);
			})
			.always(function () {
				$submit.prop('disabled', false);
			});
	}

	function initEvents() {
		$tabs.on('click', handleTabClick);
		$subject.on('input', triggerPreview);
		$heading.on('input', triggerPreview);
		$localeSelect.on('change', triggerPreview);
		$statusSelect.on('change', triggerPreview);
		$orderInput.on('input', triggerPreview);
		$refreshButton.on('click', function (event) {
			event.preventDefault();
			triggerImmediatePreview();
		});
		$mergeTagSearch.on('input', filterMergeTags);
		$mergeTagsContainer.on('click', '.wpmd-merge-tag', copyMergeTag);
		$form.on('click', '.wpmd-send-test-button', handleSendTestButtonClick);
		$modalClose.on('click', function (event) {
			event.preventDefault();
			closeModal();
		});
		$modal.on('click', function (event) {
			if ($(event.target).is('.wpmd-modal__backdrop')) {
				closeModal();
			}
		});
		$modalForm.on('submit', handleSendTestSubmit);
		$form.on('submit', syncVisualToCode);
		if ($validateButton.length) {
			$validateButton.on('click', function (event) {
				event.preventDefault();
				state.pendingValidationFocus = true;
				triggerImmediatePreview();
			});
		}
	}

	function triggerImmediatePreview() {
		setPreviewLoading(true, getString('rendering', 'Rendering…'));
		if (state.previewRequest && typeof state.previewRequest.abort === 'function') {
			state.previewRequest.abort();
		}
		state.previewRequest = $.post(ajaxUrl, buildPreviewPayload('html'), null, 'json')
			.done(handlePreviewResponse)
			.fail(function () {
				setPreviewLoading(false);
				$previewOverlay.text(getString('previewError', 'Unable to render preview.'));
			})
			.always(function () {
				state.previewRequest = null;
			});
	}

	// Initialise editors and state.
	initCodeEditors();
	setMode(state.mode);
	filterMergeTags();
	renderWarnings([]);
	initEvents();
	triggerPreview();

	function renderWarnings(warnings) {
		if (!$warningsPanel.length) {
			return;
		}

		const list = Array.isArray(warnings) ? warnings.filter(function (warning) {
			return warning && (warning.message || warning.code);
		}) : [];

		if (!list.length) {
			$warningsPanel.removeClass('has-warnings').empty();
			if (state.pendingValidationFocus) {
				speak(getString('noWarnings', 'Looks good - no validation warnings found.'));
				state.pendingValidationFocus = false;
			}
			return;
		}

		const $wrapper = $('<div />');
		$wrapper.append(
			$('<span />')
				.addClass('wpmd-preview-warnings__title')
				.text(getString('warningsTitle', 'Validation warnings'))
		);

		const $list = $('<ul />');
		list.forEach(function (warning) {
			const message = warning.message || warning.code || getString('genericWarning', 'Please review the template.');
			$list.append($('<li />').text(message));
		});
		$wrapper.append($list);

		$warningsPanel
			.addClass('has-warnings')
			.empty()
			.append($wrapper);

		if (state.pendingValidationFocus) {
			const node = $warningsPanel.get(0);
			if (node && typeof node.scrollIntoView === 'function') {
				node.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
			}
			$warningsPanel.attr('tabindex', '-1').focus();
			speak(getString('warningsAvailable', 'Validation warnings detected. Please review them below.'));
			setTimeout(function () {
				$warningsPanel.removeAttr('tabindex');
			}, 500);
			state.pendingValidationFocus = false;
		}
	}

})(jQuery);
