// Copyright (c) 2015, InfluxFramework LLC
// MIT License. See license.txt
/* eslint-disable no-console */

// __('Modules') __('Domains') __('Places') __('Administration') # for translation, don't remove

influxframework.start_app = function () {
	if (!influxframework.Application) return;
	influxframework.assets.check();
	influxframework.provide("influxframework.app");
	influxframework.provide("influxframework.desk");
	influxframework.app = new influxframework.Application();
};

$(document).ready(function () {
	if (!influxframework.utils.supportsES6) {
		influxframework.msgprint({
			indicator: "red",
			title: __("Browser not supported"),
			message: __(
				"Some of the features might not work in your browser. Please update your browser to the latest version."
			),
		});
	}
	influxframework.start_app();
});

influxframework.Application = class Application {
	constructor() {
		this.startup();
	}

	startup() {
		influxframework.socketio.init();
		influxframework.model.init();

		if (influxframework.boot.status === "failed") {
			influxframework.msgprint({
				message: influxframework.boot.error,
				title: __("Session Start Failed"),
				indicator: "red",
			});
			throw "boot failed";
		}

		this.setup_influxframework_vue();
		this.load_bootinfo();
		this.load_user_permissions();
		this.make_nav_bar();
		this.set_favicon();
		this.setup_analytics();
		this.set_fullwidth_if_enabled();
		this.add_browser_class();
		this.setup_energy_point_listeners();
		this.setup_copy_doc_listener();

		influxframework.ui.keys.setup();

		influxframework.ui.keys.add_shortcut({
			shortcut: "shift+ctrl+g",
			description: __("Switch Theme"),
			action: () => {
				if (influxframework.theme_switcher && influxframework.theme_switcher.dialog.is_visible) {
					influxframework.theme_switcher.hide();
				} else {
					influxframework.theme_switcher = new influxframework.ui.ThemeSwitcher();
					influxframework.theme_switcher.show();
				}
			},
		});

		influxframework.ui.add_system_theme_switch_listener();
		const root = document.documentElement;

		const observer = new MutationObserver(() => {
			influxframework.ui.set_theme();
		});
		observer.observe(root, {
			attributes: true,
			attributeFilter: ["data-theme-mode"],
		});

		influxframework.ui.set_theme();

		// page container
		this.make_page_container();
		this.set_route();

		// trigger app startup
		$(document).trigger("startup");

		$(document).trigger("app_ready");

		if (influxframework.boot.messages) {
			influxframework.msgprint(influxframework.boot.messages);
		}

		if (influxframework.user_roles.includes("System Manager")) {
			// delayed following requests to make boot faster
			setTimeout(() => {
				this.show_change_log();
				this.show_update_available();
			}, 1000);
		}

		if (!influxframework.boot.developer_mode) {
			let console_security_message = __(
				"Using this console may allow attackers to impersonate you and steal your information. Do not enter or paste code that you do not understand."
			);
			console.log(`%c${console_security_message}`, "font-size: large");
		}

		this.show_notes();

		if (influxframework.ui.startup_setup_dialog && !influxframework.boot.setup_complete) {
			influxframework.ui.startup_setup_dialog.pre_show();
			influxframework.ui.startup_setup_dialog.show();
		}

		influxframework.realtime.on("version-update", function () {
			var dialog = influxframework.msgprint({
				message: __(
					"The application has been updated to a new version, please refresh this page"
				),
				indicator: "green",
				title: __("Version Updated"),
			});
			dialog.set_primary_action(__("Refresh"), function () {
				location.reload(true);
			});
			dialog.get_close_btn().toggle(false);
		});

		// listen to build errors
		this.setup_build_events();

		if (influxframework.sys_defaults.email_user_password) {
			var email_list = influxframework.sys_defaults.email_user_password.split(",");
			for (var u in email_list) {
				if (email_list[u] === influxframework.user.name) {
					this.set_password(email_list[u]);
				}
			}
		}

		// REDESIGN-TODO: Fix preview popovers
		this.link_preview = new influxframework.ui.LinkPreview();

		if (!influxframework.boot.developer_mode) {
			if (influxframework.user.has_role("System Manager")) {
				setInterval(function () {
					influxframework.call({
						method: "influxframework.core.doctype.log_settings.log_settings.has_unseen_error_log",
						args: {
							user: influxframework.session.user,
						},
						callback: function (r) {
							if (r.message.show_alert) {
								influxframework.show_alert({
									indicator: "red",
									message: r.message.message,
								});
							}
						},
					});
				}, 600000); // check every 10 minutes
			}
		}
	}

	set_route() {
		influxframework.flags.setting_original_route = true;
		if (influxframework.boot && localStorage.getItem("session_last_route")) {
			influxframework.set_route(localStorage.getItem("session_last_route"));
			localStorage.removeItem("session_last_route");
		} else {
			// route to home page
			influxframework.router.route();
		}
		influxframework.after_ajax(() => (influxframework.flags.setting_original_route = false));
		influxframework.router.on("change", () => {
			$(".tooltip").hide();
		});
	}

	setup_influxframework_vue() {
		Vue.prototype.__ = window.__;
		Vue.prototype.influxframework = window.influxframework;
	}

	set_password(user) {
		var me = this;
		influxframework.call({
			method: "influxframework.core.doctype.user.user.get_email_awaiting",
			args: {
				user: user,
			},
			callback: function (email_account) {
				email_account = email_account["message"];
				if (email_account) {
					var i = 0;
					if (i < email_account.length) {
						me.email_password_prompt(email_account, user, i);
					}
				}
			},
		});
	}

	email_password_prompt(email_account, user, i) {
		var me = this;
		const email_id = email_account[i]["email_id"];
		let d = new influxframework.ui.Dialog({
			title: __("Password missing in Email Account"),
			fields: [
				{
					fieldname: "password",
					fieldtype: "Password",
					label: __(
						"Please enter the password for: <b>{0}</b>",
						[email_id],
						"Email Account"
					),
					reqd: 1,
				},
				{
					fieldname: "submit",
					fieldtype: "Button",
					label: __("Submit", null, "Submit password for Email Account"),
				},
			],
		});
		d.get_input("submit").on("click", function () {
			//setup spinner
			d.hide();
			var s = new influxframework.ui.Dialog({
				title: __("Checking one moment"),
				fields: [
					{
						fieldtype: "HTML",
						fieldname: "checking",
					},
				],
			});
			s.fields_dict.checking.$wrapper.html('<i class="fa fa-spinner fa-spin fa-4x"></i>');
			s.show();
			influxframework.call({
				method: "influxframework.email.doctype.email_account.email_account.set_email_password",
				args: {
					email_account: email_account[i]["email_account"],
					password: d.get_value("password"),
				},
				callback: function (passed) {
					s.hide();
					d.hide(); //hide waiting indication
					if (!passed["message"]) {
						influxframework.show_alert(
							{ message: __("Login Failed please try again"), indicator: "error" },
							5
						);
						me.email_password_prompt(email_account, user, i);
					} else {
						if (i + 1 < email_account.length) {
							i = i + 1;
							me.email_password_prompt(email_account, user, i);
						}
					}
				},
			});
		});
		d.show();
	}
	load_bootinfo() {
		if (influxframework.boot) {
			this.setup_workspaces();
			influxframework.model.sync(influxframework.boot.docs);
			this.check_metadata_cache_status();
			this.set_globals();
			this.sync_pages();
			influxframework.router.setup();
			this.setup_moment();
			if (influxframework.boot.print_css) {
				influxframework.dom.set_style(influxframework.boot.print_css, "print-style");
			}
			influxframework.user.name = influxframework.boot.user.name;
			influxframework.router.setup();
		} else {
			this.set_as_guest();
		}
	}

	setup_workspaces() {
		influxframework.modules = {};
		influxframework.workspaces = {};
		for (let page of influxframework.boot.allowed_workspaces || []) {
			influxframework.modules[page.module] = page;
			influxframework.workspaces[influxframework.router.slug(page.name)] = page;
		}
	}

	load_user_permissions() {
		influxframework.defaults.update_user_permissions();

		influxframework.realtime.on(
			"update_user_permissions",
			influxframework.utils.debounce(() => {
				influxframework.defaults.update_user_permissions();
			}, 500)
		);
	}

	check_metadata_cache_status() {
		if (influxframework.boot.metadata_version != localStorage.metadata_version) {
			influxframework.assets.clear_local_storage();
			influxframework.assets.init_local_storage();
		}
	}

	set_globals() {
		influxframework.session.user = influxframework.boot.user.name;
		influxframework.session.logged_in_user = influxframework.boot.user.name;
		influxframework.session.user_email = influxframework.boot.user.email;
		influxframework.session.user_fullname = influxframework.user_info().fullname;

		influxframework.user_defaults = influxframework.boot.user.defaults;
		influxframework.user_roles = influxframework.boot.user.roles;
		influxframework.sys_defaults = influxframework.boot.sysdefaults;

		influxframework.ui.py_date_format = influxframework.boot.sysdefaults.date_format
			.replace("dd", "%d")
			.replace("mm", "%m")
			.replace("yyyy", "%Y");
		influxframework.boot.user.last_selected_values = {};

		// Proxy for user globals
		Object.defineProperties(window, {
			user: {
				get: function () {
					console.warn(
						"Please use `influxframework.session.user` instead of `user`. It will be deprecated soon."
					);
					return influxframework.session.user;
				},
			},
			user_fullname: {
				get: function () {
					console.warn(
						"Please use `influxframework.session.user_fullname` instead of `user_fullname`. It will be deprecated soon."
					);
					return influxframework.session.user;
				},
			},
			user_email: {
				get: function () {
					console.warn(
						"Please use `influxframework.session.user_email` instead of `user_email`. It will be deprecated soon."
					);
					return influxframework.session.user_email;
				},
			},
			user_defaults: {
				get: function () {
					console.warn(
						"Please use `influxframework.user_defaults` instead of `user_defaults`. It will be deprecated soon."
					);
					return influxframework.user_defaults;
				},
			},
			roles: {
				get: function () {
					console.warn(
						"Please use `influxframework.user_roles` instead of `roles`. It will be deprecated soon."
					);
					return influxframework.user_roles;
				},
			},
			sys_defaults: {
				get: function () {
					console.warn(
						"Please use `influxframework.sys_defaults` instead of `sys_defaults`. It will be deprecated soon."
					);
					return influxframework.user_roles;
				},
			},
		});
	}
	sync_pages() {
		// clear cached pages if timestamp is not found
		if (localStorage["page_info"]) {
			influxframework.boot.allowed_pages = [];
			var page_info = JSON.parse(localStorage["page_info"]);
			$.each(influxframework.boot.page_info, function (name, p) {
				if (!page_info[name] || page_info[name].modified != p.modified) {
					delete localStorage["_page:" + name];
				}
				influxframework.boot.allowed_pages.push(name);
			});
		} else {
			influxframework.boot.allowed_pages = Object.keys(influxframework.boot.page_info);
		}
		localStorage["page_info"] = JSON.stringify(influxframework.boot.page_info);
	}
	set_as_guest() {
		influxframework.session.user = "Guest";
		influxframework.session.user_email = "";
		influxframework.session.user_fullname = "Guest";

		influxframework.user_defaults = {};
		influxframework.user_roles = ["Guest"];
		influxframework.sys_defaults = {};
	}
	make_page_container() {
		if ($("#body").length) {
			$(".splash").remove();
			influxframework.temp_container = $("<div id='temp-container' style='display: none;'>").appendTo(
				"body"
			);
			influxframework.container = new influxframework.views.Container();
		}
	}
	make_nav_bar() {
		// toolbar
		if (influxframework.boot && influxframework.boot.home_page !== "setup-wizard") {
			influxframework.influxframework_toolbar = new influxframework.ui.toolbar.Toolbar();
		}
	}
	logout() {
		var me = this;
		me.logged_out = true;
		return influxframework.call({
			method: "logout",
			callback: function (r) {
				if (r.exc) {
					return;
				}
				me.redirect_to_login();
			},
		});
	}
	handle_session_expired() {
		if (!influxframework.app.session_expired_dialog) {
			var dialog = new influxframework.ui.Dialog({
				title: __("Session Expired"),
				keep_open: true,
				fields: [
					{
						fieldtype: "Password",
						fieldname: "password",
						label: __("Please Enter Your Password to Continue"),
					},
				],
				onhide: () => {
					if (!dialog.logged_in) {
						influxframework.app.redirect_to_login();
					}
				},
			});
			dialog.set_primary_action(__("Login"), () => {
				dialog.set_message(__("Authenticating..."));
				influxframework.call({
					method: "login",
					args: {
						usr: influxframework.session.user,
						pwd: dialog.get_values().password,
					},
					callback: (r) => {
						if (r.message === "Logged In") {
							dialog.logged_in = true;

							// revert backdrop
							$(".modal-backdrop").css({
								opacity: "",
								"background-color": "#334143",
							});
						}
						dialog.hide();
					},
					statusCode: () => {
						dialog.hide();
					},
				});
			});
			influxframework.app.session_expired_dialog = dialog;
		}
		if (!influxframework.app.session_expired_dialog.display) {
			influxframework.app.session_expired_dialog.show();
			// add backdrop
			$(".modal-backdrop").css({
				opacity: 1,
				"background-color": "#4B4C9D",
			});
		}
	}
	redirect_to_login() {
		window.location.href = "/";
	}
	set_favicon() {
		var link = $('link[type="image/x-icon"]').remove().attr("href");
		$('<link rel="shortcut icon" href="' + link + '" type="image/x-icon">').appendTo("head");
		$('<link rel="icon" href="' + link + '" type="image/x-icon">').appendTo("head");
	}
	trigger_primary_action() {
		// to trigger change event on active input before triggering primary action
		$(document.activeElement).blur();
		// wait for possible JS validations triggered after blur (it might change primary button)
		setTimeout(() => {
			if (window.cur_dialog && cur_dialog.display) {
				// trigger primary
				cur_dialog.get_primary_btn().trigger("click");
			} else if (cur_frm && cur_frm.page.btn_primary.is(":visible")) {
				cur_frm.page.btn_primary.trigger("click");
			} else if (influxframework.container.page.save_action) {
				influxframework.container.page.save_action();
			}
		}, 100);
	}

	show_change_log() {
		var me = this;
		let change_log = influxframework.boot.change_log;

		// influxframework.boot.change_log = [{
		// 	"change_log": [
		// 		[<version>, <change_log in markdown>],
		// 		[<version>, <change_log in markdown>],
		// 	],
		// 	"description": "ERP made simple",
		// 	"title": "InfluxERP",
		// 	"version": "12.2.0"
		// }];

		if (
			!Array.isArray(change_log) ||
			!change_log.length ||
			window.Cypress ||
			cint(influxframework.boot.sysdefaults.disable_change_log_notification)
		) {
			return;
		}

		// Iterate over changelog
		var change_log_dialog = influxframework.msgprint({
			message: influxframework.render_template("change_log", { change_log: change_log }),
			title: __("Updated To A New Version 🎉"),
			wide: true,
		});
		change_log_dialog.keep_open = true;
		change_log_dialog.custom_onhide = function () {
			influxframework.call({
				method: "influxframework.utils.change_log.update_last_known_versions",
			});
			me.show_notes();
		};
	}

	show_update_available() {
		if (influxframework.boot.sysdefaults.disable_system_update_notification) return;

		influxframework.call({
			method: "influxframework.utils.change_log.show_update_popup",
		});
	}

	setup_analytics() {
		if (window.mixpanel) {
			window.mixpanel.identify(influxframework.session.user);
			window.mixpanel.people.set({
				$first_name: influxframework.boot.user.first_name,
				$last_name: influxframework.boot.user.last_name,
				$created: influxframework.boot.user.creation,
				$email: influxframework.session.user,
			});
		}
	}

	add_browser_class() {
		$("html").addClass(influxframework.utils.get_browser().name.toLowerCase());
	}

	set_fullwidth_if_enabled() {
		influxframework.ui.toolbar.set_fullwidth_if_enabled();
	}

	show_notes() {
		var me = this;
		if (influxframework.boot.notes.length) {
			influxframework.boot.notes.forEach(function (note) {
				if (!note.seen || note.notify_on_every_login) {
					var d = influxframework.msgprint({ message: note.content, title: note.title });
					d.keep_open = true;
					d.custom_onhide = function () {
						note.seen = true;

						// Mark note as read if the Notify On Every Login flag is not set
						if (!note.notify_on_every_login) {
							influxframework.call({
								method: "influxframework.desk.doctype.note.note.mark_as_seen",
								args: {
									note: note.name,
								},
							});
						}

						// next note
						me.show_notes();
					};
				}
			});
		}
	}

	setup_build_events() {
		if (influxframework.boot.developer_mode) {
			influxframework.require("build_events.bundle.js");
		}
	}

	setup_energy_point_listeners() {
		influxframework.realtime.on("energy_point_alert", (message) => {
			influxframework.show_alert(message);
		});
	}

	setup_copy_doc_listener() {
		$("body").on("paste", (e) => {
			try {
				let pasted_data = influxframework.utils.get_clipboard_data(e);
				let doc = JSON.parse(pasted_data);
				if (doc.doctype) {
					e.preventDefault();
					const sleep = influxframework.utils.sleep;

					influxframework.dom.freeze(__("Creating {0}", [doc.doctype]) + "...");
					// to avoid abrupt UX
					// wait for activity feedback
					sleep(500).then(() => {
						let res = influxframework.model.with_doctype(doc.doctype, () => {
							let newdoc = influxframework.model.copy_doc(doc);
							newdoc.__newname = doc.name;
							delete doc.name;
							newdoc.idx = null;
							newdoc.__run_link_triggers = false;
							influxframework.set_route("Form", newdoc.doctype, newdoc.name);
							influxframework.dom.unfreeze();
						});
						res && res.fail(influxframework.dom.unfreeze);
					});
				}
			} catch (e) {
				//
			}
		});
	}

	setup_moment() {
		moment.updateLocale("en", {
			week: {
				dow: influxframework.datetime.get_first_day_of_the_week_index(),
			},
		});
		moment.locale("en");
		moment.user_utc_offset = moment().utcOffset();
		if (influxframework.boot.timezone_info) {
			moment.tz.add(influxframework.boot.timezone_info);
		}
	}
};

influxframework.get_module = function (m, default_module) {
	var module = influxframework.modules[m] || default_module;
	if (!module) {
		return;
	}

	if (module._setup) {
		return module;
	}

	if (!module.label) {
		module.label = m;
	}

	if (!module._label) {
		module._label = __(module.label);
	}

	module._setup = true;

	return module;
};
