import {Stat} from "@/interfaces/user";
import {capitalize, groupBy} from "lodash";
import {convertCamelCaseToReadable} from "@/utils/string";
import {UserSolution} from "@/interfaces/exam";
import {Module} from "@/interfaces";
import {MODULES} from "@/constants/ielts";
import moment from "moment";

export const timestampToMoment = (stat: Stat): moment.Moment => {
	return moment.unix(stat.date > Math.pow(10, 11) ? stat.date / 1000 : stat.date);
};

export const totalExams = (stats: Stat[]): number => {
	const moduleStats = formatModuleTotalStats(stats);
	return moduleStats.reduce((previous, current) => previous + current.value, 0);
};

export const averageScore = (stats: Stat[]): number => {
	const {correct, total} = stats.reduce(
		(acc, current) => ({correct: acc.correct + current.score.correct, total: acc.total + current.score.total}),
		{correct: 0, total: 0},
	);
	return parseFloat(((correct / total) * 100).toFixed(2));
};

export const formatModuleTotalStats = (stats: Stat[]): {label: string; value: number}[] => {
	const moduleSessions: {[key: string]: string[]} = {};

	stats.forEach((stat) => {
		if (stat.module in moduleSessions) {
			if (!moduleSessions[stat.module].includes(stat.session)) {
				moduleSessions[stat.module] = [...moduleSessions[stat.module], stat.session];
			}
		} else {
			moduleSessions[stat.module] = [stat.session];
		}
	});

	return ["reading", "listening", "writing", "speaking"].map((module) => ({
		label: capitalize(module),
		value: moduleSessions[module]?.length || 0,
	}));
};

export const totalExamsByModule = (stats: Stat[], module: Module): number => {
	const moduleSessions: {[key: string]: string[]} = {};

	stats.forEach((stat) => {
		if (stat.module in moduleSessions) {
			if (!moduleSessions[stat.module].includes(stat.session)) {
				moduleSessions[stat.module] = [...moduleSessions[stat.module], stat.session];
			}
		} else {
			moduleSessions[stat.module] = [stat.session];
		}
	});

	return moduleSessions[module]?.length || 0;
};

export const calculateModuleAverageScoreStats = (stats: Stat[]): {module: Module; value: number}[] => {
	const moduleScores: {[key: string]: {correct: number; total: number}} = {};

	stats.forEach((stat) => {
		if (stat.module in moduleScores) {
			moduleScores[stat.module] = {
				correct: moduleScores[stat.module].correct + stat.score.correct,
				total: moduleScores[stat.module].total + stat.score.total,
			};
		} else {
			moduleScores[stat.module] = stat.score;
		}
	});

	return MODULES.map((x) => {
		const score = moduleScores[x as keyof typeof moduleScores];

		return {
			module: x,
			value: score ? parseFloat(((score.correct / score.total) * 100).toFixed(2)) : 0,
		};
	});
};

export const formatModuleAverageScoreStats = (stats: Stat[]): {label: string; value: number}[] => {
	return calculateModuleAverageScoreStats(stats).map((x) => ({label: capitalize(x.module), value: x.value}));
};

export const formatExerciseTotalStats = (stats: Stat[]): {label: string; value: number}[] => {
	const totalExercises = stats.map((stat) => ({
		label: convertCamelCaseToReadable(stat.type),
		value: stats.filter((x) => x.type === stat.type).length,
	}));

	return totalExercises.filter((ex, index) => totalExercises.findIndex((x) => x.label === ex.label) === index);
};

export const formatExerciseAverageScoreStats = (stats: Stat[]): {label: string; value: number}[] => {
	const typeScores: {[key: string]: {correct: number; total: number}} = {};

	stats.forEach((stat) => {
		if (stat.type in typeScores) {
			typeScores[stat.type] = {
				correct: typeScores[stat.type].correct + stat.score.correct,
				total: typeScores[stat.type].total + stat.score.total,
			};
		} else {
			typeScores[stat.type] = stat.score;
		}
	});

	return Object.keys(typeScores).map((x) => {
		const {correct, total} = typeScores[x as keyof typeof typeScores];

		return {
			label: convertCamelCaseToReadable(x),
			value: parseFloat(((correct / total) * 100).toFixed(2)),
		};
	});
};

export const getExamsBySession = (stats: Stat[], session: string) => {
	const grouped = groupBySession(stats);
	return grouped[session].map((exam) => exam.exam);
};

export const groupBySession = (stats: Stat[]) => groupBy(stats, "session");
export const groupByDate = (stats: Stat[]) => groupBy(stats, "date");
export const groupByExam = (stats: Stat[]) => groupBy(stats, "exam");
export const groupByModule = (stats: Stat[]) => groupBy(stats, "module");
export const groupByUser = (stats: Stat[]) => groupBy(stats, "user");

export const convertToUserSolutions = (stats: Stat[]): UserSolution[] => {
	return stats.map((stat) => ({
		exercise: stat.exercise,
		exam: stat.exam,
		score: stat.score,
		solutions: stat.solutions,
		type: stat.type,
		module: stat.module,
		shuffleMaps: stat.shuffleMaps
	}));
};
