/* global jQuery, elementor, $e, seovaultseoElementor */

/**
 * SEOvault AI — Elementor editor panel and legacy content bridge.
 *
 * @param {Object} $ jQuery instance.
 */
(function ($) {
	'use strict';

	if (typeof seovaultseoElementor === 'undefined') {
		return;
	}

	const config = seovaultseoElementor;
	const strings = config.strings || {};
	let panel;
	let toggle;
	let saveRequest;
	let assessmentRequest;
	let observer;
	let lifecycleRegistered = false;

	function debounce(callback, wait) {
		let timeout;

		return function () {
			const context = this;
			const args = arguments;

			window.clearTimeout(timeout);
			timeout = window.setTimeout(function () {
				callback.apply(context, args);
			}, wait);
		};
	}

	function makeElement(tag, className, text) {
		const element = document.createElement(tag);

		if (className) {
			element.className = className;
		}
		if (typeof text === 'string') {
			element.textContent = text;
		}

		return element;
	}

	function addField(parent, options) {
		const wrapper = makeElement('div', 'seovault-elementor-field');
		const label = makeElement(
			'label',
			'seovault-elementor-label',
			options.label
		);
		const input = document.createElement(
			options.multiline ? 'textarea' : 'input'
		);

		label.htmlFor = options.id;
		input.id = options.id;
		input.className = 'seovault-elementor-input';
		input.value = options.value || '';
		input.placeholder = options.placeholder || '';

		if (options.multiline) {
			input.rows = options.rows || 3;
		} else {
			input.type = options.type || 'text';
		}

		if (options.limit) {
			const count = makeElement('span', 'seovault-elementor-count');
			label.appendChild(count);
			input.addEventListener('input', function () {
				updateCount(input, count, options.limit);
			});
			updateCount(input, count, options.limit);
		}

		wrapper.appendChild(label);
		wrapper.appendChild(input);
		parent.appendChild(wrapper);

		return input;
	}

	function addCheckbox(parent, id, labelText, checked) {
		const label = makeElement('label', 'seovault-elementor-checkbox');
		const input = document.createElement('input');
		const text = makeElement('span', '', labelText);

		input.type = 'checkbox';
		input.id = id;
		input.checked = Boolean(checked);
		label.appendChild(input);
		label.appendChild(text);
		parent.appendChild(label);

		return input;
	}

	function addSection(parent, title, open) {
		const details = makeElement('details', 'seovault-elementor-section');
		const summary = makeElement(
			'summary',
			'seovault-elementor-section-title',
			title
		);
		const content = makeElement(
			'div',
			'seovault-elementor-section-content'
		);

		details.open = Boolean(open);
		details.appendChild(summary);
		details.appendChild(content);
		parent.appendChild(details);

		return content;
	}

	function updateCount(input, count, limits) {
		const length = input.value.length;
		const idealMin = Number(limits.ideal_min || 0);
		const idealMax = Number(limits.ideal_max || 0);
		const maximum = Number(limits.max || idealMax);
		let status = 'okay';

		if (length < idealMin || length > maximum) {
			status = 'bad';
		} else if (length <= idealMax) {
			status = 'good';
		}

		count.className =
			'seovault-elementor-count seovault-elementor-status-' + status;
		count.textContent = length + ' / ' + idealMin + '–' + idealMax;
	}

	function buildPanel() {
		if (panel) {
			return panel;
		}

		const fields = config.fields || {};
		const header = makeElement('header', 'seovault-elementor-header');
		const close = makeElement(
			'button',
			'seovault-elementor-close',
			'‹ ' + (strings.closePanel || 'Back to Elementor')
		);
		const title = makeElement(
			'strong',
			'seovault-elementor-brand',
			strings.panelTitle || 'SEOvault AI'
		);
		const body = makeElement('div', 'seovault-elementor-body');
		const footer = makeElement('footer', 'seovault-elementor-footer');
		const save = makeElement(
			'button',
			'seovault-elementor-save',
			strings.save || 'Save SEO settings'
		);
		const status = makeElement('span', 'seovault-elementor-save-status');

		panel = makeElement('aside', 'seovault-elementor-panel');
		panel.id = 'seovault-elementor-panel';
		panel.hidden = true;
		panel.setAttribute('aria-label', strings.panelTitle || 'SEOvault AI');

		close.type = 'button';
		close.addEventListener('click', function () {
			setPanelOpen(false);
		});
		header.appendChild(close);
		header.appendChild(title);

		const search = addSection(
			body,
			strings.searchAppearance || 'Search appearance',
			true
		);
		addField(search, {
			id: 'seovault-elementor-seo-title',
			label: strings.seoTitle || 'SEO title',
			value: fields.seoTitle,
			placeholder: config.autoTitle || config.postTitle || '',
			limit: config.titleLimits,
		});
		addField(search, {
			id: 'seovault-elementor-seo-description',
			label: strings.seoDescription || 'SEO description',
			value: fields.seoDescription,
			placeholder: config.autoDescription || '',
			multiline: true,
			limit: config.descriptionLimits,
		});
		addField(search, {
			id: 'seovault-elementor-focus-keyword',
			label: strings.focusKeyword || 'Focus keyword',
			value: fields.focusKeyword,
		});
		addField(search, {
			id: 'seovault-elementor-canonical-url',
			label: strings.canonicalUrl || 'Canonical URL',
			value: fields.canonicalUrl,
			placeholder: config.permalink || '',
			type: 'url',
		});

		const robots = addSection(body, strings.robots || 'Robots', false);
		addCheckbox(
			robots,
			'seovault-elementor-noindex',
			strings.noindex || 'Noindex this page',
			fields.noindex
		);
		addCheckbox(
			robots,
			'seovault-elementor-nofollow',
			strings.nofollow || 'Nofollow links on this page',
			fields.nofollow
		);

		const social = addSection(
			body,
			strings.social || 'Social sharing',
			false
		);
		addField(social, {
			id: 'seovault-elementor-og-title',
			label: strings.ogTitle || 'Social title',
			value: fields.ogTitle,
			placeholder: fields.seoTitle || config.autoTitle || '',
		});
		addField(social, {
			id: 'seovault-elementor-og-description',
			label: strings.ogDescription || 'Social description',
			value: fields.ogDescription,
			placeholder: fields.seoDescription || config.autoDescription || '',
			multiline: true,
		});
		addField(social, {
			id: 'seovault-elementor-og-image',
			label: strings.ogImage || 'Social image URL',
			value: fields.ogImage,
			type: 'url',
		});

		const assessment = addSection(
			body,
			strings.assessment || 'Live SEO checks',
			true
		);
		const assessmentStatus = makeElement(
			'div',
			'seovault-elementor-assessment-status',
			strings.loading || 'Checking live content…'
		);
		const wordCount = makeElement('div', 'seovault-elementor-word-count');
		const checks = makeElement('ul', 'seovault-elementor-checks');

		assessmentStatus.id = 'seovault-elementor-assessment-status';
		wordCount.id = 'seovault-elementor-word-count';
		checks.id = 'seovault-elementor-checks';
		assessment.appendChild(assessmentStatus);
		assessment.appendChild(wordCount);
		if (config.isV4Atomic) {
			assessment.appendChild(
				makeElement(
					'div',
					'seovault-elementor-v4-badge',
					strings.v4Active || 'Atomic Editor content sync active'
				)
			);
		}
		assessment.appendChild(checks);

		save.type = 'button';
		save.addEventListener('click', saveFields);
		status.id = 'seovault-elementor-save-status';
		footer.appendChild(save);
		footer.appendChild(status);

		panel.appendChild(header);
		panel.appendChild(body);
		panel.appendChild(footer);
		document.body.appendChild(panel);

		panel.addEventListener('input', scheduleAssessment);
		panel.addEventListener('change', scheduleAssessment);

		return panel;
	}

	function mountToggle() {
		if (toggle && document.body.contains(toggle)) {
			return;
		}

		const host =
			document.querySelector('#elementor-panel-header-controls') ||
			document.querySelector('#elementor-panel-header') ||
			document.querySelector('[data-testid="editor-header"]');

		toggle = makeElement('button', 'seovault-elementor-toggle', 'SV');
		toggle.id = 'seovault-elementor-toggle';
		toggle.type = 'button';
		toggle.title = strings.openPanel || 'Open SEOvault AI';
		toggle.setAttribute('aria-controls', 'seovault-elementor-panel');
		toggle.setAttribute('aria-expanded', 'false');
		toggle.addEventListener('click', function () {
			setPanelOpen(!panel || panel.hidden);
		});

		if (host) {
			host.appendChild(toggle);
		} else {
			toggle.classList.add('seovault-elementor-toggle-fallback');
			document.body.appendChild(toggle);
		}
	}

	function setPanelOpen(open) {
		buildPanel();
		panel.hidden = !open;
		document.body.classList.toggle('seovault-elementor-panel-open', open);

		if (toggle) {
			toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
		}
		if (open) {
			scheduleAssessment();
			const firstInput = panel.querySelector('.seovault-elementor-input');
			if (firstInput) {
				firstInput.focus();
			}
		}
	}

	function getPreviewDocument() {
		const iframe =
			document.getElementById('elementor-preview-iframe') ||
			document.querySelector('iframe[name="elementor-preview-iframe"]');

		try {
			return iframe && iframe.contentDocument
				? iframe.contentDocument
				: null;
		} catch (error) {
			return null;
		}
	}

	function cleanClone(node) {
		const clone = node.cloneNode(true);
		clone
			.querySelectorAll(
				'.elementor-element-overlay, .elementor-background-overlay, ' +
					'.ui-resizable-handle, [data-elementor-ui], script, style'
			)
			.forEach(function (chrome) {
				chrome.remove();
			});

		return clone;
	}

	function getLegacyContent() {
		const preview = getPreviewDocument();
		if (!preview) {
			return '';
		}

		const widgets = preview.querySelectorAll('.elementor-widget-container');
		if (widgets.length) {
			return Array.prototype.map
				.call(widgets, function (widget) {
					return cleanClone(widget).innerHTML;
				})
				.join('\n');
		}

		const root =
			preview.querySelector('.elementor') ||
			preview.querySelector('[data-elementor-type]');

		return root ? cleanClone(root).innerHTML : '';
	}

	function getLiveContent() {
		if (
			config.isV4Atomic &&
			window.seovaultElementorV4 &&
			typeof window.seovaultElementorV4.getContent === 'function'
		) {
			const v4Content = window.seovaultElementorV4.getContent();
			if (v4Content) {
				return v4Content;
			}
		}

		return getLegacyContent();
	}

	function getEditorTitle() {
		try {
			const model = elementor.settings.page.model;
			return model.get('post_title') || config.postTitle || '';
		} catch (error) {
			return config.postTitle || '';
		}
	}

	function getFieldValue(id) {
		const field = document.getElementById(id);
		return field ? field.value : '';
	}

	function getCheckboxValue(id) {
		const field = document.getElementById(id);
		return field && field.checked ? 1 : 0;
	}

	function countWords(content) {
		const temp = document.createElement('div');
		temp.innerHTML = content || '';
		const text = (temp.textContent || '').trim();
		return text ? text.split(/\s+/u).length : 0;
	}

	function assessmentData() {
		const content = getLiveContent();
		return {
			action: 'seovaultseo_live_assessment',
			nonce: config.assessmentNonce,
			post_id: config.postId,
			title: getFieldValue('seovault-elementor-seo-title'),
			description: getFieldValue('seovault-elementor-seo-description'),
			keyword: getFieldValue('seovault-elementor-focus-keyword'),
			canonical: getFieldValue('seovault-elementor-canonical-url'),
			noindex: getCheckboxValue('seovault-elementor-noindex'),
			nofollow: getCheckboxValue('seovault-elementor-nofollow'),
			content,
			post_title: getEditorTitle(),
		};
	}

	function updateAssessment() {
		if (!panel) {
			return;
		}

		const data = assessmentData();
		const wordCount = document.getElementById(
			'seovault-elementor-word-count'
		);
		if (wordCount) {
			wordCount.textContent =
				(strings.contentWords || 'Content words') +
				': ' +
				countWords(data.content);
		}

		if (assessmentRequest && assessmentRequest.state() === 'pending') {
			assessmentRequest.abort();
		}

		assessmentRequest = $.post(config.ajaxUrl, data)
			.done(function (response) {
				if (response && response.success && response.data) {
					renderAssessment(response.data);
					return;
				}

				renderAssessmentError();
			})
			.fail(function (request, textStatus) {
				if (textStatus !== 'abort') {
					renderAssessmentError();
				}
			});
	}

	const scheduleAssessment = debounce(updateAssessment, 500);

	function renderAssessmentError() {
		const status = document.getElementById(
			'seovault-elementor-assessment-status'
		);
		const list = document.getElementById('seovault-elementor-checks');
		const message =
			strings.assessmentError || 'Live SEO checks could not be updated.';

		if (status) {
			status.className =
				'seovault-elementor-assessment-status seovault-elementor-status-unknown';
			status.textContent = strings.unknown || 'Unknown';
		}

		if (list) {
			list.replaceChildren(
				makeElement(
					'li',
					'seovault-elementor-check seovault-elementor-status-unknown',
					message
				)
			);
		}
	}

	function renderAssessment(data) {
		const status = document.getElementById(
			'seovault-elementor-assessment-status'
		);
		const list = document.getElementById('seovault-elementor-checks');
		const labels = {
			good: strings.good || 'Good',
			okay: strings.okay || 'Okay',
			bad: strings.needsWork || 'Needs Work',
			unknown: strings.unknown || 'Unknown',
		};

		if (status) {
			status.className =
				'seovault-elementor-assessment-status ' +
				'seovault-elementor-status-' +
				data.overall;
			status.textContent = labels[data.overall] || labels.unknown;
			if (typeof data.score !== 'undefined') {
				status.textContent += ' — ' + data.score + '/100';
			}
		}

		if (!list) {
			return;
		}

		list.replaceChildren();
		(data.checks || []).forEach(function (check) {
			const item = makeElement(
				'li',
				'seovault-elementor-check seovault-elementor-status-' +
					check.status
			);
			const label = makeElement(
				'strong',
				'seovault-elementor-check-label',
				check.label
			);
			const message = makeElement(
				'span',
				'seovault-elementor-check-message',
				check.message
			);

			item.appendChild(label);
			item.appendChild(message);
			list.appendChild(item);
		});
	}

	function saveData() {
		return {
			action: 'seovaultseo_elementor_save',
			nonce: config.saveNonce,
			post_id: config.postId,
			seo_title: getFieldValue('seovault-elementor-seo-title'),
			seo_description: getFieldValue(
				'seovault-elementor-seo-description'
			),
			focus_keyword: getFieldValue('seovault-elementor-focus-keyword'),
			canonical_url: getFieldValue('seovault-elementor-canonical-url'),
			noindex: getCheckboxValue('seovault-elementor-noindex'),
			nofollow: getCheckboxValue('seovault-elementor-nofollow'),
			og_title: getFieldValue('seovault-elementor-og-title'),
			og_description: getFieldValue('seovault-elementor-og-description'),
			og_image: getFieldValue('seovault-elementor-og-image'),
		};
	}

	function saveFields() {
		if (saveRequest && saveRequest.state() === 'pending') {
			return saveRequest;
		}

		buildPanel();
		const status = document.getElementById(
			'seovault-elementor-save-status'
		);

		if (status) {
			status.className = 'seovault-elementor-save-status';
			status.textContent = strings.saving || 'Saving…';
		}

		saveRequest = $.post(config.ajaxUrl, saveData())
			.done(function (response) {
				if (response && response.success) {
					status.className =
						'seovault-elementor-save-status is-success';
					status.textContent = strings.saved || 'SEO settings saved.';
					return;
				}

				status.className = 'seovault-elementor-save-status is-error';
				status.textContent =
					strings.saveError || 'SEO settings could not be saved.';
			})
			.fail(function () {
				status.className = 'seovault-elementor-save-status is-error';
				status.textContent =
					strings.saveError || 'SEO settings could not be saved.';
			});

		return saveRequest;
	}

	function isTargetDocument(context) {
		let documentId =
			context && context.document ? context.document.id : context?.id;

		if (!documentId) {
			try {
				documentId = elementor.documents.getCurrent().id;
			} catch (error) {
				return true;
			}
		}

		return Number.parseInt(documentId, 10) === Number(config.postId);
	}

	function registerElementorHook(timing, command, id, callback) {
		if (
			typeof $e === 'undefined' ||
			!$e.hooks ||
			!$e.modules ||
			!$e.modules.hookUI
		) {
			return;
		}

		class SeoVaultElementorHook extends $e.modules.hookUI.Base {
			getCommand() {
				return command;
			}

			getId() {
				return id;
			}

			getConditions() {
				return isTargetDocument(arguments[0]);
			}

			apply() {
				return callback.apply(null, arguments);
			}
		}

		const method =
			timing === 'before' ? 'registerUIBefore' : 'registerUIAfter';
		if (typeof $e.hooks[method] === 'function') {
			$e.hooks[method](new SeoVaultElementorHook());
		}
	}

	function registerLifecycle() {
		if (lifecycleRegistered) {
			return;
		}
		lifecycleRegistered = true;

		mountToggle();
		buildPanel();

		registerElementorHook(
			'after',
			'editor/documents/attach-preview',
			'seovaultseo/content/attach-preview',
			function () {
				mountToggle();
				scheduleAssessment();
			}
		);
		registerElementorHook(
			'after',
			'panel/editor/open',
			'seovaultseo/content/panel-open',
			scheduleAssessment
		);
		registerElementorHook(
			'after',
			'document/save/save',
			'seovaultseo/meta/save',
			saveFields
		);
		registerElementorHook(
			'after',
			'document/save/set-is-modified',
			'seovaultseo/content/modified',
			scheduleAssessment
		);

		try {
			elementor.channels.editor.on('change', scheduleAssessment);
			elementor.settings.page.model.on('change', scheduleAssessment);
		} catch (error) {
			// The $e hooks above remain the primary lifecycle bridge.
		}

		document.addEventListener(
			'seovault:elementor-content-change',
			scheduleAssessment
		);

		observer = new MutationObserver(mountToggle);
		observer.observe(document.body, {
			childList: true,
			subtree: true,
		});

		scheduleAssessment();
	}

	$(window).on('elementor:init', function () {
		if (elementor && typeof elementor.on === 'function') {
			elementor.on('panel:init', registerLifecycle);
		}
		window.setTimeout(registerLifecycle, 0);
	});

	if (typeof window.elementor !== 'undefined') {
		window.setTimeout(registerLifecycle, 0);
	}
})(jQuery);
