const { Op } = require("sequelize");
const ApiError = require("../errorClass");
const database = require("../../../database");
const apiTypes = require("../typeChecker");

const router = require('express').Router();

async function checkSyntaxArgs(req, res) {
	const checker = new apiTypes.TypeChecker(false);
	
	await checker.checkAdditional(req.query.id, apiTypes.MusicType, 'id');
	await checker.checkAdditional(req.query.author, apiTypes.AuthorType, 'author');
	await checker.checkAdditional(req.query.authors, apiTypes.AuthorsType, 'authors');
	await checker.checkAdditional(req.query.offset, apiTypes.IntType, 'offset');
	await checker.checkAdditional(req.query.count, apiTypes.IntType, 'count');
	await checker.checkAdditional(req.query.min_date, apiTypes.IntType, 'min_date');
	await checker.checkAdditional(req.query.max_date, apiTypes.IntType, 'max_date');
	await checker.checkAdditional(req.query.q, apiTypes.StrType, 'q');
	await checker.checkAdditional(req.query.searchByAuthor, apiTypes.StrType, 'searchByAuthor');
	await checker.checkAdditional(req.query.searchByName, apiTypes.StrType, 'searchByName');
	
	const result = await checker.calculate();
	if (!result.success) {
		throw new ApiError("UNSYNTAX_PARAMS_OR_MISSED_REQUIRED_PARAMS", result);
	}
}

router.get('/get-music', async (req, res, next) => {
	try {
		await checkSyntaxArgs(req, res);
		
		// Оптимизация: флаг 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;
		
		const searchAuthors = !req.query.authors ? [] : [...req.query.authors.split(',').map(i => +i)];
		if (req.query.author) searchAuthors.push(+req.query.author);
		
		const minDate = req.query.min_date === undefined ? 0 : +req.query.min_date;
		const maxDate = req.query.max_date === undefined ? 9999999999 : +req.query.max_date;
		
		let searchedParams = [];
		if (searchAuthors > 0) {
			searchAuthors.forEach(author_id => {
				console.log(author_id);
				searchedParams.push({ [Op.and] : [
					req.query.id !== undefined ? {id : +req.query.id} : undefined,
					{ author_id },
					{time : {
						[Op.gte]: minDate,
						[Op.lte]: maxDate,
					}},
				] });
			});
		}
		else {
			searchedParams.push({ [Op.and] : [
				req.query.id !== undefined ? {id : +req.query.id} : undefined,
				{time : {
					[Op.gte]: minDate,
					[Op.lte]: maxDate,
				}},
			] });
		}
		
		console.log('searchedParams', searchedParams);
		
		let result = (
			await database.music.findAll({
				where : { [Op.or]: searchedParams },
				raws : true
			})
		).map((i) => ({
			id: i.id,
			name: i.name,
			author_id: i.author_id,
			is_data_exists: i.data !== null && i.data.length > 0,
			date: i.time,
		}));

		if (req.query?.q !== undefined) {
			let authors = await database.authors.findAll({raws : true});
			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);
		res.result({
			count: result.length,
			items: result,
		});
	}
	catch (err) {
		return next(err);
	}
});

router.use('/get-music', async (req, res, next) => {
	try {
		return next(new ApiError("METHOD_MUST_BE_GET", { method : 'get-music' }));
	}
	catch (err) {
		return next(err);
	}
});

module.exports = router;