const { jingrow_request } = require("../utils");
const log = console.log;

const WEBSITE_ROOM = "website";
const SITE_ROOM = "all";

function jingrow_handlers(realtime, socket) {
	socket.join(user_room(socket.user));
	socket.join(WEBSITE_ROOM);

	if (socket.user_type == "System User") {
		socket.join(SITE_ROOM);
	}

	socket.on("ping", () => {
		socket.emit("pong");
	});

	socket.on("pagetype_subscribe", function (pagetype) {
		can_subscribe_pagetype({
			socket,
			pagetype,
			callback: () => {
				socket.join(pagetype_room(pagetype));
			},
		});
	});

	socket.on("pagetype_unsubscribe", function (pagetype) {
		socket.leave(pagetype_room(pagetype));
	});

	socket.on("task_subscribe", function (task_id) {
		const room = task_room(task_id);
		socket.join(room);
	});

	socket.on("task_unsubscribe", function (task_id) {
		const room = task_room(task_id);
		socket.leave(room);
	});

	socket.on("progress_subscribe", function (task_id) {
		const room = task_room(task_id);
		socket.join(room);
	});

	socket.on("pg_subscribe", function (pagetype, pagename) {
		can_subscribe_pg({
			socket,
			pagetype,
			pagename,
			callback: () => {
				let room = pg_room(pagetype, pagename);
				socket.join(room);
			},
		});
	});

	socket.on("pg_unsubscribe", function (pagetype, pagename) {
		let room = pg_room(pagetype, pagename);
		socket.leave(room);
	});

	socket.on("pg_open", function (pagetype, pagename) {
		can_subscribe_pg({
			socket,
			pagetype,
			pagename,
			callback: () => {
				let room = open_pg_room(pagetype, pagename);
				socket.join(room);
				if (!socket.subscribed_documents) socket.subscribed_documents = [];
				socket.subscribed_documents.push([pagetype, pagename]);

				// show who is currently viewing the form
				notify_subscribed_pg_users({
					socket: socket,
					pagetype: pagetype,
					pagename: pagename,
				});
			},
		});
	});

	socket.on("pg_close", function (pagetype, pagename) {
		// remove this user from the list of 'who is currently viewing the form'
		let room = open_pg_room(pagetype, pagename);
		socket.leave(room);

		if (socket.subscribed_documents) {
			socket.subscribed_documents = socket.subscribed_documents.filter(([dt, dn]) => {
				!(dt == pagetype && dn == pagename);
			});
		}

		notify_subscribed_pg_users({
			socket: socket,
			pagetype: pagetype,
			pagename: pagename,
		});
	});

	socket.on("disconnect", () => {
		notify_disconnected_documents(socket);
	});
}

function notify_disconnected_documents(socket) {
	if (socket.subscribed_documents) {
		socket.subscribed_documents.forEach(([pagetype, pagename]) => {
			notify_subscribed_pg_users({ socket, pagetype, pagename });
		});
	}
}

function can_subscribe_pagetype(args) {
	if (!args) return;
	if (!args.pagetype) return;
	jingrow_request("/api/action/jingrow.realtime.can_subscribe_pagetype", args.socket)
		.type("form")
		.query({
			pagetype: args.pagetype,
		})
		.end(function (err, res) {
			if (!res || res.status == 403 || err) {
				if (err) {
					log(err);
				}
				return false;
			} else if (res.status == 200) {
				args.callback && args.callback(err, res);
				return true;
			}
			log("ERROR (can_subscribe_pagetype): ", err, res);
		});
}

function notify_subscribed_pg_users(args) {
	if (!(args && args.pagetype && args.pagename)) {
		return;
	}
	const socket = args.socket;
	const room = open_pg_room(args.pagetype, args.pagename);

	const clients = Array.from(socket.nsp.adapter.rooms.get(room) || []);

	let users = [];

	socket.nsp.sockets.forEach((sock) => {
		if (clients.includes(sock.id)) {
			users.push(sock.user);
		}
	});

	// dont send update to self. meaningless.
	if (users.length == 1 && users[0] == args.socket.user) return;

	// notify
	socket.nsp.to(room).emit("pg_viewers", {
		pagetype: args.pagetype,
		pagename: args.pagename,
		users: Array.from(new Set(users)),
	});
}

function can_subscribe_pg(args) {
	if (!args) return;
	if (!args.pagetype || !args.pagename) return;
	jingrow_request("/api/action/jingrow.realtime.can_subscribe_pg", args.socket)
		.type("form")
		.query({
			pagetype: args.pagetype,
			pagename: args.pagename,
		})
		.end(function (err, res) {
			if (!res) {
				log("No response for pg_subscribe");
			} else if (res.status == 403) {
				return;
			} else if (err) {
				log(err);
			} else if (res.status == 200) {
				args.callback(err, res);
			} else {
				log("Something went wrong", err, res);
			}
		});
}

const pg_room = (pagetype, pagename) => "pg:" + pagetype + "/" + pagename;
const open_pg_room = (pagetype, pagename) => "open_pg:" + pagetype + "/" + pagename;
const user_room = (user) => "user:" + user;
const pagetype_room = (pagetype) => "pagetype:" + pagetype;
const task_room = (task_id) => "task_progress:" + task_id;

module.exports = jingrow_handlers;
