"use strict";

/**
 * @name Catalog
 *
 * @description
 * Implements actions with catalog
 *
 * @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
 * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
 */
export default class catalog {
	/**
	 * @name Type of the program
	 */
	static type = "module";

	/**
	 * Parameters of search
	 *
	 * Will be converted to the body of the GET request ("?name=value&name2=value2")
	 */
	static parameters = new Map([
		[
			"text",
			new URLSearchParams(document.location.search).get("text"),
		],
		[
			"category",
			new URLSearchParams(document.location.search).get(
				"category",
			),
		],
		[
			"sort",
			new URLSearchParams(document.location.search).get("sort"),
		],
		[
			"brand",
			new URLSearchParams(document.location.search).get("brand"),
		],
	]);

	/**
	 * @name Search (interface)
	 *
	 * @description
	 * Request search in the catalog and render result in the core.main
	 *
	 * @param {Event} event Event (keyup)
	 * @param {bool} force Ignore the damper? (false)
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static search(event, force = false) {
		// Initializing the search <input> element
		const input = document.querySelector("search#search>input");

		if (input instanceof HTMLElement) {
			// Found the search <input> element

			// Removing errors animations
			input.classList.remove("error");

			if (
				input.value.length < 3 &&
				input.value.lenght > 0
			) {
				// Only 1-2 character entered (this is not a search reset and is not an adequate search)

				// Exit (fail)
				return false;
			}
		}

		if (event instanceof Event) {
			// Executed from event

			if (event.type === "keyup") {
				// Executed by "keyup" event

				if (event.target === input) {
					// Executed from search <input> element

					if (event.keyCode === 13) {
						// Executed by "enter" button

						// Blocking the search <input> element
						input.setAttribute(
							"disabled",
							true,
						);

						// Execute
						this.search.system();
					} else if (input.value.length < 3) {
						// Less than 3 character entered (this is not a search reset and is not an adequate search)

						// Exit (fail)
						return false;
					} else {
						// Executed by any else button

						core.modules.connect("damper").then(
							() => {
								// Imported the damper module

								// Execute under damper
								this.search.damper(force);
							},
							() => {
								// Not imported the damper module

								// Execute under damper
								this.search.system(force);
							},
						);
					}
				}
			} else {
				// Executed not by "keyup" event

				core.modules.connect("damper").then(
					() => {
						// Imported the damper module

						// Execute under damper
						this.search.damper(force);
					},
					() => {
						// Not imported the damper module

						// Execute under damper
						this.search.system(force);
					},
				);
			}

			// Exit (success)
			return true;
		}

		// Exit (fail)
		return false;
	}

	/**
	 * @name Product card (interface)
	 *
	 * @description
	 * Request product data and render result in core.window
	 *
	 * @param {HTMLElement} button Button of the product <a>
	 * @param {bool} force Ignore the damper? (false)
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static product(button, force = false) {
		// Initializing identifier of the category
		const identifier = button.parentElement.getAttribute(
			"data-product-identifier",
		);

		core.modules.connect("damper").then(
			() => {
				// Imported the damper module

				// Execute under damper
				this.product.damper(identifier, force);
			},
			() => {
				// Not imported the damper module

				// Execute
				this.product.system(identifier, force);
			},
		);

		// Exit (success)
		return true;
	}
}

core.modules.connect("damper").then(() => {
	// Imported the damper module

	Object.assign(
		catalog.search,
		{
			/**
			 * @name Search (system)
			 *
			 * @description
			 * Request search in the catalog and render result in the core.main
			 *
			 * @memberof catalog.search
			 *
			 * @param {bool} force Ignore the damper? (false)
			 *
			 * @return {void}
			 */
			damper: core.damper(
				(...variables) => catalog.search.system(...variables),
				300,
				1,
			),
		},
	);

	Object.assign(
		catalog.product,
		{
			/**
			 * @name Product card (damper)
			 *
			 * @description
			 * Request product data and render result in the core.window
			 *
			 * @memberof catalog.product
			 *
			 * @param {string} identifier Identifier of the product
			 * @param {bool} force Ignore the damper? (false)
			 *
			 * @return {void}
			 */
			damper: core.damper(
				(...variables) => catalog.product.system(...variables),
				200,
				1,
			),
		},
	);
});

Object.assign(
	catalog.product,
	{
		/**
		 * @name Product card (system)
		 *
		 * @description
		 * Request product data and render result in the core.window
		 *
		 * @memberof catalog.product
		 *
		 * @param {string} identifier Identifier of the product
		 *
		 * @return {Promise} Request to the server
		 */
		async system(
			identifier,
			resolve = () => {},
			reject = () => {},
		) {
			try {
				if (typeof identifier === "string") {
					// Validated identifier

					// Initialize the buffer of URN parameters @todo after opening window add to document.location.search
					const parameters = new URLSearchParams(
						document.location.search,
					);

					// Write parameter to the buffer of URN parameters
					parameters.set("product", identifier);

					// Intializing URI of the request
					const uri = "?" + parameters;

					return await core.request(uri, undefined, "GET").then(
						async (json) => {
							if (json) {
								// Received a JSON-response

								if (
									json.errors !== null &&
									typeof json.errors === "object" &&
									json.errors.length > 0
								) {
									// Fail (received errors)

									// Exit (fail)
									reject(json);
								} else {
									// Success (not received errors)

									if (core.window instanceof HTMLElement) {
										// Initialized active window

										// Delete active window
										core.window.remove();
									}

									core.modules.connect(["cart", "telegram"]).then(async () => {
										// Imported the telegram module

										if (
											json.product !== null &&
											typeof json.product === "object"
										) {
											// Received data of the product

											// Writing to the browser history
											history.pushState({}, json.product.name, uri);

											// Deinitializing of the old winow
											const old = document.getElementById("window");
											if (old instanceof HTMLElement) old.remove();

											const wrap = document.createElement("section");
											wrap.setAttribute("id", "window");

											const card = document.createElement("div");
											// card.classList.add("product", "card");
											card.classList.add("card");

											const h3 = document.createElement("h3");

											const name = document.createElement("span");
											name.classList.add("name", "unselectable");
											name.setAttribute("title", identifier);
											name.innerText = json.product.name;

											const exit = document.createElement("a");
											exit.classList.add("exit");
											exit.setAttribute("type", "button");

											const exit_icon = document.createElement("i");
											exit_icon.classList.add("icon", "close");

											const images = document.createElement("div");
											images.setAttribute("id", "images");
											images.classList.add("images", "unselectable");

											for (
												const [index, uri] of json.product.images["200"]
													.entries()
											) {
												const image = document.createElement("img");
												image.setAttribute("src", uri);
												image.setAttribute("data-image-small", uri);
												image.setAttribute(
													"data-image-big",
													json.product.images["800"][index],
												);
												image.setAttribute("ondragstart", "return false;");

												images.appendChild(image);
											}

											let width = 0;
											let buffer;
											[...images.children].forEach(
												// 150px instead of child.offsetWidth by min-width in window.css
												(child) => (width += 150 +
													(isNaN(
															buffer = parseFloat(
																getComputedStyle(child).marginRight,
															),
														)
														? 0
														: buffer)),
											);

											const button = core.telegram.api.isVisibless;

											// блокировка закрытия изображений
											let images_from;
											const _images_from = (event) => (images_from = event);
											images.addEventListener("mousedown", _images_from);
											images.addEventListener("touchstart", _images_from);

											let touches;
											images.addEventListener('touchmove', (move) => {
												touches = move.touches;
											});

											const _open = (event) => {
												if (
													event.type === "touchstart" ||
													event.button === 0
												) {
													const x = event.pageX ||
														(event.touches && event.touches[0]?.pageX) || 0;
													const y = event.pageY ||
														(event.touches && event.touches[0]?.pageY) || 0;
													const _x = images_from.pageX ||
														(images_from.touches &&
															images_from.touches[0]?.pageX) ||
														0;
													const _y = images_from.pageY ||
														(images_from.touches &&
															images_from.touches[0]?.pageY) ||
														0;

													if (
														_x - x < 10 &&
														_x - x > -10 &&
														_y - y < 10 &&
														_y - y > -10
													) {
														// Replacing small images with big images
														Array.from(images.children).forEach((image) =>
															image.setAttribute(
																"src",
																image.getAttribute("data-image-big"),
															)
														);

														// Expanding the "Web App" window
														core.telegram.api.expand();
														core.telegram.api.disableVerticalSwipes();

														images.classList.add("extend");

														if (button) {
															core.telegram.api.MainButton.hide();
														}

														setTimeout(() => {
															images.hotline.alive = false;
															images.hotline.movable = false;
															images.hotline.restart();

															images.addEventListener("mouseup", _close);
															images.addEventListener("touchend", _close);
														}, 300);
														images.removeEventListener("mouseup", _open);
														images.removeEventListener("touchend", _open);
													}
												}
											};

											const _close = (event) => {
												console.log(event)
												const x = event.pageX ||
													(touches && touches[0]?.pageX) || 0;
												const y = event.pageY ||
													(touches && touches[0]?.pageY) || 0;
												const _x = images_from.pageX ||
													(images_from.touches &&
														images_from.touches[0]?.pageX) ||
													0;
												const _y = images_from.pageY ||
													(images_from.touches &&
														images_from.touches[0]?.pageY) ||
													0;

												if (
													event.type === "touchend" ||
													event.button === 0
												) {
													if (
														_x - x < 10 &&
														_x - x > -10 &&
														_y - y < 10 &&
														_y - y > -10
													) {
														// Курсор не был сдвинут на 10 квардратных пикселей
														// (в идеале надо переделать на таймер 2 секунды есди зажата кнопка то ничего не делать а просто двигать)
														// пох абсолютно сейчас заказчик слишком охуевший для этого

														images.hotline.movable = true;
														images.hotline.alive = true;
														images.hotline.step = -1;
														images.hotline.wheel = true;
														images.hotline.restart();

														if (width < card.offsetWidth) {
															images.hotline.stop();
														}

														// Replacing big images with small images
														Array.from(images.children).forEach((image) =>
															image.setAttribute(
																"src",
																image.getAttribute("data-image-small"),
															)
														);

														images.classList.remove("extend");


														core.telegram.api.enableVerticalSwipes();

														if (button) {
															core.telegram.api.MainButton.show();
														}

														images.removeEventListener("mouseup", _close);
														images.removeEventListener("touchend", _close);
														images.addEventListener("mousedown", _start);
														images.addEventListener("touchstart", _start);
													} else {
														// Курсор был сдвинут более чем на 10 пикселей
													
														if (x > _x) images.hotline.forward();
														else images.hotline.backward();
													}
												}
											};

											const _start = (event) => {
												if (
													event.type === "touchstart" ||
													event.button === 0
												) {
													images.removeEventListener("mousedown", _start);
													images.removeEventListener("touchstart", _start);
													images.addEventListener("mouseup", _open);
													images.addEventListener("touchend", _open);
												}
											};

											images.addEventListener("mousedown", _start);
											images.addEventListener("touchstart", _start);

											const header = document.createElement("p");
											header.classList.add("header");

											const brand = document.createElement("small");
											brand.classList.add("brand");
											brand.innerText = json.product.brand;

											const description = document.createElement("p");
											description.classList.add("description");
											description.innerText = json.product.description;

											const compatibility = document.createElement("p");
											compatibility.classList.add("compatibility");
											compatibility.innerText = json.product.compatibility;

											const footer = document.createElement("div");
											footer.classList.add("footer");
											footer.classList.add("footer");

											const dimensions = document.createElement("small");
											dimensions.classList.add("dimensions");

											const x = json.product.dimensions.x;
											const y = json.product.dimensions.y;
											const z = json.product.dimensions.z;

											let formatted = "";

											if (x !== "") formatted = x;
											if (y !== "") {
												if (formatted.length === 0) formatted = y;
												else formatted += "x" + y;
											}
											if (z !== "") {
												if (formatted.length === 0) formatted = z;
												else formatted += "x" + z;
											}

											dimensions.innerText = formatted;

											const weight = document.createElement("small");
											weight.classList.add("weight");
											weight.innerText = json.product.weight + "г";

											const cost = document.createElement("p");
											cost.classList.add("cost", "currency");
											cost.innerText = json.product.cost;

											h3.appendChild(name);
											exit.appendChild(exit_icon);
											h3.appendChild(exit);
											card.appendChild(h3);
											card.appendChild(images);
											header.appendChild(brand);
											card.appendChild(header);
											card.appendChild(description);
											card.appendChild(compatibility);
											footer.appendChild(dimensions);
											footer.appendChild(weight);
											footer.appendChild(cost);
											card.appendChild(footer);
											wrap.appendChild(card);
											document.body.appendChild(wrap);

											// Reinitialize parameter
											core.window = document.getElementById("window");

											// Write
											const add = () => {
												core.cart.write(
													undefined,
													document.getElementById(
														"product_" + json.product.identifier,
													),
												);

												core.telegram.api.MainButton
													.setText(json.product.cart.text.added)
													.setParams({
														color: "#90be36",
														has_shine_effect: true,
													})
													.offClick(add)
													.onClick(added);
											};

											// Delete
											const added = () => {
												core.cart.set(
													undefined,
													document.getElementById(
														"product_" + json.product.identifier,
													),
													0,
												);

												core.telegram.api.MainButton
													.setText(json.product.cart.text.add)
													.setParams({
														color: core.telegram.api.themeParams.button_color,
														// has_shine_effect: json.product.discount > 0,
														has_shine_effect: false,
													})
													.offClick(added)
													.onClick(add);
											};

											if (json.product.cart.amount > 0) {
												// Initializing the "Main Button" of the "Web App" window
												core.telegram.api.MainButton
													.setText(json.product.cart.text.added)
													.setParams({
														color: "#90be36",
														has_shine_effect: true,
													})
													.onClick(added)
													.hideProgress()
													.enable()
													.show();
											} else {
												// Initializing the "Main Button" of the "Web App" window
												core.telegram.api.MainButton
													.setText(json.product.cart.text.add)
													.setParams({
														color: core.telegram.api.themeParams.button_color,
														// has_shine_effect: json.product.discount > 0,
														has_shine_effect: false,
													})
													.onClick(add)
													.hideProgress()
													.enable()
													.show();
											}

											// блокировка закрытия карточки
											let from;
											const _from = (event) => (from = event.target);
											wrap.addEventListener("mousedown", _from);
											wrap.addEventListener("touchstart", _from);

											const remove = (event) => {
												if (
													typeof event === "undefined" ||
													event.type !== "popstate"
												) {
													history.back();

													// Initialize the buffer of URN parameters @todo after opening window add to document.location.search
													const parameters = new URLSearchParams(
														document.location.search,
													);

													if (parameters.get("product") === identifier) {
														// The previous window with the product card was exactly the same

														// Deleting product card
														parameters.delete("product");

														// Writing to the browser history
														history.pushState(
															{},
															json.product.name,
															"?" + parameters,
														);
													}

													// Write parameter to the buffer of URN parameters
													parameters.set("product", identifier);
												}

												wrap.remove();
												images.removeEventListener(
													"mousedown",
													_images_from,
												);
												images.removeEventListener(
													"touchstart",
													_images_from,
												);
												wrap.removeEventListener("mousedown", _from);
												wrap.removeEventListener("touchstart", _from);
												exit.removeEventListener("click", remove);
												exit.removeEventListener("touch", remove);
												document.removeEventListener("click", close);
												document.removeEventListener("touch", close);
												window.removeEventListener("popstate", remove);

												// Denitializing the "Back Button" of the "Web App" window
												core.telegram.api.BackButton.hide();
												core.telegram.api.BackButton.offClick(remove);

												// Deinitializing the "Main Button" of the "Web App" window
												core.telegram.api.MainButton
													.offClick(add)
													.offClick(added)
													.disable()
													.hide();
											};

											const close = (event) => {
												if (
													from === wrap &&
													!card.contains(event.target) &&
													!!card &&
													!!(
														card.offsetWidth ||
														card.offsetHeight ||
														card.getClientRects().length
													)
												) {
													remove();
												}

												from = undefined;
											};

											exit.addEventListener("click", remove);
											exit.addEventListener("touch", remove);
											document.addEventListener("click", close);
											document.addEventListener("touch", close);
											window.addEventListener("popstate", remove);

											// Initializing the "Back Button" of the "Web App" window
											core.telegram.api.BackButton.show();
											core.telegram.api.BackButton.onClick(remove);

											// setTimeout(() => {
											import("./hotline.mjs").then((hotline) => {
												// Imported the hotline module
												images.hotline = new hotline.default(
													images,
												);
												images.hotline.step = -1;
												images.hotline.interval = 20;
												images.hotline.wheel = true;
												images.hotline.touch = true;
												images.hotline.events.set("transfer.beginning", true);
												images.hotline.events.set("transfer.end", true);
												images.hotline.events.set("moved.forward", true);
												images.hotline.events.set("moved.backward", true);

												if (width > card.offsetWidth) {
													images.hotline.start();
												}
											});
											// }, 300);
										}
									});

									// Exit (success)
									resolve();
								}
							}
						},
						() => reject(),
					);
				}
			} catch (e) {
				// Exit (fail)
				reject(e);
			}
		},
	},
);

Object.assign(
	catalog.search,
	{
		/**
		 * @name Search (system)
		 *
		 * @description
		 * Request search in the catalog and render result in the core.main
		 *
		 * @memberof catalog.search
		 *
		 * @return {Promise} Request to the server
		 *
		 * @todo add animations of errors
		 */
		async system(
			resolve = () => {},
			reject = () => {},
		) {
			try {
				// @todo add timeout to unblock

				// Initialize the buffer of URN parameters
				const parameters = new URLSearchParams(
					window.location.search,
				);

				// Iterate parameters
				catalog.parameters.forEach((value, parameter) => {
					if (
						(typeof value === "string" ||
							typeof value === "number") &&
						!(parameter === "text" && value === null)
					) {
						// Validated value

						// Write parameter to the buffer of URN parameters
						parameters.set(parameter, value);
					} else parameters.delete(parameter);
				});

				return await core.modules.connect("loader").then(async () => {
					// Imported the loader module

					return await core.loader.load("?" + parameters)
						.then(
							(json) => {
								if (json) {
									// Received a JSON-response

									// Initializing the search <input> element
									const input = document.querySelector("search#search>input");

									if (input instanceof HTMLElement) {
										// Found the search <input> element

										input.removeAttribute("disabled");
										// input.focus();
									}

									/**
									 * Title <h2>
									 */
									if (
										typeof json.title === "string" &&
										json.title.length > 0
									) {
										// Received and validated text of the title <h2>

										// Initializing the title <h2> element
										const title = document.getElementById("title");

										if (title instanceof HTMLElement) {
											// Found the title <h2> element

											// Writing into the title <h2> element
											title.innerText = json.title;
										} else {
											// Not found the title <h2> element

											// Initialize the title <h2> element
											const title = document.createElement("h2");

											if (core.main instanceof HTMLElement) {
												// Found the <main> element

												// Inititalize the first element in the <main> element
												const first = core.main.firstElementChild;

												if (first instanceof HTMLElement) {
													// Initialized the first element in the <main> element

													// Writing the title <h2> element before the first element in the <main> element
													core.main.insertBefore(
														title,
														first,
													);
												}
											}

											// Writing into the title <h2> element
											title.innerText = json.title;
										}
									} else {
										// Not received or not validated text of the title <h2>

										// Deleting the title <h2> element
										document.getElementById("title")?.remove();
									}

									/**
									 * Search search <search>
									 */
									if (
										typeof json.search === "string" &&
										json.search.length > 0
									) {
										// Received and validated the searcn HTML-code

										// Initializing the search <search> element
										const search = document.getElementById("search");

										if (search instanceof HTMLElement) {
											// Found the search <search> element

											// Writing into the search <search> element
											search.outerHTML = json.search;
										} else {
											// Not found the search <search> element

											// Initialize the search <search> element
											const search = document.createElement("search");

											if (core.main instanceof HTMLElement) {
												// Found the <main> element

												// Initializing the title <h2> element
												const title = document.getElementById("title");

												if (title instanceof HTMLElement) {
													// Initialized the title <h2> elemment in the <main> element

													// Writing the search <search> element after the title <h2> element in the <main> element
													core.main.insertBefore(
														search,
														title.nextElementSibling,
													);
												} else {
													// Not initialized the title <h2> element in the <main> element

													// Inititalize the first element in the <main> element
													const first = core.main.firstElementChild;

													if (first instanceof HTMLElement) {
														// Initialized the first element in the <main> element

														// Writing the search <search> element before the first element in the <main> element
														core.main.insertBefore(
															search,
															first,
														);
													}
												}
											}

											// Writing into the search <search> element
											search.outerHTML = json.search;
										}
									} else {
										// Not received or not validated the search HTML-code

										if (
											typeof json.search !== undefined && json.search === ""
										) {
											// Requested to delete the search <search> element

											// Deleting the search <search> element
											document.getElementById("search")?.remove();
										}
									}

									/**
									 * Categories
									 */
									if (
										typeof json.categories === "string" &&
										json.categories.length > 0
									) {
										// Received and validated the categories HTML-code

										// Initializing the categories <section> element
										const categories = document.getElementById("categories");

										if (categories instanceof HTMLElement) {
											// Found the categories <section> element

											// Writing into the categories <section> element
											categories.outerHTML = json.categories;
										} else {
											// Not found the categories <section> element

											// Initialize the categories <section> element
											const categories = document.createElement("section");

											if (core.main instanceof HTMLElement) {
												// Found the <main> element

												// Initializing the search <search> element
												const search = document.getElementById("search");

												if (search instanceof HTMLElement) {
													// Initialized the search <search> element in the <main> element

													// Writing the categories <section> element after the search <search> element in the <main> element
													core.main.insertBefore(
														categories,
														search.nextElementSibling,
													);
												} else {
													// Not initialized the search <search> element in the <main> element

													// Initializing the title <h2> element
													const title = document.getElementById("title");

													if (
														title instanceof HTMLElement
													) {
														// Initialized the title <h2> element in the <main> element

														// Writing the categories <section> element after the title <h2> element in the <main> element
														core.main.insertBefore(
															categories,
															title.nextElementSibling,
														);
													} else {
														// Not initialized the title <h2> element in the <main> element

														// Inititalize the first element in the <main> element
														const first = core.main.firstElementChild;

														if (first instanceof HTMLElement) {
															// Initialized the first element in the <main> element

															// Writing the categories <section> before the first element in the <main> element
															core.main.insertBefore(
																categories,
																first,
															);
														}
													}
												}
											}

											// Writing into the categories <section> element
											categories.outerHTML = json.categories;
										}
									} else {
										// Not received or not validated the categories HTML-code

										// Deleting the categories <section> element
										document.getElementById("categories")?.remove();
									}

									/**
									 * Filters
									 */
									if (
										typeof json.filters === "string" &&
										json.filters.length > 0
									) {
										// Received and validated the filters HTML-code

										// Initializing the filters <section> element
										const filters = document.getElementById("filters");

										if (filters instanceof HTMLElement) {
											// Found the filters <section> element

											// Writing into the filters <section> element
											filters.outerHTML = json.filters;
										} else {
											// Not found the filters <section> element

											// Initialize the filters <section> element
											const filters = document.createElement("section");

											if (core.main instanceof HTMLElement) {
												// Found the <main> element

												// Initializing the categories <section> element
												const categories = document.getElementById(
													"categories",
												);

												if (
													categories instanceof HTMLElement
												) {
													// Initialized the categories <section> element in the <main> element

													// Writing the filters <section> element after the categories <section> element in the <main> element
													core.main.insertBefore(
														filters,
														categories.nextElementSibling,
													);
												} else {
													// Not initialized the categories <section> element in the <main> element

													// Initializing the search <search> element
													const search = document.getElementById("search");

													if (
														search instanceof HTMLElement
													) {
														// Initialized the search <search> element in the <main> element

														// Writing the filters <section> element after the search <search> element in the <main> element
														core.main.insertBefore(
															filters,
															search.nextElementSibling,
														);
													} else {
														// Not initialized the search <search> element in the <main> element

														// Initializing the title <h2> element
														const title = document.getElementById("title");

														if (
															title instanceof HTMLElement
														) {
															// Initialized the title <h2> element in the <main> element

															// Writing the filters <section> element after the title <h2> element in the <main> element
															core.main.insertBefore(
																filters,
																title.nextElementSibling,
															);
														} else {
															// Not initialized the title <h2> element in the <main> element

															// Inititalize the first element in the <main> element
															const first = core.main.firstElementChild;

															if (first instanceof HTMLElement) {
																// Initialized the first element in the <main> element

																// Writing the filters <section> before the first element in the <main> element
																core.main.insertBefore(
																	filters,
																	first,
																);
															}
														}
													}
												}
											}

											// Writing into the filters <section> element
											filters.outerHTML = json.filters;
										}
									} else {
										// Not received or not validated the filters HTML-code

										// Deleting the filters <section> element
										document.getElementById("filters")?.remove();
									}

									/**
									 * Sorting
									 */
									if (
										typeof json.sorting === "string" &&
										json.sorting.length > 0
									) {
										// Received and validated the sorting HTML-code

										// Initializing the sorting <section> element
										const sorting = document.getElementById("sorting");

										if (sorting instanceof HTMLElement) {
											// Found the sorting <section> element

											// Writing into the sorting <section> element
											sorting.outerHTML = json.sorting;
										} else {
											// Not found the sorting <section> element

											// Initialize the sorting <section> element
											sorting = document.createElement("section");

											if (core.main instanceof HTMLElement) {
												// Found the <main> element

												// Initializing the filters <section> element
												const filters = document.getElementById("filters");

												if (filters instanceof HTMLElement) {
													// Initialized the filters <section> element in the <main> element

													// Writing the sorting <section> element after the filters <section> element in the <main> element
													core.main.insertBefore(
														sorting,
														filters.nextElementSibling,
													);
												} else {
													// Not initialized the filters <section> element in the <main> element

													// Initializing the categories <section> element
													const categories = document.getElementById(
														"categories",
													);

													if (
														categories instanceof HTMLElement
													) {
														// Initialized the categories <section> element in the <main> element

														// Writing the sorting <section> element after the categories <section> element in the <main> element
														core.main.insertBefore(
															sorting,
															categories.nextElementSibling,
														);
													} else {
														// Notnitialized the categories <section> element in the <main> element

														// Initializing the search <search> element
														const search = document.getElementById("search");

														if (
															search instanceof HTMLElement
														) {
															// Initialized the search <search> element in the <main> element

															// Writing the sorting <section> element after the search <search> element in the <main> element
															core.main.insertBefore(
																sorting,
																search.nextElementSibling,
															);
														} else {
															// Not nitialized the search <search> element in the <main> element

															// Initializing the title <h2> element
															const title = document.getElementById("title");

															if (
																title instanceof HTMLElement
															) {
																// Initialized the title <h2> element in the <main> element

																// Writing the sorting <section> element after the title <h2> element in the <main> element
																core.main.insertBefore(
																	sorting,
																	title.nextElementSibling,
																);
															} else {
																// Not initialized the title <h2> element in the <main> element

																// Inititalize the first element in the <main> element
																const first = core.main.firstElementChild;

																if (first instanceof HTMLElement) {
																	// Initialized the first element in the <main> element

																	// Writing the sorting <section> before the first element in the <main> element
																	core.main.insertBefore(
																		sorting,
																		first,
																	);
																}
															}
														}
													}
												}
											}

											// Writing into the sorting <section> element
											sorting.outerHTML = json.sorting;
										}
									} else {
										// Not received or not validated the sorting HTML-code

										// Deleting the sorting <section> element
										document.getElementById("sorting")?.remove();
									}

									/**
									 * Products
									 */
									if (
										typeof json.products === "string" &&
										json.products.length > 0
									) {
										// Received and validated the products HTML-code

										// Initializing the products <section> element
										const products = document.getElementById("products");

										if (products instanceof HTMLElement) {
											// Found the products <section> element

											// Writing into the products <section> element
											products.outerHTML = json.products;
										} else {
											// Not found the products <section> element element

											// Initialize the products <section> element
											const products = document.createElement("section");

											if (core.main instanceof HTMLElement) {
												// Found the <main> element

												// Initializing the sorting <section> element
												const sorting = document.getElementById("sorting");

												if (sorting instanceof HTMLElement) {
													// Initialized the sorting <section> element in the <main> element

													// Writing the products <section> element after the sorting <section> element in the <main> element
													core.main.insertBefore(
														products,
														sorting.nextElementSibling,
													);
												} else {
													// Initialized the sorting <section> element in the <main> element

													// Initializing the filters <section> element
													const filters = document.getElementById("filters");

													if (
														filters instanceof HTMLElement
													) {
														// Initialized the filters <section> element in the <main> element

														// Writing the products <section> element after the filters <section> element in the <main> element
														core.main.insertBefore(
															products,
															filters.nextElementSibling,
														);
													} else {
														// Not initialized the filters <section> element in the <main> element

														// Initializing the categories <section> element
														const categories = document.getElementById(
															"categories",
														);

														if (
															categories instanceof HTMLElement
														) {
															// Initialized the categories <section> element in the <main> element

															// Writing the products <section> element after the categories <section> element in the <main> element
															core.main.insertBefore(
																products,
																categories.nextElementSibling,
															);
														} else {
															// Not initialized the categories <section> element in the <main> element

															// Initializing the search <search> element
															const search = document.getElementById("search");

															if (
																search instanceof HTMLElement
															) {
																// Initialized the search <search> element in the <main> element

																// Writing the products <section> element after the search <search> element in the <main> element
																core.main.insertBefore(
																	products,
																	search.nextElementSibling,
																);
															} else {
																// Not initialized the search <search> element in the <main> element

																// Initializing the title <h2> element
																const title = document.getElementById("title");

																if (
																	title instanceof HTMLElement
																) {
																	// Initialized the title <h2> element in the <main> element

																	// Writing the products <section> element after the title <h2> element in the <main> element
																	core.main.insertBefore(
																		products,
																		title.nextElementSibling,
																	);
																} else {
																	// Not initialized the title <h2> element in the <main> element

																	// Inititalize the first element in the <main> element
																	const first = core.main.firstElementChild;

																	if (first instanceof HTMLElement) {
																		// Initialized the first element in the <main> element

																		// Writing the products <section> before the first element in the <main> element
																		core.main.insertBefore(
																			products,
																			first,
																		);
																	}
																}
															}
														}
													}
												}
											}

											// Writing into the products <section> element
											products.outerHTML = json.products;
										}
									} else {
										// Not received or not validated the products HTML-code

										// Deleting the products <section> element
										document.getElementById("products")?.remove();
									}
								}

								// Exit (success)
								resolve();
							},
							() => reject(),
						);
				});
			} catch (e) {
				// Exit (fail)
				reject(e);
			}
		},
	},
);

// Connecting to the core
if (!core.catalog) core.catalog = catalog;
