'use strict';

define('userFilter', ['api', 'hooks', 'slugify', 'benchpress'], function (api, hooks, slugify, benchpress) {
	const userFilter = {};

	userFilter.init = function (el, options) {
		if (!el || !el.length) {
			return;
		}
		options = options || {};

		let placeholderHtml;
		let selectedUsers = [];
		if (options.selectedUsers) {
			selectedUsers = options.selectedUsers.map(u => ({ ...u }));
		}
		hooks.fire('action:user.filter.options', { el: el, options: options });

		async function renderSelectedUsers() {
			const block = options.selectedBlock || 'userFilterSelected';
			const payload = {};

			// This allows `selectedBlock` to be a nested object via dot notation.
			// It's hacky and only works one level.
			if (block.indexOf('.') !== -1) {
				const split = block.split('.');
				payload[split[0]] = {};
				payload[split[0]][split[1]] = selectedUsers;
			} else {
				payload[block] = selectedUsers;
			}

			const html = await app.parseAndTranslate(options.template, block, payload);
			el.find('[component="user/filter/selected"]').html(html);
		}

		async function onSelectionChange() {
			await renderSelectedUsers();
			if (options.onSelect) {
				options.onSelect(selectedUsers);
			}
		}

		async function doSearch() {
			let result = { users: [] };
			const query = el.find('[component="user/filter/search"]').val();
			if (query && query.length > 1) {
				if (app.user.privileges['search:users']) {
					result = await api.get('/api/users', { query: query });
				} else {
					try {
						const userData = await api.get(`/api/user/${slugify(query)}`);
						result.users.push(userData);
					} catch (err) {}
				}
			}
			if (!result.users.length) {
				el.find('[component="user/filter/results"]').translateHtml(
					'[[users:no-users-found]]'
				);
				return;
			}
			result.users = result.users.slice(0, 20);
			const uidToUser = {};
			result.users.forEach((user) => {
				uidToUser[user.uid] = user;
			});

			const html = await app.parseAndTranslate(options.template, 'userFilterResults', {
				userFilterResults: result.users,
			});
			el.find('[component="user/filter/results"]').html(html);

			el.find('[component="user/filter/results"] [data-uid]').on('click', async function () {
				const clickedUid = parseInt($(this).attr('data-uid'), 10);
				if (!selectedUsers.find(u => u.uid === clickedUid)) {
					selectedUsers.push(uidToUser[clickedUid]);
					await onSelectionChange();
				}
			});
		}

		el.find('[component="user/filter/search"]').on('keyup', () => {
			el.find('[component="user/filter/results"]').html(placeholderHtml);
		});

		el.find('[component="user/filter/search"]').on('keyup', utils.debounce(function () {
			if (app.user.privileges['search:users']) {
				doSearch();
			}
		}, 1000));

		el.on('click', '[component="user/filter/delete"]', async function () {
			const uid = $(this).attr('data-uid');
			selectedUsers = selectedUsers.filter(u => parseInt(u.uid, 10) !== parseInt(uid, 10));
			await onSelectionChange();
		});

		el.find('[component="user/filter/search"]').on('keyup', (e) => {
			if (e.key === 'Enter' && !app.user.privileges['search:users']) {
				doSearch();
			}
		});

		el.on('shown.bs.dropdown', function () {
			el.find('[component="user/filter/search"]').trigger('focus');
		});

		el.on('hidden.bs.dropdown', function () {
			if (options.onHidden) {
				options.onHidden(selectedUsers);
			}
		});

		// Pre-render placeholders for search
		benchpress.render(options.placeholderTemplate || 'partials/userFilter-placeholders').then((html) => {
			placeholderHtml = html;
		});
	};

	return userFilter;
});
