"use strict";

/**
 * @name Cart
 *
 * @description
 * Implements actions with cart
 *
 * @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 cart {
	/**
	 * @name Type of the program
	 */
	static type = "module";

	/**
	 * @name Toggle (interface)
	 *
	 * @description
	 * Toggle the product in the cart
	 *
	 * @param {HTMLButtonElement|HTMLInputElement|null} element Handler elememnt of the product
	 * @param {HTMLElement} product The product element
	 * @param {bool} remove Remove the product element if json.amount === 0?
	 * @param {bool} force Ignore the damper? (false)
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static toggle(element, product, remove = false, force = false) {
		// Blocking the element
		element?.setAttribute("disabled", "true");

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

				// Execute under damper
				this.product.damper(
					element,
					product,
					"toggle",
					undefined,
					remove,
					force,
				);
			},
			() => {
				// Not imported the damper module

				// Execute
				this.product.system(
					element,
					product,
					"toggle",
					undefined,
					remove,
					force,
				);
			},
		);

		// Exit (success)
		return true;
	}

	/**
	 * @name Write (interface)
	 *
	 * @description
	 * Write the product in the cart
	 *
	 * @param {HTMLButtonElement|HTMLInputElement|null} element Handler elememnt of the product
	 * @param {HTMLElement} product The product element
	 * @param {number} amount Amount of writings
	 * @param {bool} remove Remove the product element if json.amount === 0?
	 * @param {bool} force Ignore the damper? (false)
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static write(
		element,
		product,
		amount = 1,
		remove = false,
		force = false,
	) {
		// Blocking the element
		element?.setAttribute("disabled", "true");

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

				// Execute under damper
				this.product.damper(
					element,
					product,
					"write",
					amount,
					remove,
					force,
				);
			},
			() => {
				// Not imported the damper module

				// Execute
				this.product.system(
					element,
					product,
					"write",
					amount,
					remove,
					force,
				);
			},
		);

		// Exit (success)
		return true;
	}

	/**
	 * @name Delete (interface)
	 *
	 * @description
	 * Delete the product from the cart
	 *
	 * @param {HTMLButtonElement|HTMLInputElement|null} element Handler elememnt of the product
	 * @param {HTMLElement} product The product element
	 * @param {number} amount Amount of deletings
	 * @param {bool} remove Remove the product element if json.amount === 0?
	 * @param {bool} force Ignore the damper? (false)
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static delete(
		element,
		product,
		amount = 1,
		remove = false,
		force = false,
	) {
		// Blocking the element
		element?.setAttribute("disabled", "true");

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

				// Execute under damper
				this.product.damper(
					element,
					product,
					"delete",
					amount,
					remove,
					force,
				);
			},
			() => {
				// Not imported the damper module

				// Execute
				this.product.system(
					element,
					product,
					"delete",
					amount,
					remove,
					force,
				);
			},
		);

		// Exit (success)
		return true;
	}

	/**
	 * @name Set (interface)
	 *
	 * @description
	 * Set amount of the product in the cart
	 *
	 * @param {HTMLButtonElement|HTMLInputElement|null} element Handler elememnt of the product
	 * @param {HTMLElement} product The product element
	 * @param {number} amount Amount of the product in the cart to be setted
	 * @param {bool} remove Remove the product element if json.amount === 0?
	 * @param {bool} force Ignore the damper? (false)
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static set(
		element,
		product,
		amount = 1,
		remove = false,
		force = false,
	) {
		// Blocking the element
		element?.setAttribute("disabled", "true");

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

				// Execute under damper
				this.product.damper(
					element,
					product,
					"set",
					amount,
					remove,
					force,
				);
			},
			() => {
				// Not imported the damper module

				// Execute
				this.product.system(
					element,
					product,
					"set",
					amount,
					remove,
					force,
				);
			},
		);

		// Exit (success)
		return true;
	}

	/**
	 * @name Product (interface)
	 *
	 * @description
	 * Handle the product in the cart
	 *
	 * @param {HTMLButtonElement|HTMLInputElement|null} element Handler element of the product
	 * @param {HTMLElement} product The product element
	 * @param {string} type Type of action with the product
	 * @param {number} amount Amount of product to handle
	 * @param {bool} remove Remove the product element if json.amount === 0?
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static product(
		element,
		product,
		type,
		amount = null,
		remove = false,
	) {
		core.modules.connect("damper").then(
			() => {
				// Imported the damper module

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

				// Execute
				this.product.system(
					element,
					product,
					type,
					amount,
					remove,
					force,
				);
			},
		);

		// Exit (success)
		return true;
	}

	/**
	 * @name Summary (interface)
	 *
	 * @description
	 * Initialize summary of products the cart
	 *
	 * @param {HTMLButtonElement} button Button <button>
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static summary(button) {
		// Disabling button
		button?.setAttribute("disabled", true);

		// Initializing timer of enabling the delivery company <input> (radio) element
		const enabling = setTimeout(() => {
			// Enabling button
			button?.removeAttribute("disabled");
		}, 3000);

		/**
		 * @name Resolved
		 *
		 * @description
		 * Render the result of the resolved request
		 *
		 * @param {object} json
		 *
		 * @return {void}
		 */
		const resolved = (json) => {
			if (json) {
				// Received JSON-response

				// Deinitializing timer of enabling the delivery company <input> (radio) element
				clearTimeout(enabling);

				// Enabling button
				button?.removeAttribute("disabled");
			}
		};

		/**
		 * @name Rejected
		 *
		 * @description
		 * Render the result of the rejected request
		 *
		 * @param {object} json
		 *
		 * @return {void}
		 */
		const rejected = (json) => {
			if (json) {
				// Received JSON-response

				// Deinitializing timer of enabling the delivery company <input> (radio) element
				clearTimeout(enabling);

				// Enabling button
				button?.removeAttribute("disabled");
			}
		};

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

				// Execute under damper
				this.summary.damper()
					.then(resolved, rejected);
			},
			() => {
				// Not imported the damper module

				// Execute
				this.summary.system()
					.then(resolved, rejected);
			},
		);

		// Exit (success)
		return true;
	}

	/**
	 * @name Share (interface)
	 *
	 * @description
	 * Generate sharing hash of the cart and sent ot to the chat-robot
	 *
	 * @param {HTMLButtonElement} button Button <button>
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static async share(button) {
		return await core.modules.connect("telegram").then(
			() => {
				// Imported the damper module

				// Disabling button
				button?.setAttribute("disabled", true);

				// Initializing timer of enabling the delivery company <input> (radio) element
				const enabling = setTimeout(() => {
					// Enabling button
					button?.removeAttribute("disabled");
				}, 3000);

				/**
				 * @name Resolved
				 *
				 * @description
				 * Render the result of the resolved request
				 *
				 * @param {object} json
				 *
				 * @return {void}
				 */
				const resolved = (json) => {
					if (json) {
						// Received JSON-response

						// Deinitializing timer of enabling the delivery company <input> (radio) element
						clearTimeout(enabling);

						// Enabling button
						button?.removeAttribute("disabled");
					}
				};

				/**
				 * @name Rejected
				 *
				 * @description
				 * Render the result of the rejected request
				 *
				 * @param {object} json
				 *
				 * @return {void}
				 */
				const rejected = (json) => {
					if (json) {
						// Received JSON-response

						// Deinitializing timer of enabling the delivery company <input> (radio) element
						clearTimeout(enabling);

						// Enabling button
						button?.removeAttribute("disabled");
					}
				};

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

						// Execute under damper
						this.share.damper()
							.then(resolved, rejected);
					},
					() => {
						// Not imported the damper module

						// Execute
						this.share.system()
							.then(resolved, rejected);
					},
				);

				// Exit (success)
				return true;
			},
			// Exit (fail)
			() => false,
		);
	}
}

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

	Object.assign(
		cart.product,
		{
			/**
			 * @name Product (damper)
			 *
			 * @description
			 * Handle the product in the cart
			 *
			 * @memberof cart.product
			 *
			 * @param {HTMLButtonElement|HTMLInputElement} element Handler elememnt of the product
			 * @param {HTMLElement} product The product element
			 * @param {bool} remove Remove the product element if json.amount === 0?
			 * @param {bool} force Ignore the damper? (false)
			 *
			 * @return {Promise}
			 */
			damper: core.damper(
				(...variables) =>
					cart.product.system(...variables).then(cart.summary.system),
				300,
				5,
			),
		},
	);

	Object.assign(
		cart.summary,
		{
			/**
			 * @name Summary (damper)
			 *
			 * @description
			 * Initialize summary of products the cart
			 *
			 * @memberof cart.summary
			 *
			 * @return {Promise}
			 */
			damper: core.damper(
				(...variables) => cart.summary.system(...variables),
				300,
			),
		},
	);

	Object.assign(
		cart.share,
		{
			/**
			 * @name Share (damper)
			 *
			 * @description
			 * Generate sharing hash of the cart and sent ot to the chat-robot
			 *
			 * @memberof cart.share
			 *
			 * @return {Promise}
			 */
			damper: core.damper(
				(...variables) => cart.share.system(...variables),
				400,
			),
		},
	);
});

Object.assign(
	cart.product,
	{
		/**
		 * @name Product (system)
		 *
		 * @description
		 * Handle the product in the cart
		 *
		 * @memberof cart.product
		 *
		 * @param {HTMLButtonElement|HTMLInputElement|null} element Handler element of the product
		 * @param {HTMLElement} product The product element
		 * @param {string} type Type of action with the product
		 * @param {number} amount Amount of product to handle
		 * @param {bool} remove Remove the product element if json.amount === 0?
		 *
		 * @return {Promise|null}
		 */
		async system(
			element,
			product,
			type,
			amount = null,
			remove = false,
			resolve = () => {},
			reject = () => {},
		) {
			try {
				if (product instanceof HTMLElement) {
					// Validated required arguments

					// Initializing the buffer of request body
					let request = "";

					// Initializing of identifier of the product
					const identifier = +product.getAttribute(
						"data-product-identifier",
					);

					if (typeof identifier === "number") {
						// Validated identifier

						// Writing to the buffer of request body
						request += "&identifier=" + identifier;

						if (
							type === "toggle" ||
							type === "write" ||
							type === "delete" ||
							type === "set"
						) {
							// Validated type

							// Writing to the buffer of request body
							request += "&type=" + type;

							if (
								(type === "toggle" &&
										amount === null ||
									typeof amount === "undefined") ||
								(type === "set" &&
										amount === 0 ||
									amount === 100) ||
								typeof amount === "number" &&
									amount > 0 &&
									amount < 100
							) {
								// Validated amount

								if (type !== "toggle") {
									// Not a toggle request

									// Writing to the buffer of request body
									request += "&amount=" + amount;
								}

								// Request
								return await core.request(
									"/cart/product",
									request,
									"PATCH",
								)
									.then(
										(json) => {
											if (json) {
												// Received a JSON-response

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

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

														core.telegram.api.HapticFeedback
															.notificationOccurred("error");
													});

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

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

														core.telegram.api.HapticFeedback
															.notificationOccurred("success");
													});

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

															// Calculating delivery
															core.delivery.calculate();
														},
													);

													if (remove && json.amount === 0) {
														// Requested deleting of the product element when there is no the product in the cart

														// Deleting the product element
														product.remove();
													} else {
														// Not requested deleting the product element when there is no the product in the cart

														// Unblocking the element
														element?.removeAttribute("disabled");

														// Writing offset of hue-rotate to indicate that the product is in the cart
														product.style.setProperty(
															"--hue-rotate-offset",
															json.amount + "0deg",
														);

														// Writing attribute with amount of the product in the cart
														product.setAttribute(
															"data-product-amount",
															json.amount,
														);

														// Initializing the amount <span> element
														const amounts = product.querySelectorAll(
															'[data-product-parameter="amount"]',
														);

														for (const amount of amounts) {
															// Iterating over an amount elements

															if (amount instanceof HTMLInputElement) {
																// The <input> element

																// Writing amount of the product in the cart
																amount.value = json.amount;
															} else {
																// Not the <input> element

																// Writing amount of the product in the cart
																amount.innerText = json.amount;
															}
														}
													}

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

Object.assign(
	cart.summary,
	{
		/**
		 * @name Summary (system)
		 *
		 * @description
		 * Initialize summary of products the cart
		 *
		 * @memberof cart.summary
		 *
		 * @return {Promise}
		 */
		async system(
			resolve = () => {},
			reject = () => {},
		) {
			try {
				// Request
				return await core.request("/cart/summary", undefined, "GET")
					.then((json) => {
						if (json) {
							// Received a JSON-response

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

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

									core.telegram.api.HapticFeedback.notificationOccurred(
										"error",
									);
								});

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

								// Initializing the summary amount <span> element
								const amount = document.getElementById("amount");

								if (amount instanceof HTMLElement) {
									// Initialized the summary amount element

									// Writing summary amount into the summary amount element
									amount.innerText = json.amount;
								}

								// Initializing the summary cost <span> element
								const cost = document.getElementById("cost");

								if (cost instanceof HTMLElement) {
									// Initialized the summary cost element

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

										core.telegram.api.HapticFeedback.notificationOccurred(
											"success",
										);
									});

									// Writing summary cost into the summary cost element
									cost.innerText = json.cost;
								}

								// Dispatching event
								document.dispatchEvent(
									new CustomEvent("core.cart.summary.received", {
										detail: {
											json,
										},
									}),
								);

								// Exit (success)
								resolve(json);
							}

							// Exit (fail)
							reject(json);
						}
					});
			} catch (e) {
				// Exit (fail)
				reject(e);
			}
		},
	},
);

Object.assign(
	cart.share,
	{
		/**
		 * @name Share (system)
		 *
		 * @description
		 * Generate sharing hash of the cart and sent ot to the chat-robot
		 *
		 * @memberof cart.share
		 *
		 * @return {Promise}
		 */
		async system(
			resolve = () => {},
			reject = () => {},
		) {
			try {
				// Request
				return await core.request("/cart/share", undefined, "POST")
					.then((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 (json.share) {
									// Received sharing hash

									// Request to the chat-robot
									core.telegram.api.sendData(
										JSON.stringify({
											type: "cart_share",
											hash: json.share,
										}),
									);
								}

								/* if (json.robokassa) {
									// Received data for the Robokassa acquiring

									// Initializing iframe
									Robokassa.StartPayment({
										MerchantLogin: json.robokassa.identifier,
										OutSum: json.robokassa.cost,
										InvId: json.robokassa.cart,
										Description: json.robokassa.description,
										Culture: json.robokassa.language,
										Encoding: "utf-8",
										Settings: JSON.stringify({
											PaymentMethods: ["BankCard", "SBP"],
											Mode: "modal",
										}),
										SignatureValue: json.robokassa.hash,
									});
								} */

								// Exit (success)
								resolve(json);
							}

							// Exit (fail)
							reject(json);
						}
					});
			} catch (e) {
				// Exit (fail)
				reject(e);
			}
		},
	},
);

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