jingrow.ui.OnboardingTour = class OnboardingTour {
	constructor() {
		this.driver_steps = [];
		this.last_step_saved = null;
		this.last_element_clicked = null;
	}

	init_driver() {
		this.driver = new jingrow.Driver({
			className: "jingrow-driver",
			allowClose: false,
			padding: 10,
			overlayClickNext: false,
			keyboardControl: false,
			nextBtnText: __("Next"),
			prevBtnText: __("Previous"),
			doneBtnText: __("Done"),
			closeBtnText: __("Skip"),
			opacity: 0.5,
			onHighlighted: (step) => {
				jingrow.ui.next_form_tour = step.options.step_info?.next_form_tour;
				const wait_for_node = setInterval(() => {
					if (!step.popover.node) return;
					if (step.options.step_info?.offset_x) {
						step.popover.node.style.left = `${
							step.popover.node.offsetLeft + step.options.step_info.offset_x
						}px`;
					}
					if (step.options.step_info?.offset_y) {
						step.popover.node.style.top = `${
							step.popover.node.offsetTop + step.options.step_info.offset_y
						}px`;
					}
					if (step.popover.node.offsetLeft < 0) {
						step.popover.node.style.minWidth = "200px";
						step.popover.node.style.maxWidth = `${
							350 + step.popover.node.offsetLeft
						}px`;
						step.popover.node.style.left = "0px";
					}
					if (step.popover.closeBtnNode) {
						step.popover.closeBtnNode.onclick = () => {
							this.on_finish && this.on_finish();
							!jingrow.boot.user.onboarding_status[this.tour.name] &&
								(jingrow.boot.user.onboarding_status[this.tour.name] = {});
							jingrow.boot.user.onboarding_status[this.tour.name].is_complete = true;
							if (!this.driver.hasNextStep()) {
								jingrow.boot.user.onboarding_status[
									this.tour.name
								].all_steps_completed = true;
							}

							jingrow.call({
								method: "jingrow.desk.pagetype.form_tour.form_tour.update_user_status",
								args: {
									value: JSON.stringify(jingrow.boot.user.onboarding_status),
									step: JSON.stringify(step.options.step_info),
								},
							});
						};
					}
					clearInterval(wait_for_node);
				}, 300);

				// focus on first input.
				// TODO : later add option to select which input to focus as well.
				const $input = $(step.node).find("input").get(0);
				if ($input) jingrow.utils.sleep(200).then(() => $input.focus());
			},
		});
	}

	async init({ tour_name, start_step }) {
		this.tour = await jingrow.db.get_pg("Form Tour", tour_name);
		this.init_driver();
		this.build_steps();
		this.update_driver_steps();
		if (!this.tour.track_steps) {
			start_step = 0;
		}
		this.start(start_step);
	}

	build_steps() {
		this.driver_steps = [];
		this.tour.steps.forEach((step) => {
			const on_next = async (el) => {
				const step_index = this.driver.steps.indexOf(el);
				if (step_index == -1 || this.last_step_saved?.name == step.name) return;
				jingrow.boot.user.onboarding_status[this.tour.name] = {
					steps_complete: step_index,
				};
				if (!this.driver.hasNextStep()) {
					this.on_finish && this.on_finish();
					jingrow.boot.user.onboarding_status[this.tour.name].is_complete = true;
				}
				this.last_step_saved = step;
				jingrow.call({
					method: "jingrow.desk.pagetype.form_tour.form_tour.update_user_status",
					args: {
						value: JSON.stringify(jingrow.boot.user.onboarding_status),
						step: JSON.stringify(step),
					},
				});
			};
			const driver_step = this.get_step(step, on_next);
			driver_step.element && this.driver_steps.push(driver_step);
		});
	}

	get_step(step_info, on_next) {
		const {
			name,
			element_selector,
			title,
			description,
			ondemand_description,
			position,
			parent_element_selector,
			hide_buttons,
			next_on_click,
			popover_element,
			modal_trigger,
		} = step_info;
		let element = cur_page?.page.querySelector(element_selector);
		!element && (element = document.querySelector(element_selector));
		if (element && parent_element_selector) {
			element = element.closest(parent_element_selector);
		}
		if (element && (next_on_click || hide_buttons || modal_trigger)) {
			$(element).on("click", () => {
				if (
					!this.driver.getHighlightedElement() ||
					this.driver.getHighlightedElement().node.id?.startsWith("popover")
				)
					return;

				if (
					modal_trigger &&
					(!this.last_element_clicked ||
						new Date().getTime() - new Date(this.last_element_clicked).getTime() >
							1000)
				) {
					this.last_element_clicked = new Date().getTime();
					this.handle_modal_steps(this.driver.currentStep, title, ondemand_description);
					return;
				}

				if (!popover_element) {
					on_next(this.driver.getHighlightedElement());
					this.driver.moveNext();
					this.driver.overlay.refresh();
				}

				if (!this.driver.getHighlightedElement()) return;
				on_next(this.driver.getHighlightedElement());
				let popover = this.driver
					.getHighlightedElement()
					.node.getAttribute("aria-describedby")
					? this.driver.getHighlightedElement().node
					: this.driver
							.getHighlightedElement()
							.node.querySelector('[aria-describedby^="popover"]');

				if (!popover) return;

				let popover_id = popover.getAttribute("aria-describedby");
				let step_index = this.driver.steps.indexOf(this.driver.getHighlightedElement());

				if (this.driver_steps[step_index + 1]?.element.id == popover_id) return;

				this.driver_steps = this.driver_steps.filter(
					(step) => !step.element.id?.startsWith("popover")
				);

				let new_step = { ...this.driver_steps[step_index] };
				new_step.element = document.getElementById(popover_id);
				new_step.showButtons = false;
				ondemand_description && (new_step.popover.description = ondemand_description);

				this.driver_steps.splice(this.driver.currentStep + 1, 0, new_step);
				this.update_driver_steps();
				this.driver.moveNext();
				this.driver.overlay.refresh();

				$(popover).one("hide.bs.popover", (e) => {
					this.driver_steps.splice(this.driver.currentStep, 1);
					this.driver_steps[this.driver.currentStep - 1].showButtons = true;
					new_step.popover.description = description;
					this.update_driver_steps();
					this.driver.movePrevious();
					this.driver.overlay.refresh();
				});
			});
		}

		let showButtons = true;
		if (popover_element || hide_buttons) {
			showButtons = false;
		}
		return {
			element,
			name,
			popover: {
				title,
				description,
				position: jingrow.router.slug(position || "Bottom"),
			},
			onNext: on_next,
			step_info: step_info,
			showButtons,
		};
	}

	update_driver_steps(steps = []) {
		if (steps.length == 0) {
			steps = this.driver_steps;
		}
		this.driver.defineSteps(steps);
	}

	start(idx = 0) {
		if (this.driver_steps.length == 0) {
			return;
		}
		this.driver.start(idx);
	}

	handle_modal_steps(step, title, description) {
		setTimeout(() => {
			const modal_element = $(".modal-content");
			const attach_dialog_step = {
				element: modal_element[0],
				allowClose: false,
				overlayClickNext: false,
				popover: {
					title,
					description,
					position: "left-center",
					doneBtnText: __("Next"),
				},
			};
			this.driver_steps.splice(step + 1, 0, attach_dialog_step);
			this.update_driver_steps(); // need to define again, since driver.js only considers steps which are inside DOM
			this.driver.reset();
			this.driver.start(step + 1);
			this.driver.overlay.refresh();
			modal_element.closest(".modal").one("hide.bs.modal", () => {
				this.driver_steps.splice(this.driver.currentStep, 1);
				this.update_driver_steps();
				this.driver.movePrevious();
				this.driver.moveNext();
				this.driver.overlay.refresh();
			});
		}, 500);
	}
};

jingrow.ui.init_onboarding_tour = () => {
	// As of now Tours are only for desktop as it is annoying on mobile.
	// Also lot of elements are hidden on mobile so until we find a better way to do it.
	if (!window.matchMedia("(min-device-width: 992px)").matches) return;

	typeof jingrow.boot.onboarding_tours == "undefined" && jingrow.boot.onboarding_tours == [];
	typeof jingrow.boot.user.onboarding_status == "undefined" &&
		jingrow.boot.user.onboarding_status == {};
	let route = jingrow.router.current_route;
	if (route?.[0] === "") return;

	let tour_name;
	let matching_tours = [];
	let start_step;
	if (route[0] == "query-report") {
		route = ["List", route[1], "Report"];
	}
	if (route[0] != "dashboard-view") {
		jingrow.boot.onboarding_tours &&
			jingrow.boot.onboarding_tours.forEach((tour) => {
				let tour_route = tour[1];
				let length = Math.min(route.length, tour_route.length);
				if (length >= 1 && route[0] != tour_route[0]) return;
				if (length >= 2 && tour_route[1] != "*" && route[1] != tour_route[1]) return;
				if (
					length >= 3 &&
					["*", "new-*"].indexOf(tour_route[2]) == -1 &&
					route[2] != tour_route[2]
				)
					return;
				matching_tours.push(tour);
			});
	}
	matching_tours = matching_tours.filter((tour) => {
		if (jingrow.boot.user.onboarding_status[tour[0]]?.is_complete == true) return false;
		return true;
	});
	matching_tours = matching_tours.map((tour) => {
		if (jingrow.boot.user.onboarding_status[tour[0]]?.steps_complete != undefined) {
			tour.push(jingrow.boot.user.onboarding_status[tour[0]].steps_complete);
		}
		return tour;
	});
	if (matching_tours.length == 0) return;
	let current_tour = matching_tours.find(
		(tour) => tour[0] == jingrow.ui.currentTourInstance?.tour?.name
	);
	let next_tour = matching_tours.find((tour) => tour[0] == jingrow.ui.next_form_tour);
	if (current_tour) {
		tour_name = current_tour[0];
		start_step = current_tour.at(-1);
		if (typeof start_step != "number") {
			start_step = 0;
		}
	} else if (next_tour) {
		tour_name = next_tour[0];
		start_step = next_tour.at(-1);
		if (typeof start_step != "number") {
			start_step = 0;
		} else {
			start_step += 1;
		}
		jingrow.ui.next_form_tour = undefined;
	} else {
		tour_name = matching_tours[0][0];
		start_step = matching_tours[0].at(-1);
		if (typeof start_step != "number") {
			start_step = 0;
		} else {
			start_step += 1;
		}
	}
	if (!tour_name) return;
	if (jingrow.ui.currentTourInstance?.driver) {
		jingrow.ui.currentTourInstance.driver_steps = [];
		jingrow.ui.currentTourInstance.driver.reset(true);
		jingrow.ui.currentTourInstance.update_driver_steps();
	}
	const tour = (jingrow.ui.currentTourInstance = new jingrow.ui.OnboardingTour());
	// wait for workspace and/or data to load.
	const wait_for_data = setInterval(() => {
		if (cur_page?.page.querySelector(".workspace-sidebar-skeleton")) return;
		if (cur_page?.page.querySelector(".workspace-skeleton")) return;
		if (document.body.getAttribute("data-ajax-state") === "complete") {
			jingrow.utils.sleep(500).then(() => {
				tour.init({
					tour_name,
					start_step,
				});
				clearInterval(wait_for_data);
			});
		}
	}, 100);
};

jingrow.router.on("change", () => {
	jingrow.ui.init_onboarding_tour();
});
