'use strict';

const db = require('../database');
const user = require('../user');
const plugins = require('../plugins');
const cache = require('../cache');

module.exports = function (Groups) {
	Groups.leave = async function (groupNames, uid) {
		if (Array.isArray(groupNames) && !groupNames.length) {
			return;
		}
		if (!Array.isArray(groupNames)) {
			groupNames = [groupNames];
		}

		const isMembers = await Groups.isMemberOfGroups(uid, groupNames);

		const groupsToLeave = groupNames.filter((groupName, index) => isMembers[index]);
		if (!groupsToLeave.length) {
			return;
		}

		await Promise.all([
			db.sortedSetRemove(groupsToLeave.map(groupName => 'group:' + groupName + ':members'), uid),
			db.setRemove(groupsToLeave.map(groupName => 'group:' + groupName + ':owners'), uid),
			db.decrObjectField(groupsToLeave.map(groupName => 'group:' + groupName), 'memberCount'),
		]);

		Groups.clearCache(uid, groupsToLeave);
		cache.del(groupsToLeave.map(name => 'group:' + name + ':members'));

		const groupData = await Groups.getGroupsFields(groupsToLeave, ['name', 'hidden', 'memberCount']);
		if (!groupData) {
			return;
		}

		const emptyPrivilegeGroups = groupData.filter(g => g && Groups.isPrivilegeGroup(g.name) && g.memberCount === 0);
		const visibleGroups = groupData.filter(g => g && !g.hidden);

		const promises = [];
		if (emptyPrivilegeGroups.length) {
			promises.push(Groups.destroy, emptyPrivilegeGroups);
		}
		if (visibleGroups.length) {
			promises.push(db.sortedSetAdd, 'groups:visible:memberCount',
				visibleGroups.map(groupData => groupData.memberCount),
				visibleGroups.map(groupData => groupData.name)
			);
		}

		await Promise.all(promises);

		await clearGroupTitleIfSet(groupsToLeave, uid);

		plugins.hooks.fire('action:group.leave', {
			groupNames: groupsToLeave,
			uid: uid,
		});
	};

	async function clearGroupTitleIfSet(groupNames, uid) {
		groupNames = groupNames.filter(groupName => groupName !== 'registered-users' && !Groups.isPrivilegeGroup(groupName));
		if (!groupNames.length) {
			return;
		}
		const userData = await user.getUserData(uid);
		if (!userData) {
			return;
		}

		const newTitleArray = userData.groupTitleArray.filter(groupTitle => !groupNames.includes(groupTitle));
		if (newTitleArray.length) {
			await db.setObjectField('user:' + uid, 'groupTitle', JSON.stringify(newTitleArray));
		} else {
			await db.deleteObjectField('user:' + uid, 'groupTitle');
		}
	}

	Groups.leaveAllGroups = async function (uid) {
		const groups = await db.getSortedSetRange('groups:createtime', 0, -1);
		await Promise.all([
			Groups.leave(groups, uid),
			Groups.rejectMembership(groups, uid),
		]);
	};

	Groups.kick = async function (uid, groupName, isOwner) {
		if (isOwner) {
			// If the owners set only contains one member, error out!
			const numOwners = await db.setCount('group:' + groupName + ':owners');
			if (numOwners <= 1) {
				throw new Error('[[error:group-needs-owner]]');
			}
		}
		await Groups.leave(groupName, uid);
	};
};
