"use strict";

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

	/**
	 * @name Company (interface)
	 *
	 * @description
	 * Choose a delivery company
	 *
	 * @param {HTMLInputElement} company The button for choose a delivery company <input> (radio)
	 * @param {bool} [calculate=true] Calculate delivery if the server has confirmed the data is ready
	 * @param {bool} [force=false] Ignore the damper? (false)
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static company = (company, calculate = true, force = false) => {
		if (company instanceof HTMLInputElement) {
			// Initialized the delivery company <input> (radio) element

			// Disabling the delivery company <input> (radio) element
			company.setAttribute("disabled", true);

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

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

			if (order instanceof HTMLButtonElement) {
				// Initializeg the order <button> element

				// Disabling the order <button> element
				order.setAttribute("disabled", true);
			}

			// Initializing the delivery data request <section> element
			const request = document.getElementById("delivery_request");

			/**
			 * @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 the delivery company <input> (radio) element
					company.removeAttribute("disabled");

					if (json.status === "success") {
						// Received "success" status of execution

						// Select the delivery company <input> (radio) element
						company.checked = true;
					}

					if (json.ready) {
						// Received readiness status

						if (order instanceof HTMLButtonElement) {
							// Initializeg the order <button> element

							// Enabling the order <button> element
							order.removeAttribute("disabled");
						}

						if (request instanceof HTMLElement) {
							// Initializeg the delivery data request <section> element

							// Hiding the delivery data request <section> element
							request.classList.add("hidden");
						}
					} else {
						// Not received readiness status or readiness status is false

						if (request instanceof HTMLElement) {
							// Initializeg the delivery data request <section> element

							// Hiding the delivery data request <section> element
							request.classList.remove("hidden");
						}
					}

					// Calculating delivery
					if (calculate) this.calculate();

					if (json.company) {
						// Received company property

						// Initializing the delivery company <input> (radio) element
						const button = document.getElementById(json.company);

						if (button instanceof HTMLInputElement) {
							// Initialized the delivery company <input> (radio) element

							// Select the delivery company <input> (radio) element
							button.checked = true;
						}
					}

					if (json.delivery) {
						// Received delivery HTML-code

						core.modules.connect(["telegram"])
							.then(() => {
								//

								core.telegram.api.LocationManager.init(() => {
									//if (core.telegram.api.LocationManager.isAccessRequested && !core.telegram.api.LocationManager.isAccessGranted) {
									//	alert('Предоставьте разрешение на доступ к геопозиции');
									//	core.telegram.api.LocationManager.openSettings();
									//}

									if (!core.telegram.api.LocationManager.isLocationAvailable) {
										// Dispatching event
										document.dispatchEvent(
											new CustomEvent("core.telegram.api.location.rejected"),
										);
									} else {
										core.telegram.api.LocationManager.getLocation(
											(location) => {
												// Dispatching event
												document.dispatchEvent(
													new CustomEvent(
														"core.telegram.api.location.received",
														{
															detail: {
																location,
															},
														},
													),
												);
											},
										);
									}
								});
							});

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

						if (deliveries instanceof HTMLElement) {
							// Initialized the deliveries <div> element

							// Initializing the deliveries <section> element
							let section = deliveries.nextElementSibling;

							if (section instanceof HTMLElement) {
								// Initialized the deliveries <section> element

								// Deinitializing the delivery <section> element
								section.remove();
							}

							// Creating the delivery <section> element
							section = document.createElement("section");

							// Writing the delivery <section> element after the delivery <div> element
							deliveries.parentElement.insertBefore(
								section,
								deliveries.nextElementSibling,
							);

							// Reinitializing the delivery <section> element
							section.outerHTML = json.delivery.html;

							// Reinitializing the deliveries <section> element
							// section = document.getElementById("address");
							section = deliveries.nextElementSibling;

							for (const javascript of json.delivery.javascript) {
								// Received delivery JavaScript-code and delivery JavaScript-links

								// Initializing the delivery JavaScript-code <script> element
								const script = document.createElement("script");
								script.setAttribute("defer", "true");

								if (javascript.link) {
									// Initializing the delivery JavaScript-link <script> element attributes
									script.setAttribute("type", "text/javascript");
									script.setAttribute("src", javascript.link);
									script.setAttribute("charset", 'charset="utf-8');
								} else if (javascript.code) {
									// Delivery JavaScript-code

									// Initializing the delivery JavaScript-code <script> element value
									script.innerHTML = javascript.code;
								}

								// Writing the delivery JavaScript-code <script> element and executing the delivery JavaScript-code
								section.appendChild(script);
							}
						}
					}
				}
			};

			/**
			 * @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 the delivery company <input> (radio) element
					company.removeAttribute("disabled");
				}
			};

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

					// Execute under damper
					this.write.damper("company", company.getAttribute("id"), force)
						.then(resolved, rejected);
				},
				() => {
					// Not imported the damper module

					// Execute
					this.write.system("company", company.getAttribute("id"), force)
						.then(resolved, rejected);
				},
			);

			// Exit (success)
			return true;
		}

		// Exit (fail)
		return false;
	};

	/**
	 * @name Location (interface)
	 *
	 * @description
	 * Write name of the location for delivery
	 *
	 * @param {HTMLInputElement} location The input element with name of the location <input>
	 * @param {bool} [first=false] Select first element in <datalist> element, if received
	 * @param {bool} [calculate=false] Calculate delivery if the server has confirmed the data is ready
	 * @param {bool} [map=true] Move the map cursor to the new coordinates after calculating?
	 * @param {bool} [force=false] Ignore the damper? (false)
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static location = (
		location,
		first = false,
		calculate = true,
		map = true,
		force = false,
	) => {
		if (location instanceof HTMLInputElement) {
			// Initialized the location <input> element

			// Deleting statuses from the location <input> element
			location.classList.remove("success", "fail");

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

			if (order instanceof HTMLButtonElement) {
				// Initializeg the order <button> element

				// Disabling the order <button> element
				order.setAttribute("disabled", true);
			}

			// Initializing the delivery data request <section> element
			const request = document.getElementById("delivery_request");

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

					if (json.status) {
						// Received status of execution

						// Deleting statuses from the location <input> element
						location.classList.remove("success", "fail");

						// Writing status of execution as CSS class
						location.classList.add(json.status);
					}

					if (json.ready) {
						// Received readiness status

						if (order instanceof HTMLButtonElement) {
							// Initializeg the order <button> element

							// Enabling the order <button> element
							order.removeAttribute("disabled");
						}

						if (request instanceof HTMLElement) {
							// Initializeg the delivery data request <section> element

							// Hiding the delivery data request <section> element
							request.classList.add("hidden");
						}
					} else {
						// Not received readiness status or readiness status is false

						if (request instanceof HTMLElement) {
							// Initializeg the delivery data request <section> element

							// Hiding the delivery data request <section> element
							request.classList.remove("hidden");
						}
					}

					// Calculating delivery
					if (calculate) this.calculate(map);

					if (json.location) {
						// Received location

						if (json.location.identifier) {
							// Received location identifier

							if (location.value !== json.location) {
								// The value entered differs from what was written on the server

								// Writing attribute with location identifier
								/* location.setAttribute(
									"data-location-identifier",
									json.location.identifier,
								); */

								// Writing CSS variable with location identifier
								/* location.style.setProperty(
								"--identifier",
								json.location.identifier,
							); */
							}
						}

						if (json.location.input) {
							// Received location value for <input> element

							if (location.value !== json.location.input) {
								// The value entered differs from what was written on the server

								// Writing location property to the location <input> element
								location.value = json.location.input;
							}
						}
					}

					// Initializing the locations suggestions <datalist> element
					let locations = document.getElementById("locations");

					if (json.locations) {
						// Reveived locations suggestions

						if (!(locations instanceof HTMLDataListElement)) {
							// Not initialized the locations suggestions <datalist> element

							// Initializing the locations suggestions <datalist> element
							const datalist = document.createElement("datalist");
							datalist.setAttribute("id", "locations");

							// Connection the locations suggestions <datalist> element to the location <input> element
							location.setAttribute("list", "locations");

							// Writing the locations suggestions <datalist> element after the location <input> element
							location.parentElement.insertBefore(
								datalist,
								location.nextElementSibling,
							);

							// Reinitializing the locations suggestions <datalist> element
							locations = document.getElementById("locations");

							if (first && locations.firstelementchild?.value) {
								// Requested selecting first <option> element in the locations <datalist> element

								// Writing value from the first <option> element in the locations <datalist> element
								location.value = locations.firstelementchild.value;

								// Sending value to the server (enter into recursion)
								this.location(location, true, force);
							}
						}
					}

					if (locations instanceof HTMLDataListElement) {
						// Initialized locations suggestions <datalist> element

						// Initializing buffer of created options
						const options = new Set();

						for (const location of json.locations ?? []) {
							// Iterating over locations suggestions

							// Initializing the location <option> element
							const option = document.createElement("option");
							option.setAttribute(
								"value",
								(location.name + ", " + location.structure.reverse().join(", "))
									.trim(),
							);

							// Writing to buffer of created options
							options.add(option);
						}

						// Replacing content of the locations suggestions <datalist> element
						locations.replaceChildren(...Array.from(options));

						// locations.focus();
					}
				}
			};

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

					if (json.status) {
						// Reveived status of execution

						// Deleting statuses from the location <input> element
						location.classList.remove("success", "fail");

						// Writing status of execution as CSS class
						location.classList.add(json.status);
					}
				}
			};

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

					// Execute under damper
					this.write.damper("location", location.value, force)
						.then(resolved, rejected);
				},
				() => {
					// Not imported the damper module

					// Execute
					this.write.system("location", location.value, force)
						.then(resolved, rejected);
				},
			);

			// Exit (success)
			return true;
		}

		// Exit (fail)
		return false;
	};

	/**
	 * @name Street (interface)
	 *
	 * @description
	 * Write name of the street for delivery
	 *
	 * @param {HTMLInputElement} element The input element with name of the street <input>
	 * @param {bool} [calculate=true] Calculate delivery if the server has confirmed the data is ready
	 * @param {bool} [force=false] Ignore the damper? (false)
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static street = (street, calculate = true, force = false) => {
		if (street instanceof HTMLInputElement) {
			// Initialized the street <input> element

			// Deleting statuses from the street <input> element
			street.classList.remove("success", "fail");

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

			if (order instanceof HTMLButtonElement) {
				// Initializeg the order <button> element

				// Disabling the order <button> element
				order.setAttribute("disabled", true);
			}

			// Initializing the delivery data request <section> element
			const request = document.getElementById("delivery_request");

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

					if (json.status) {
						// Reveived status of execution

						// Deleting statuses from the street <input> element
						street.classList.remove("success", "fail");

						// Writing status of execution as CSS class
						street.classList.add(json.status);
					}

					if (json.ready) {
						// Received readiness status

						if (order instanceof HTMLButtonElement) {
							// Initializeg the order <button> element

							// Enabling the order <button> element
							order.removeAttribute("disabled");
						}

						if (request instanceof HTMLElement) {
							// Initializeg the delivery data request <section> element

							// Hiding the delivery data request <section> element
							request.classList.add("hidden");
						}

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

							core.telegram.api.HapticFeedback.notificationOccurred("success");
						});
					} else {
						// Not received readiness status or readiness status is false

						if (request instanceof HTMLElement) {
							// Initializeg the delivery data request <section> element

							// Hiding the delivery data request <section> element
							request.classList.remove("hidden");
						}
					}

					// Calculating delivery
					if (calculate) this.calculate();

					if (json.street) {
						// Received street property

						if (street.value !== json.street) {
							// The value entered differs from what was written on the server

							// Writing street property to the street element <input>
							street.value = json.street;
						}
					}
				}
			};

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

					if (json.status) {
						// Reveived status of execution

						// Deleting statuses from the street <input> element
						street.classList.remove("success", "fail");

						// Writing status of execution as CSS class
						street.classList.add(json.status);
					}
				}
			};

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

					// Execute under damper
					this.write.damper("street", street.value, force)
						.then(resolved, rejected);
				},
				() => {
					// Not imported the damper module

					// Execute
					this.write.system("street", street.value, force)
						.then(resolved, rejected);
				},
			);

			// Exit (success)
			return true;
		}

		// Exit (fail)
		return false;
	};

	/**
	 * @name Apartamet (interface)
	 *
	 * @description
	 * Write number of apartament for delivery
	 *
	 * @param {HTMLInputElement} element The input element with name of the street <input>
	 * @param {bool} [calculate=true] Calculate delivery if the server has confirmed the data is ready
	 * @param {bool} [force=false] Ignore the damper? (false)
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static apartament = (apartament, calculate = true, force = false) => {
		if (apartament instanceof HTMLInputElement) {
			// Initialized the apartament <input> element

			// Deleting statuses from the apartament <input> element
			apartament.classList.remove("success", "fail");

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

			if (order instanceof HTMLButtonElement) {
				// Initializeg the order <button> element

				// Disabling the order <button> element
				order.setAttribute("disabled", true);
			}

			// Initializing the delivery data request <section> element
			const request = document.getElementById("delivery_request");

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

					if (json.status) {
						// Reveived status of execution

						// Deleting statuses from the apartament <input> element
						apartament.classList.remove("success", "fail");

						// Writing status of execution as CSS class
						apartament.classList.add(json.status);
					}

					if (json.ready) {
						// Received readiness status

						if (order instanceof HTMLButtonElement) {
							// Initializeg the order <button> element

							// Enabling the order <button> element
							order.removeAttribute("disabled");
						}

						if (request instanceof HTMLElement) {
							// Initializeg the delivery data request <section> element

							// Hiding the delivery data request <section> element
							request.classList.add("hidden");
						}

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

							core.telegram.api.HapticFeedback.notificationOccurred("success");
						});
					} else {
						// Not received readiness status or readiness status is false

						if (request instanceof HTMLElement) {
							// Initializeg the delivery data request <section> element

							// Hiding the delivery data request <section> element
							request.classList.remove("hidden");
						}
					}

					// Calculating delivery
					if (calculate) this.calculate();

					if (json.apartament) {
						// Received apartament property

						if (apartament.value !== json.apartament) {
							// The value entered differs from what was written on the server

							// Writing street property to the apartament element <input>
							apartament.value = json.apartament;
						}
					}
				}
			};

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

					if (json.status) {
						// Reveived status of execution

						// Deleting statuses from the apartament <input> element
						apartament.classList.remove("success", "fail");

						// Writing status of execution as CSS class
						apartament.classList.add(json.status);
					}
				}
			};

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

					// Execute under damper
					this.write.damper("apartament", apartament.value, force)
						.then(resolved, rejected);
				},
				() => {
					// Not imported the damper module

					// Execute
					this.write.system("apartament", apartament.value, force)
						.then(resolved, rejected);
				},
			);

			// Exit (success)
			return true;
		}

		// Exit (fail)
		return false;
	};


	/**
	 * @name Write (interface)
	 *
	 * @return {void}
	 */
	static write = () => {};

	/**
	 * @name Calculate (interface)
	 *
	 * @description
	 * Calculate delivery by validated data from buffers
	 *
	 * @param {bool} [map=false] Move the map cursor to the new coordinates after calculating?
	 *
	 * @return {bool} Did the execution complete without errors?
	 */
	static calculate = (map = false) => {
		core.modules.connect("damper").then(
			() => {
				// Imported the damper module

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

				// Execute
				this.calculate.system(map);
			},
		);

		// Exit (success)
		return true;
	};
}

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

	Object.assign(
		delivery.write,
		{
			/**
			 * @name Write (damper)
			 *
			 * @description
			 * Validate and write a delivery parameter into buffers
			 *
			 * @memberof delivery.write
			 *
			 * @param {string} name Name of the parameter
			 * @param {string|number} value Value of the parameter
			 * @param {bool} force Ignore the damper? (false)
			 *
			 * @return {Promise}
			 */
			damper: core.damper(
				(...variables) => delivery.write.system(...variables),
				400,
				2,
			),
		},
	);

	Object.assign(
		delivery.calculate,
		{
			/**
			 * @name Calculate (damper)
			 *
			 * @description
			 * Calculate delivery by validated data from buffers
			 *
			 * @memberof delivery.calculate
			 *
			 * @param {bool} [map=false] Move the map cursor to the new coordinates after calculating?
			 *
			 * @return {Promise}
			 */
			damper: core.damper(
				(...variables) => delivery.calculate.system(...variables),
				200,
			),
		},
	);
});

Object.assign(
	delivery.write,
	{
		/**
		 * @name Write (system)
		 *
		 * @description
		 * Validate and write a delivery parameter into buffers
		 *
		 * @memberof delivery.write
		 *
		 * @param {string} name Name of the parameter
		 * @param {string|number} value Value of the parameter
		 *
		 * @return {Promise}
		 */
		async system(
			name,
			value,
			resolve = () => {},
			reject = () => {},
		) {
			try {
				if (
					typeof name === "string" &&
					(typeof value === "string" || typeof value === "number")
				) {
					// Received and validated required arguments

					// Sending request to the server
					return await core.request(
						"/delivery/write",
						`${name}=${value}`,
						"PATCH",
					)
						.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.validated) {
											// Validated delivery data from all fields

											// Unblocking the "continue" button in the summary <section> element
											document.getElementById("summary")
												?.classList.remove("disabled");
										}

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

Object.assign(
	delivery.calculate,
	{
		/**
		 * @name Calculate (system)
		 *
		 * @description
		 * Calculate delivery by validated data from buffers
		 *
		 * @memberof delivery.calculate
		 *
		 * @param {bool} [map=false] Move the map cursor to the new coordinates after calculating?
		 *
		 * @return {Promise}
		 */
		async system(
			map = false,
			resolve = () => {},
			reject = () => {},
		) {
			try {
				// Sending request to the server
				return await core.request(
					"/delivery/calculate",
					undefined,
					"GET",
				)
					.then(
						(json) => {
							if (json) {
								// Received JSON-response

								if (json.cost) {
									// Received delivery cost

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

									if (cost instanceof HTMLElement) {
										// Initialized the delivery cost <span> element

										// Writing delivery cost to the delivery cost <span> element
										cost.innerText = json.cost;
									} else {
										// Not initialized the delivery cost <span> element

										// Initializing the delivery cost <span> element
										const cost = document.createElement("span");
										cost.setAttribute("id", "cost_delivery");
										cost.classList.add(
											"cost",
											"delivery",
											"currency",
											"plus",
											"hint",
										);

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

										if (products instanceof HTMLElement) {
											// Initialized the products cost <span> element

											// Writing the delivery cost <span> element after the products cost <span> element
											products.parentElement.insertBefore(
												cost,
												products.nextElementSibling,
											);
										} else {
											// Not initialized the products cost <span> element

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

											if (amount instanceof HTMLElement) {
												// Initialized the products amount <span> element

												// Writing the delivery cost <span> element after the products amount <span> element
												amount.parentElement.insertBefore(
													cost,
													amount.nextElementSibling,
												);
											} else {
												// Not initialized the products amount <span> element

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

												if (order instanceof HTMLButtonElement) {
													// Initialized the order <button> element

													// Writing the delivery cost <span> element before the order <button> element
													order.parentElement.insertBefore(
														cost,
														order,
													);
												} else {
													// Not initialized the order <button> element

													// Initializing the summary first row <div> element
													const summary = core.main.querySelector(
														"#summary>div.row",
													);

													if (summary instanceof HTMLElement) {
														// Initialized the summary first row <div> element

														// Writing the delivery cost <span> element into the summary first row <div> element
														summary.appendChild(cost);
													}
												}
											}
										}

										// Writing delivery cost to the delivery cost <span> element
										cost.innerText = json.cost;
									}
								} else {
									// Not received delivery cost

									// Deleting the delivery cost <span> element
									document.getElementById("cost_delivery")?.remove();
								}

								if (json.days) {
									// Received delivery days

									// Initializing the delivery days <span> element
									const days = document.getElementById("shipping");

									if (days instanceof HTMLElement) {
										// Initialized the delivery days <span> element

										// Writing delivery days to the delivery days <span> element
										days.innerText = json.days;
									} else {
										// Not initialized the delivery days <span> element

										// Initializing the delivery days <span> element
										const days = document.createElement("span");
										days.setAttribute("id", "shipping");
										days.classList.add("delivery", "days", "hint");

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

										if (cost instanceof HTMLElement) {
											// Initialized the delivery cost <span> element

											// Writing the delivery days <span> element after the delivery cost <span> element
											cost.parentElement.insertBefore(
												days,
												cost.nextElementSibling,
											);
										} else {
											// Not initialized the delivery cost <span> element

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

											if (products instanceof HTMLElement) {
												// Initialized the products cost <span> element

												// Writing the delivery days <span> element after the products cost <span> element
												products.parentElement.insertBefore(
													days,
													products.nextElementSibling,
												);
											} else {
												// Not initialized the products cost <span> element

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

												if (amount instanceof HTMLElement) {
													// Initialized the products amount <span> element

													// Writing the delivery days <span> element after the products amount <span> element
													amount.parentElement.insertBefore(
														days,
														amount.nextElementSibling,
													);
												} else {
													// Not initialized the products amount <span> element

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

													if (order instanceof HTMLButtonElement) {
														// Initialized the order <button> element

														// Writing the delivery days <span> element before the order <button> element
														order.parentElement.insertBefore(
															days,
															order,
														);
													} else {
														// Not initialized the order <button> element

														// Initializing the summary first row <div> element
														const summary = core.main.querySelector(
															"#summary>div.row",
														);

														if (summary instanceof HTMLElement) {
															// Initialized the summary first row <div> element

															// Writing the delivery days <span> element into the summary first row <div> element
															summary.appendChild(days);
														}
													}
												}
											}
										}

										// Writing delivery days to the delivery days <span> element
										days.innerText = json.days;
									}
								} else {
									// Not received delivery days

									// Deleting the delivery days <span> element
									document.getElementById("shipping")?.remove();
								}

								// Dispatching event
								document.dispatchEvent(
									new CustomEvent("core.delivery.calculated", {
										detail: {
											map,
											json,
										},
									}),
								);

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

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