const ApiError = require("../errorClass");

async function isAuthorExists(authorId) {
	if (!authorId) return false;
	return (
		(
			await global.database.authors
				.promiseMode()
				.get({ where: { id: authorId } })
		).length !== 0
	);
}

async function isAuthorsExists(authorsId) {
	if (!Array.isArray(authorsId)) return false;
	const authors = (await global.database.authors.promiseMode().get()).map(
		(i) => i.id,
	);
	return authorsId.map((authorId) => authors.includes(authorId));
}

async function checkSyntaxArgs(req, res) {
	return !!(
		// Проверка поля author.
		(req.query.author === undefined
			? true
			: await isAuthorExists(+req.query.author)) && // Проверка поля authors.
		(req.query.authors === undefined
			? true
			: await isAuthorsExists(req.query.authors.split(",").map((i) => +i))) && // Проверка поля offset
		(req.query.offset === undefined
			? true
			: Number.isInteger(+req.query.offset)) && // Проверка поля count
		(req.query.count === undefined
			? true
			: Number.isInteger(+req.query.count)) && // Проверка поля min_date
		(req.query.min_date === undefined
			? true
			: Number.isInteger(+req.query.min_date)) && // Проверка поля max_date
		(req.query.max_date === undefined
			? true
			: Number.isInteger(+req.query.max_date)) && // Проверка поля q. (Ключевые слова для поиска)
		true && // (Проверки нет, query всегда строка, необязательный параметр) // Проверка поля searchByAuthor (Флаг для 'q'. 0 - отключить)
		true && // (Проверки нет, query всегда строка, необязательный параметр) // Проверка поля searchByName (Флаг для 'q'. 0 - отключить)
		true // (Проверки нет, query всегда строка, необязательный параметр)
	);
}

module.exports = async (req, res) => {
	if (req.method !== "GET") {
		throw new ApiError("METHOD_MUST_BE_GET", {
			request_method: req.method,
		});
	}
	if (!(await checkSyntaxArgs(req, res))) {
		throw new ApiError("INVALID_OR_UNSYNTAX_PARAMS", {
			request_method: req.method,
			params: {
				author: req.query?.author === undefined ? null : req.query.author,
				authors: req.query?.authors === undefined ? null : req.query.authors,
				q: req.query?.q === undefined ? null : req.query.q,
				offset: req.query?.offset === undefined ? null : req.query.offset,
				count: req.query?.count === undefined ? null : req.query.count,
				searchByAuthor:
					req.query?.searchByAuthor === undefined
						? null
						: req.query.searchByAuthor,
				searchByName:
					req.query?.searchByName === undefined ? null : req.query.searchByName,
				min_date: req.query?.min_date === undefined ? null : req.query.min_date,
				max_date: req.query?.max_date === undefined ? null : req.query.max_date,
			},
		});
	}

	// Оптимизация: флаг searchByAuthor выставится на 0, если была запрошена выборка по музыке определённого автора
	// Тем самым, мы ускоряем время ответа, поскольку мы не перебираем массив searchedAuthors с целью поиска совпадений
	let searchByAuthor =
		req.query.author === undefined ? req.query.searchByAuthor : "0";

	const offset = req.query.offset === undefined ? 0 : +req.query.offset;
	const countFromNull =
		req.query.count === undefined ? undefined : offset + +req.query.count;

	let result = (
		await global.database.muzic.promiseMode().get(
			req.query?.author === undefined
				? {}
				: {
						where: {
							author_id: +req.query.author,
						},
				  },
		)
	).map((i) => ({
		id: i.id,
		name: i.name,
		author_id: i.author_id,
		is_data_exists: i.data !== null,
		date: i.time,
	}));
	// Если просят выборку по authors
	if (req.query.authors) {
		let authors = req.query.authors.split(",").map((author) => +author);
		result = result.filter((res) => authors.includes(res.author_id));
	}
	// Если просят выборку по времени
	if (req.query.min_date || req.query.max_date) {
		const minDate = req.query.min_date === undefined ? 0 : +req.query.min_date;
		const maxDate =
			req.query.max_date === undefined ? 1e32 : +req.query.max_date;

		result = result.filter((res) => minDate <= res.date && res.date <= maxDate);
	}

	if (req.query?.q !== undefined) {
		let authors = await global.database.authors.promiseMode().get();
		let searchedAuthors = result.map((i) => {
			let author_id = i.author_id;
			return authors.filter((a) => a.id === author_id)[0];
		});
		result = result.filter((i) => {
			const search = req.query.q.toLowerCase();
			return (
				(req.query.searchByName !== "0" &&
					i.name.toLowerCase().includes(search)) ||
				!!(
					searchByAuthor !== "0" &&
					searchedAuthors
						.filter((a) => a.id === i.author_id)[0]
						?.name.toLowerCase()
						.includes(search)
				)
			);
		});
	}
	result = result.slice(offset, countFromNull);
	return {
		count: result.length,
		items: result,
	};
};