"use strict";

// Import dependencies
import("/js/core.js").then(() =>
	import("/js/damper.js").then(() => {
		import("/js/telegram.js").then(() => {
			import("/js/hotline.js").then(() => {
				const dependencies = setInterval(() => {
					if (
						typeof core === "function" &&
						typeof core.damper === "function" &&
						typeof core.telegram === "function" &&
						typeof core.hotline === "function"
					) {
						clearInterval(dependencies);
						clearTimeout(timeout);
						initialization();
					}
				}, 10);
				const timeout = setTimeout(() => {
					clearInterval(dependencies);
					initialization();
				}, 5000);

				function initialization() {
					if (typeof core.catalog === "undefined") {
						// Not initialized

						// Write to the core
						core.catalog = class catalog {
							/**
							 * Parameters of search
							 *
							 * Will be converted to the body of the GET request ("?name=value&name2=value2")
							 */
							static parameters = new Map([
								["text", null],
								["category", null],
								["sort", null],
								["brand", null],
							]);

							/**
							 * Search (interface)
							 *
							 * @param {Event} event Event (keyup)
							 * @param {HTMLElement} element Search bar <input>
							 * @param {bool} force Ignore the damper?
							 *
							 * @return {void}
							 */
							static search(event, element, force = false) {
								if (typeof element === "undefined") {
									element = document.getElementById("search");
								}

								element.classList.remove("error");

								if (element.value.length === 1) {
									return;
								} else {
									if (typeof event === "undefined") {
										//

										this._search(element, true);
									} else if (event.keyCode === 13) {
										// Button: "enter"

										element.setAttribute("disabled", true);

										this._search(element, force);
									} else {
										// Button: any

										this._search(element, force);
									}
								}
							}

							/**
							 * Search (damper)
							 *
							 * @param {HTMLElement} element Search bar <input>
							 * @param {bool} force Ignore the damper?
							 *
							 * @return {void}
							 */
							static _search = core.damper(
								(...variables) => this.__search(...variables),
								1400,
								2,
							);

							/**
							 * Search (system)
							 *
							 * @param {HTMLElement} element Search bar <input>
							 *
							 * @return {Promise} Request to the server
							 *
							 * @todo add animations of errors
							 */
							static __search(element) {
								if (typeof element === "undefined") {
									element = document.getElementById("search");
								}

								const urn = Array.from(this.parameters)
									.filter(([k, v]) =>
										typeof v === "string" || typeof v === "number"
									)
									.map(([k, v]) => `${k}=${v}`)
									.join("&");

								return core.request(
									"/",
									urn,
								)
									.then((json) => {
										element.removeAttribute("disabled");
										element.focus();

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

											element.classList.add("error");
										} else {
											// Errors not received

											history.pushState(
												{},
												urn,
												urn,
											);

											if (
												typeof json.title === "string" &&
												json.title.length > 0
											) {
												// Received the page title

												// Initialize a link to the categories list
												const title = core.main.getElementsByTagName("h2")[0];

												// Write the title
												title.innerText = json.title;
											}

											// Deinitialization of the categories
											const categories = core.main.querySelector(
												'section[data-catalog-type="categories"]',
											);
											// if (categories instanceof HTMLElement) categories.remove();

											if (
												typeof json.html.categories === "string" &&
												json.html.categories.length > 0
											) {
												// Received categories (reinitialization of the categories)

												const categories = core.main.querySelector(
													'section[data-catalog-type="categories"]',
												);

												if (categories instanceof HTMLElement) {
													// Found list of categories

													categories.outerHTML = json.html.categories;
												} else {
													// Not found list of categories

													const element = document.createElement("section");

													const search = core.main.querySelector(
														'search[data-section="search"]',
													);

													if (search instanceof HTMLElement) {
														core.main.insertBefore(
															element,
															search.nextSibling,
														);
													} else {
														core.main.append(element);
													}

													element.outerHTML = json.html.categories;
												}
											} else {
												// Not received categories (deinitialization of the categories)

												const categories = core.main.querySelector(
													'section[data-catalog-type="categories"',
												);

												if (categories instanceof HTMLElement) {
													categories.remove();
												}
											}

											if (
												typeof json.html.products === "string" &&
												json.html.products.length > 0
											) {
												// Received products (reinitialization of the products)

												const products = core.main.querySelector(
													'section[data-catalog-type="products"]',
												);

												if (products instanceof HTMLElement) {
													// Found list of products

													products.outerHTML = json.html.products;
												} else {
													// Not found list of products

													const element = document.createElement("section");

													const categories = core.main.querySelector(
														'section[data-catalog-type="categories"',
													);

													if (categories instanceof HTMLElement) {
														//

														//
														core.main.insertBefore(
															element,
															categories.nextSibling,
														);

														element.outerHTML = json.html.products;
													} else {
														//

														//
														const search = core.main.querySelector(
															'search[data-section="search"]',
														);

														if (search instanceof HTMLElement) {
															core.main.insertBefore(
																element,
																search.nextSibling,
															);

															element.outerHTML = json.html.products;
														}
													}
												}
											} else {
												// Not received products (deinitialization of the products)

												const products = core.main.querySelector(
													'section[data-catalog-type="products"]',
												);

												if (products instanceof HTMLElement) {
													products.remove();
												}
											}
										}
									});
							}

							/**
							 * Open product card (interface)
							 *
							 * @param {HTMLElement} button Button of a product <a>
							 * @param {bool} force Ignore the damper?
							 *
							 * @return {void}
							 */
							static product(button, force = false) {
								// Initializing identifier of the category
								const identifier = button.getAttribute(
									"data-product-identifier",
								);

								this._product(identifier, force);
							}

							/**
							 * Open product card (damper)
							 *
							 * @param {string} identifier Identifier of a product
							 * @param {bool} force Ignore the damper?
							 *
							 * @return {void}
							 */
							static _product = core.damper(
								(...variables) => this.__product(...variables),
								400,
								1,
							);

							/**
							 * Open product card (system)
							 *
							 * @param {string} identifier Identifier of a product
							 *
							 * @return {Promise} Request to the server
							 */
							static __product(identifier) {
								if (typeof identifier === "string") {
									//

									//
									const urn = `?product=${identifier}`;

									return core.request(urn)
										.then((json) => {
											if (
												json.errors !== null &&
												typeof json.errors === "object" &&
												json.errors.length > 0
											) {
												// Errors received
											} else {
												// Errors not received

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

													// 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", "unselectable");

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

													const name = document.createElement("span");
													name.classList.add("name");
													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.classList.add("images", "unselectable");

													const button = core.telegram.api.isVisible;

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

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

																if (
																	_x - x < 10 &&
																	_x - x > -10 &&
																	_y - y < 10 &&
																	_y - y > -10
																) {
																	images.classList.add("extend");

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

																	setTimeout(() => {
																		images.hotline.step = 0;
																		images.hotline.wheel = false;
																		images.hotline.start();
																		images.addEventListener("mouseup", _close);
																		images.addEventListener("touchend", _close);
																	}, 300);
																	images.removeEventListener("mouseup", _open);
																	images.removeEventListener("touchend", _open);
																}
															}
														}
													};

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

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

																images.hotline.step = -0.3;
																images.hotline.wheel = true;

																if (width < card.offsetWidth) {
																	images.hotline.stop();
																}
																images.classList.remove("extend");

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

																images.removeEventListener("mouseup", _close);
																images.removeEventListener("touchend", _close);
																images.addEventListener("mousedown", _start);
																images.addEventListener("touchstart", _start);
															}
														}
													};

													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);

													for (const uri of json.product.images) {
														const image = document.createElement("img");
														image.setAttribute("src", uri);
														image.setAttribute("ondragstart", "return false;");

														images.append(image);
													}

													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");
													cost.innerText = json.product.cost + "р";

													h3.append(name);
													exit.append(exit_icon);
													h3.append(exit);
													card.append(h3);
													card.append(images);
													header.append(brand);
													card.append(header);
													card.append(description);
													card.append(compatibility);
													footer.append(dimensions);
													footer.append(weight);
													footer.append(cost);
													card.append(footer);
													wrap.append(card);
													core.main.append(wrap);

													let width = 0;
													let buffer;
													[...images.children].forEach((child) =>
														width += child.offsetWidth + (isNaN(
																buffer = parseFloat(
																	getComputedStyle(child).marginRight,
																),
															)
															? 0
															: buffer)
													);

													history.pushState(
														{ identifier },
														json.product.name,
														urn,
													);

													// блокировка закрытия карточки
													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();

														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);
													};

													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);

													images.hotline = new core.hotline(
														json.product.identfier,
														images,
													);
													images.hotline.step = -0.3;
													images.hotline.wheel = true;
													images.hotline.touch = true;

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