import { io } from "socket.io-client";
influxframework.socketio = {
	open_tasks: {},
	open_docs: [],
	emit_queue: [],
	init: function (port = 3000) {
		if (influxframework.boot.disable_async) {
			return;
		}

		if (influxframework.socketio.socket) {
			return;
		}

		// Enable secure option when using HTTPS
		if (window.location.protocol == "https:") {
			influxframework.socketio.socket = io.connect(influxframework.socketio.get_host(port), {
				secure: true,
				withCredentials: true,
			});
		} else if (window.location.protocol == "http:") {
			influxframework.socketio.socket = io.connect(influxframework.socketio.get_host(port), {
				withCredentials: true,
			});
		} else if (window.location.protocol == "file:") {
			influxframework.socketio.socket = io.connect(window.localStorage.server, {
				withCredentials: true,
			});
		}

		if (!influxframework.socketio.socket) {
			console.log("Unable to connect to " + influxframework.socketio.get_host(port));
			return;
		}

		influxframework.socketio.socket.on("msgprint", function (message) {
			influxframework.msgprint(message);
		});

		influxframework.socketio.socket.on("progress", function (data) {
			if (data.progress) {
				data.percent = (flt(data.progress[0]) / data.progress[1]) * 100;
			}
			if (data.percent) {
				influxframework.show_progress(
					data.title || __("Progress"),
					data.percent,
					100,
					data.description,
					true
				);
			}
		});

		influxframework.socketio.setup_listeners();
		influxframework.socketio.setup_reconnect();

		$(document).on("form-load form-rename", function (e, frm) {
			if (!frm.doc || frm.is_new()) {
				return;
			}

			for (var i = 0, l = influxframework.socketio.open_docs.length; i < l; i++) {
				var d = influxframework.socketio.open_docs[i];
				if (frm.doctype == d.doctype && frm.docname == d.name) {
					// already subscribed
					return false;
				}
			}

			influxframework.socketio.doc_subscribe(frm.doctype, frm.docname);
		});

		$(document).on("form-refresh", function (e, frm) {
			if (!frm.doc || frm.is_new()) {
				return;
			}

			influxframework.socketio.doc_open(frm.doctype, frm.docname);
		});

		$(document).on("form-unload", function (e, frm) {
			if (!frm.doc || frm.is_new()) {
				return;
			}

			// influxframework.socketio.doc_unsubscribe(frm.doctype, frm.docname);
			influxframework.socketio.doc_close(frm.doctype, frm.docname);
		});

		$(document).on("form-typing", function (e, frm) {
			influxframework.socketio.form_typing(frm.doctype, frm.docname);
		});

		$(document).on("form-stopped-typing", function (e, frm) {
			influxframework.socketio.form_stopped_typing(frm.doctype, frm.docname);
		});

		window.addEventListener("beforeunload", () => {
			if (!cur_frm || !cur_frm.doc || cur_frm.is_new()) {
				return;
			}

			influxframework.socketio.doc_close(cur_frm.doctype, cur_frm.docname);
		});
	},
	get_host: function (port = 3000) {
		var host = window.location.origin;
		if (window.dev_server) {
			var parts = host.split(":");
			port = influxframework.boot.socketio_port || port.toString() || "3000";
			if (parts.length > 2) {
				host = parts[0] + ":" + parts[1];
			}
			host = host + ":" + port;
		}
		return host;
	},
	subscribe: function (task_id, opts) {
		// TODO DEPRECATE

		influxframework.socketio.socket.emit("task_subscribe", task_id);
		influxframework.socketio.socket.emit("progress_subscribe", task_id);

		influxframework.socketio.open_tasks[task_id] = opts;
	},
	task_subscribe: function (task_id) {
		influxframework.socketio.socket.emit("task_subscribe", task_id);
	},
	task_unsubscribe: function (task_id) {
		influxframework.socketio.socket.emit("task_unsubscribe", task_id);
	},
	doc_subscribe: function (doctype, docname) {
		if (influxframework.flags.doc_subscribe) {
			console.log("throttled");
			return;
		}

		influxframework.flags.doc_subscribe = true;

		// throttle to 1 per sec
		setTimeout(function () {
			influxframework.flags.doc_subscribe = false;
		}, 1000);

		influxframework.socketio.socket.emit("doc_subscribe", doctype, docname);
		influxframework.socketio.open_docs.push({ doctype: doctype, docname: docname });
	},
	doc_unsubscribe: function (doctype, docname) {
		influxframework.socketio.socket.emit("doc_unsubscribe", doctype, docname);
		influxframework.socketio.open_docs = $.filter(influxframework.socketio.open_docs, function (d) {
			if (d.doctype === doctype && d.name === docname) {
				return null;
			} else {
				return d;
			}
		});
	},
	doc_open: function (doctype, docname) {
		// notify that the user has opened this doc, if not already notified
		if (
			!influxframework.socketio.last_doc ||
			influxframework.socketio.last_doc[0] != doctype ||
			influxframework.socketio.last_doc[1] != docname
		) {
			influxframework.socketio.socket.emit("doc_open", doctype, docname);

			influxframework.socketio.last_doc &&
				influxframework.socketio.doc_close(
					influxframework.socketio.last_doc[0],
					influxframework.socketio.last_doc[1]
				);
		}
		influxframework.socketio.last_doc = [doctype, docname];
	},
	doc_close: function (doctype, docname) {
		// notify that the user has closed this doc
		influxframework.socketio.socket.emit("doc_close", doctype, docname);

		// if the doc is closed the user has also stopped typing
		influxframework.socketio.socket.emit("doc_typing_stopped", doctype, docname);
	},
	form_typing: function (doctype, docname) {
		// notifiy that the user is typing on the doc
		influxframework.socketio.socket.emit("doc_typing", doctype, docname);
	},
	form_stopped_typing: function (doctype, docname) {
		// notifiy that the user has stopped typing
		influxframework.socketio.socket.emit("doc_typing_stopped", doctype, docname);
	},
	setup_listeners: function () {
		influxframework.socketio.socket.on("task_status_change", function (data) {
			influxframework.socketio.process_response(data, data.status.toLowerCase());
		});
		influxframework.socketio.socket.on("task_progress", function (data) {
			influxframework.socketio.process_response(data, "progress");
		});
	},
	setup_reconnect: function () {
		// subscribe again to open_tasks
		influxframework.socketio.socket.on("connect", function () {
			// wait for 5 seconds before subscribing again
			// because it takes more time to start python server than nodejs server
			// and we use validation requests to python server for subscribing
			setTimeout(function () {
				$.each(influxframework.socketio.open_tasks, function (task_id, opts) {
					influxframework.socketio.subscribe(task_id, opts);
				});

				// re-connect open docs
				$.each(influxframework.socketio.open_docs, function (d) {
					if (locals[d.doctype] && locals[d.doctype][d.name]) {
						influxframework.socketio.doc_subscribe(d.doctype, d.name);
					}
				});

				if (cur_frm && cur_frm.doc) {
					influxframework.socketio.doc_open(cur_frm.doc.doctype, cur_frm.doc.name);
				}
			}, 5000);
		});
	},
	process_response: function (data, method) {
		if (!data) {
			return;
		}

		// success
		var opts = influxframework.socketio.open_tasks[data.task_id];
		if (opts[method]) {
			opts[method](data);
		}

		// "callback" is std influxframework term
		if (method === "success") {
			if (opts.callback) opts.callback(data);
		}

		// always
		influxframework.request.cleanup(opts, data);
		if (opts.always) {
			opts.always(data);
		}

		// error
		if (data.status_code && data.status_code > 400 && opts.error) {
			opts.error(data);
		}
	},
};

influxframework.provide("influxframework.realtime");
influxframework.realtime.on = function (event, callback) {
	influxframework.socketio.socket && influxframework.socketio.socket.on(event, callback);
};

influxframework.realtime.off = function (event, callback) {
	influxframework.socketio.socket && influxframework.socketio.socket.off(event, callback);
};

influxframework.realtime.publish = function (event, message) {
	if (influxframework.socketio.socket) {
		influxframework.socketio.socket.emit(event, message);
	}
};
