// Load Elementor Icons. Needed because we use fa- icons while elementor uses
// eicon- icons, that do not need loading icon libraries.
jQuery(window).on("elementor:init", function () {
	elementor.iconManager.loadIconLibraries();
});

function posts_v2_item_id_to_label(id) {
	return posts_v2_item_label_localization[id];
}

// Add WP_Query args in Context Menu
elementor.hooks.addFilter(
	"elements/widget/contextMenuGroups",
	function (groups, element) {
		// Features with collection "dynamic-posts"
		let features = dce_features_collection_dynamic_posts;

		if (!features.includes(element.options.model.get("widgetType"))) {
			return groups;
		}

		groups.push({
			name: "dce_dynamic_collection_query_args",
			actions: [
				{
					name: "dce_dynamic_collection_query_args",
					title: "Get Query Args for Debug",
					icon: "icon-dce-logo-dce",
					callback: function () {
						let query_args = jQuery(element.el)
							.find(".dce-posts-container")
							.data("dce-debug-query-args");
						query_args = JSON.stringify(query_args, null, 2);

						navigator.clipboard
							.writeText(query_args)
							.then(function () {
								elementor.notifications.showToast({
									message:
										"WP_Query Args copied to clipboard",
								});
							});
					},
				},
			],
		});
		return groups;
	},
);

// Loading the section items in the widget Dynamic Posts is extremely slow.
// We thus want to give a feedback to the user that the section is actually loading.
jQuery(window).on("elementor:init", function () {
	elementor.hooks.addAction(
		"panel/open_editor/widget/dce-dynamicposts-v2",
		function (panel, model, view) {
			const callback = () => {
				let $items = panel.$el.find(".elementor-control-section_items");
				if (
					$items.length === 0 ||
					$items.attr("data-dce-loader-set") === "yes"
				) {
					return;
				}
				$items.attr("data-dce-loader-set", "yes");
				let $title = $items.find(".elementor-panel-heading-title");
				let $cc = $items.find(".elementor-control-content");
				// Get elementor original click handler and unbind it. We need
				// it so we can run it by hand after a timeout. Without the
				// timeout it would block page rendering and the loading
				// message wound not appear.
				let handler = jQuery._data($items[0], "events").click[0]
					.handler;
				$items.unbind("click");
				$cc.on("click", () => {
					$title.append(' <em style="color: gray;">loading...</em>');
					setTimeout(handler, 5);
				});
			};
			const config = { childList: true, subtree: true };
			const observer = new MutationObserver(callback);
			observer.observe(panel.$el[0], config);
		},
	);
});

function dce_get_element_id_from_cid(cid) {
	var iFrameDOM = jQuery("iframe#elementor-preview-iframe").contents();
	var eid = iFrameDOM
		.find(".elementor-element[data-model-cid=" + cid + "]")
		.data("id");
	return eid;
}

function dce_getimageSizes(url, callback) {
	var img = new Image();
	img.crossOrigin = "anonymous";
	img.onload = function () {
		var sizes = {};
		sizes.height = this.height;
		sizes.width = this.width;
		sizes.coef = sizes.height / sizes.width;
		callback(sizes);
	};
	img.src = url;
}

jQuery(function () {
	// Add DCE global settings panel menu item
	if (elementor && ElementorConfig.settings.dynamicooo) {
		elementor.on("panel:init", function () {
			var menuSettings = ElementorConfig.settings.dynamicooo;
			var groupName = "style"; // Elementor v3 'Settings' panel group name
			var beforeItem = "editor-preferences"; // Elementor v3 'User Preferences' panel menu name
			var namespace = "panel/" + menuSettings.name + "-settings",
				menuItemOptions = {
					icon: "icon-dce-logo-dce",
					title: menuSettings.panelPage.title,
					type: "page",
					pageName: menuSettings.name + "_settings",
					callback: function callback() {
						return elementorCommon.api.route(
							"".concat(namespace, "/settings"),
						);
					},
				};
			elementorCommon.api.bc.ensureTab(
				namespace,
				"settings",
				menuItemOptions.pageName,
			);
			elementor.modules.layouts.panel.pages.menu.Menu.addItem(
				menuItemOptions,
				groupName,
				beforeItem,
			);
		});
	}

	jQuery(document).on(
		"mousedown",
		".elementor-control-repeater_shape_path .elementor-repeater-fields, .elementor-control-repeater_shape_polyline .elementor-repeater-fields",
		function () {
			var repeater_index = jQuery(this).index();
			var eid = dce_get_element_id_from_cid(dce_model_cid);
			var iFrameDOM = jQuery(
				"iframe#elementor-preview-iframe",
			).contents();
			var morphed = iFrameDOM.find(
				".elementor-element[data-id=" + eid + "] svg.dce-svg-morph",
			);

			if (morphed.attr("data-run") == "paused")
				morphed.attr("data-morphid", repeater_index);
		},
	);
	jQuery(document).on(
		"change",
		".elementor-control-playpause_control",
		function () {
			var runAnimation =
				elementorFrontend.config.elements.data[dce_model_cid]
					.attributes["playpause_control"];
			var eid = dce_get_element_id_from_cid(dce_model_cid);
			var iFrameDOM = jQuery(
				"iframe#elementor-preview-iframe",
			).contents();
			var morphed = iFrameDOM.find(
				".elementor-element[data-id=" + eid + "] #dce-svg-" + eid,
			);
			morphed.attr("data-run", runAnimation);
		},
	);
	//---- global settings -----
	var inputSelector =
		".elementor-control-selector_wrapper.elementor-control-type-text input, .elementor-control-selector_header.elementor-control-type-text input";
	var detect_content_frame = function ($content) {
		var iFrameDOM = jQuery("iframe#elementor-preview-iframe").contents();
		var classController =
			".elementor-control-dce_smoothtransition_class_controller input, .elementor-control-dce_trackerheader_class_controller input";
		const queryCheck = (s) =>
			document.createDocumentFragment().querySelector(s);
		const isSelectorValid = (selector) => {
			try {
				queryCheck(selector);
			} catch (e) {
				return false;
			}
			return true;
		};
		if (isSelectorValid($content) && typeof $content !== "undefined") {
			var sectorList = $content.split(",");
			var sectorListLength = sectorList.length;
			var countSelectorValid = 0;
			sectorList.forEach(selectorIteration);
			function selectorIteration(value) {
				value = value.trim();
				if (
					iFrameDOM.find(value).length &&
					value.length > 1 &&
					(value.substring(0, 1) == "." ||
						value.substring(0, 1) == "#")
				) {
					countSelectorValid++;
				}
			}
			if (countSelectorValid >= sectorListLength) {
				jQuery(".dce-class-debug")
					.text("Detected")
					.addClass("detected");
				jQuery(classController).val("detected").trigger("input");
			} else {
				jQuery(".dce-class-debug")
					.text("No matches")
					.removeClass("detected");
				jQuery(classController).val("").trigger("input");
			}
		}
	};
	var detect_from_text = function ($target) {
		var selectorVal = $target;
		detect_content_frame(selectorVal);
	};
	jQuery(document).on(
		"mousedown",
		"#elementor-panel-dynamicooo-settings, .elementor-panel-menu-item-undefined",
		function (e) {
			setTimeout(function () {
				detect_from_text(jQuery(inputSelector).val());
			}, 200);
			detect_from_text(jQuery(inputSelector).val());
		},
	);
	jQuery(document).on("input", inputSelector, function () {
		detect_from_text(jQuery(this).val());
	});
});

(function () {
	/**
	 * Sanitize string for use in URL parameters
	 *
	 * @param {string} str String to sanitize
	 * @return {string} Sanitized string
	 */
	const sanitizeUrlParam = (str) => {
		if (!str) {
			return '';
		}
		// Allow only alphanumeric, dash, underscore
		return String(str).replace(/[^a-zA-Z0-9_-]/g, '');
	};

	/**
	 * Validate and sanitize numeric ID
	 *
	 * @param {string|number} id ID to validate
	 * @return {number|null} Validated ID or null
	 */
	const validateId = (id) => {
		const numId = parseInt(id, 10);
		if (isNaN(numId) || numId <= 0) {
			return null;
		}
		return numId;
	};

	/**
	 * Validate URL points to wp-admin
	 *
	 * @param {string} url URL to validate
	 * @param {string} base_url Base URL
	 * @return {boolean} Whether URL is valid
	 */
	const isValidAdminUrl = (url, base_url) => {
		if (!url || url === '#') {
			return false;
		}
		// Must start with base_url/wp-admin
		return url.startsWith(`${base_url}/wp-admin/`);
	};

	/**
	 * Generate edit or add link based on query parameters
	 *
	 * @param {string|array} value Selected value(s)
	 * @param {string} query_type Type of query (posts, users, terms)
	 * @param {string} object_type Specific object type
	 * @param {boolean} is_edit Whether to generate edit or add link
	 * @return {string} Generated URL or '#' if not applicable
	 */
	const generateActionLink = (value, query_type, object_type, is_edit) => {
		const base_url = ElementorConfig.home_url;
		
		// Sanitize inputs
		query_type = sanitizeUrlParam(query_type);
		object_type = sanitizeUrlParam(object_type);

		if (is_edit) {
			// Validate ID for edit operations
			const validId = validateId(value);
			if (!validId) {
				return "#";
			}

			// Edit link
			let link = "#";
			switch (query_type) {
				case "posts":
					if (!object_type || object_type !== "type") {
						link = `${base_url}/wp-admin/post.php?post=${validId}`;
						link += object_type === "elementor_library" ? "&action=elementor" : "&action=edit";
					}
					break;
				case "users":
					if (!object_type || object_type !== "role") {
						link = `${base_url}/wp-admin/user-edit.php?user_id=${validId}`;
					}
					break;
				case "terms":
					if (object_type) {
						link = `${base_url}/wp-admin/term.php?tag_ID=${validId}&taxonomy=${object_type}`;
					}
					break;
			}
			
			return isValidAdminUrl(link, base_url) ? link : "#";
		} else {
			// Add new link
			let link = "#";
			switch (query_type) {
				case "posts":
					if (!object_type || object_type !== "type") {
						if (object_type === "elementor_library") {
							link = `${base_url}/wp-admin/edit.php?post_type=${object_type}#add_new`;
						} else if (object_type) {
							link = `${base_url}/wp-admin/post-new.php?post_type=${object_type}`;
						} else {
							link = `${base_url}/wp-admin/post-new.php`;
						}
					}
					break;
				case "users":
					if (!object_type || object_type !== "role") {
						link = `${base_url}/wp-admin/user-new.php`;
					}
					break;
				case "terms":
					if (object_type) {
						link = `${base_url}/wp-admin/edit-tags.php?taxonomy=${object_type}`;
					} else {
						link = `${base_url}/wp-admin/edit-tags.php`;
					}
					break;
			}
			
			return isValidAdminUrl(link, base_url) ? link : "#";
		}
	};

	/**
	 * Update query action button for ooo_query control
	 *
	 * @param {HTMLElement} selectElement The select element
	 */
	const dce_update_query_btn = (selectElement) => {
		const $select = jQuery(selectElement);
		const $control = $select.closest(".elementor-control-type-ooo_query");
		const $buttonField = $control.find(".dce-query-button-field");
		const $button = $buttonField.find(".dce-query-action-button");
		const $buttonText = $button.find(".dce-query-button-text");
		const $buttonIcon = $button.find("i");
		
		const query_type = $select.data("query-type");
		const object_type = $select.data("object-type");
		const value = $select.val();

		// Check if we should show button (single value selected or empty for "add new")
		const is_edit = value && (!jQuery.isArray(value) || value.length === 1);
		const actual_value = jQuery.isArray(value) ? value[0] : value;

		const link = generateActionLink(actual_value, query_type, object_type, is_edit);

		if (link && link !== "#") {
			// Update button appearance
			$buttonIcon.attr("class", is_edit ? "eicon-pencil" : "eicon-plus");
			$buttonText.text(is_edit ? " Quick Edit" : " Add New");
			
			// Store link in button data
			$button.data("action-link", link);
			
			// Show button
			$buttonField.show();
		} else {
			// Hide button if no valid link
			$buttonField.hide();
		}
	};

	/**
	 * Handle click on query action button
	 * 
	 * Security: Link is validated before opening:
	 * - IDs are validated as positive integers
	 * - Query types and object types are sanitized (alphanumeric only)
	 * - URLs are verified to point to wp-admin only
	 * - Button is only rendered for users with edit_posts capability
	 */
	jQuery(document).on("click", ".dce-query-action-button", function(e) {
		e.preventDefault();
		const link = jQuery(this).data("action-link");
		if (link && link !== "#") {
			window.open(link, "_blank");
		}
	});
	const editorInit = () => {
		// FILEBROWSER
		elementor.channels.editor.on(
			"dceFileBrowser:removeMedia",
			(childView) => {
				tinyMCE.editors[0].setContent("");
			},
		);

		elementor.channels.editor.on(
			"dynamicShortcodesWizard::generateShortcode",
			(childView) => {
				wp.ajax
					.post("dce_generate_dynamic_shortcode", {
						settings: childView.container.settings.attributes,
					})
					.done(function (shortcode) {
						childView.container.settings.setExternalChange(
							"shortcode",
							shortcode,
						);
						childView.container.settings.setExternalChange(
							"status",
							"generated",
						);

						container = childView.container;
						const tagText =
								elementor.dynamicTags.tagContainerToTagText(
									container,
								),
							commandArgs = {
								container: container.parent,
								settings: {
									[container.view.options.controlName]:
										tagText,
								},
							};
						$e.run("document/dynamic/settings", commandArgs);
						elementor.notifications.showToast({
							message: "Dynamic Shortcode generated.",
						});
					})
					.fail(function (errorThrown) {
						elementor.notifications.showToast({
							message:
								"ERROR! Dynamic Shortcode not generated. " +
								errorThrown,
						});
						console.log(
							"ERROR! Dynamic Shortcode not generated. " +
								errorThrown,
						);
					});
			},
		);

		elementor.channels.editor.on(
			"dynamicShortcodesWizard::editShortcode",
			(childView) => {
				childView.container.settings.setExternalChange(
					"status",
					"edit",
				);
				elementor.notifications.showToast({
					message: "Dynamic Shortcode edit mode.",
				});
			},
		);

		elementor.channels.editor.on(
			"dynamicShortcodesWizard::startShortcode",
			(childView) => {
				childView.container.settings.setExternalChange(
					"status",
					"initial",
				);
			},
		);

		elementor.channels.editor.on(
			"dynamicShortcodesWizard::copyShortcode",
			(childView) => {
				navigator.clipboard
					.writeText(
						childView.container.settings.attributes.shortcode,
					)
					.then(function () {
						elementor.notifications.showToast({
							message: "Dynamic Shortcode copied to clipboard",
						});
					});
			},
		);
		// Query Control
		var DCEControlQuery = elementor.modules.controls.Select2.extend({
			cache: null,
			isTitlesReceived: false,
			getSelect2Placeholder: function getSelect2Placeholder() {
				var self = this;
				return {
					id: "",
					text: self.model.get("placeholder"), //'All',
				};
			},
			getSelect2DefaultOptions: function getSelect2DefaultOptions() {
				var self = this;
				return jQuery.extend(
					elementor.modules.controls.Select2.prototype.getSelect2DefaultOptions.apply(
						this,
						arguments,
					),
					{
						ajax: {
							transport: function transport(
								params,
								success,
								failure,
							) {
								var data = {
									q: params.data.q,
									query_type: self.model.get("query_type"),
									object_type: self.model.get("object_type"),
								};
								return elementorCommon.ajax.addRequest(
									"dce_query_control_filter_autocomplete",
									{
										data: data,
										success: success,
										error: failure,
									},
								);
							},
							data: function data(params) {
								return {
									q: params.term,
									page: params.page,
								};
							},
							cache: true,
						},
						escapeMarkup: function escapeMarkup(markup) {
							return markup;
						},
						minimumInputLength: 2,
					},
				);
			},
			// translate with an ajax post ids to post titles.
			getValueTitles: function getValueTitles() {
				var self = this;
				var ids = this.getControlValue();
				var queryType = this.model.get("query_type");
				objectType = this.model.get("object_type");
				if (!ids || !queryType) return;
				if (!_.isArray(ids)) {
					ids = [ids];
				}
				// no translation needed for these query types:
				if (
					queryType === "pods" ||
					queryType === "jet" ||
					queryType === "metabox" ||
					queryType === "metabox_relationship" ||
					queryType === "options"
				) {
					let t = {};
					for (id of ids) {
						t[id] = id; // Label is the same as the value.
					}
					self.isTitlesReceived = true;
					self.model.set("options", t);
					self.render();
					return;
				}

				elementorCommon.ajax.loadObjects({
					action: "dce_query_control_value_titles",
					ids: ids,
					data: {
						query_type: queryType,
						object_type: objectType,
						unique_id: "" + self.cid + queryType,
					},
					success: function success(data) {
						self.isTitlesReceived = true;
						self.model.set("options", data);
						self.render();
					},
					before: function before() {
						self.addSpinner();
					},
				});
			},
			addSpinner: function addSpinner() {
				this.ui.select.prop("disabled", true);
				this.$el
					.find(".elementor-control-title")
					.after(
						'<span class="elementor-control-spinner dce-control-spinner">&nbsp;<i class="fa fa-spinner fa-spin"></i>&nbsp;</span>',
					);
			},
		onReady: function onReady() {
			setTimeout(
				elementor.modules.controls.Select2.prototype.onReady.bind(
					this,
				),
			);
			if (this.ui.select) {
				dce_update_query_btn(this.ui.select);
			}

			if (!this.isTitlesReceived) {
				this.getValueTitles();
			}
		},
			onBeforeDestroy: function onBeforeDestroy() {
				if (this.ui.select.data("select2")) {
					this.ui.select.select2("destroy");
				}

				this.$el.remove();
			},
		});
		// Add Control Handlers
		elementor.addControlView("ooo_query", DCEControlQuery);
		jQuery(document).on(
			"change",
			".elementor-control-type-ooo_query select",
			function () {
				dce_update_query_btn(this);
			},
		);
	};
	if (typeof elementor !== "undefined") {
		editorInit();
	} else {
		jQuery(window).on("elementor:init", editorInit);
	}
})();
