'use strict';

const _ = require('lodash');

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

module.exports = function (Categories) {
	Categories.search = async function (data) {
		const query = data.query || '';
		const page = data.page || 1;
		const uid = data.uid || 0;
		const paginate = data.hasOwnProperty('paginate') ? data.paginate : true;

		const startTime = process.hrtime();

		let cids = await findCids(query, data.hardCap);

		const result = await plugins.hooks.fire('filter:categories.search', {
			cids: cids,
			uid: uid,
		});
		cids = await privileges.categories.filterCids('find', result.cids, uid);

		const searchResult = {
			matchCount: cids.length,
		};

		if (paginate) {
			const resultsPerPage = data.resultsPerPage || 50;
			const start = Math.max(0, page - 1) * resultsPerPage;
			const stop = start + resultsPerPage;
			searchResult.pageCount = Math.ceil(cids.length / resultsPerPage);
			cids = cids.slice(start, stop);
		}

		const childrenCids = await getChildrenCids(cids, uid);
		const uniqCids = _.uniq(cids.concat(childrenCids));
		const categoryData = await Categories.getCategories(uniqCids, uid);

		Categories.getTree(categoryData, 0);
		await Categories.getRecentTopicReplies(categoryData, uid, data.qs);
		categoryData.forEach((category) => {
			if (category && Array.isArray(category.children)) {
				category.children = category.children.slice(0, category.subCategoriesPerPage);
				category.children.forEach((child) => {
					child.children = undefined;
				});
			}
		});

		categoryData.sort((c1, c2) => {
			if (c1.parentCid !== c2.parentCid) {
				return c1.parentCid - c2.parentCid;
			}
			return c1.order - c2.order;
		});
		searchResult.timing = (process.elapsedTimeSince(startTime) / 1000).toFixed(2);
		searchResult.categories = categoryData.filter(c => cids.includes(c.cid));
		return searchResult;
	};

	async function findCids(query, hardCap) {
		if (!query || String(query).length < 2) {
			return [];
		}
		const data = await db.getSortedSetScan({
			key: 'categories:name',
			match: `*${String(query).toLowerCase()}*`,
			limit: hardCap || 500,
		});
		return data.map(data => parseInt(data.split(':').pop(), 10));
	}

	async function getChildrenCids(cids, uid) {
		const childrenCids = await Promise.all(cids.map(cid => Categories.getChildrenCids(cid)));
		return await privileges.categories.filterCids('find', _.flatten(childrenCids), uid);
	}
};
