import {MODULES} from "@/constants/ielts";
import {app} from "@/firebase";
import {Module} from "@/interfaces";
import {Stat, User} from "@/interfaces/user";
import {sessionOptions} from "@/lib/session";
import {calculateBandScore} from "@/utils/score";
import {groupByModule, groupBySession} from "@/utils/stats";
import { MODULE_ARRAY } from "@/utils/moduleUtils";
import client from "@/lib/mongodb";
import {withIronSessionApiRoute} from "iron-session/next";
import {groupBy} from "lodash";
import {NextApiRequest, NextApiResponse} from "next";

const db = client.db(process.env.MONGODB_DB);

export default withIronSessionApiRoute(update, sessionOptions);

async function update(req: NextApiRequest, res: NextApiResponse) {
	if (req.session.user) {
		const docUser = await db.collection("users").findOne({ id: req.session.user.id });

		if (!docUser) {
			res.status(401).json(undefined);
			return;
		}

		const stats = await db.collection("stats").find<Stat>({ user: req.session.user.id }).toArray();

		const groupedStats = groupBySession(stats);
		const sessionLevels: {[key in Module]: {correct: number; total: number}}[] = Object.keys(groupedStats).map((key) => {
			const sessionStats = groupedStats[key].map((stat) => ({module: stat.module, correct: stat.score.correct, total: stat.score.total}));
			const sessionLevels = {
				reading: {
					correct: 0,
					total: 0,
				},
				listening: {
					correct: 0,
					total: 0,
				},
				writing: {
					correct: 0,
					total: 0,
				},
				speaking: {
					correct: 0,
					total: 0,
				},
				level: {
					correct: 0,
					total: 0,
				},
			};

			MODULE_ARRAY.forEach((module: Module) => {
				const moduleStats = sessionStats.filter((x) => x.module === module);
				if (moduleStats.length === 0) return;

				const moduleScore = moduleStats.reduce(
					(accumulator, current) => ({correct: accumulator.correct + current.correct, total: accumulator.total + current.total}),
					{correct: 0, total: 0},
				);

				sessionLevels[module] = moduleScore;
			});

			return sessionLevels;
		});

		const readingLevel = sessionLevels
			.map((x) => x.reading)
			.filter((x) => x.total > 0)
			.reduce((acc, cur) => ({total: acc.total + cur.total, correct: acc.correct + cur.correct}), {total: 0, correct: 0});
		const listeningLevel = sessionLevels
			.map((x) => x.listening)
			.filter((x) => x.total > 0)
			.reduce((acc, cur) => ({total: acc.total + cur.total, correct: acc.correct + cur.correct}), {total: 0, correct: 0});
		const writingLevel = sessionLevels
			.map((x) => x.writing)
			.filter((x) => x.total > 0)
			.reduce((acc, cur) => ({total: acc.total + cur.total, correct: acc.correct + cur.correct}), {total: 0, correct: 0});
		const speakingLevel = sessionLevels
			.map((x) => x.speaking)
			.filter((x) => x.total > 0)
			.reduce((acc, cur) => ({total: acc.total + cur.total, correct: acc.correct + cur.correct}), {total: 0, correct: 0});

			const levelLevel = sessionLevels
			.map((x) => x.level)
			.filter((x) => x.total > 0)
			.reduce((acc, cur) => ({total: acc.total + cur.total, correct: acc.correct + cur.correct}), {total: 0, correct: 0});


		const levels = {
			reading: calculateBandScore(readingLevel.correct, readingLevel.total, "reading", req.session.user.focus),
			listening: calculateBandScore(listeningLevel.correct, listeningLevel.total, "listening", req.session.user.focus),
			writing: calculateBandScore(writingLevel.correct, writingLevel.total, "writing", req.session.user.focus),
			speaking: calculateBandScore(speakingLevel.correct, speakingLevel.total, "speaking", req.session.user.focus),
			level: calculateBandScore(levelLevel.correct, levelLevel.total, "level", req.session.user.focus),
		};

		await db.collection("users").updateOne(
			{ id: req.session.user.id},
			{ $set: {levels} }
		);
		  
		res.status(200).json({ok: true});
	} else {
		res.status(401).json(undefined);
	}
}
