import React from "react";
import {BsClock, BsXCircle} from "react-icons/bs";
import clsx from "clsx";
import {Stat, User} from "@/interfaces/user";
import {Module} from "@/interfaces";
import ai_usage from "@/utils/ai.detection";
import {calculateBandScore} from "@/utils/score";
import moment from "moment";
import {Assignment} from "@/interfaces/results";
import {uuidv4} from "@firebase/util";
import {useRouter} from "next/router";
import {uniqBy} from "lodash";
import {sortByModule} from "@/utils/moduleUtils";
import {convertToUserSolutions} from "@/utils/stats";
import {getExamById} from "@/utils/exams";
import {Exam, UserSolution} from "@/interfaces/exam";
import ModuleBadge from "../ModuleBadge";

const formatTimestamp = (timestamp: string | number) => {
	const time = typeof timestamp === "string" ? parseInt(timestamp) : timestamp;
	const date = moment(time);
	const formatter = "YYYY/MM/DD - HH:mm";
	return date.format(formatter);
};

const aggregateScoresByModule = (stats: Stat[]): {module: Module; total: number; missing: number; correct: number}[] => {
	const scores: {
		[key in Module]: {total: number; missing: number; correct: number};
	} = {
		reading: {
			total: 0,
			correct: 0,
			missing: 0,
		},
		listening: {
			total: 0,
			correct: 0,
			missing: 0,
		},
		writing: {
			total: 0,
			correct: 0,
			missing: 0,
		},
		speaking: {
			total: 0,
			correct: 0,
			missing: 0,
		},
		level: {
			total: 0,
			correct: 0,
			missing: 0,
		},
	};

	stats.forEach((x) => {
		scores[x.module!] = {
			total: scores[x.module!].total + x.score.total,
			correct: scores[x.module!].correct + x.score.correct,
			missing: scores[x.module!].missing + x.score.missing,
		};
	});

	return Object.keys(scores)
		.filter((x) => scores[x as Module].total > 0)
		.map((x) => ({module: x as Module, ...scores[x as Module]}));
};

interface StatsGridItemProps {
	width?: string | undefined;
	height?: string | undefined;
	examNumber?: number | undefined;
	stats: Stat[];
	timestamp: string | number;
	user: User;
	assignments: Assignment[];
	users: User[];
	training?: boolean;
	selectedTrainingExams?: string[];
	maxTrainingExams?: number;
	setSelectedTrainingExams?: React.Dispatch<React.SetStateAction<string[]>>;
	setExams: (exams: Exam[]) => void;
	setShowSolutions: (show: boolean) => void;
	setUserSolutions: (solutions: UserSolution[]) => void;
	setSelectedModules: (modules: Module[]) => void;
	setInactivity: (inactivity: number) => void;
	setTimeSpent: (time: number) => void;
	renderPdfIcon: (session: string, color: string, textColor: string) => React.ReactNode;
}

const StatsGridItem: React.FC<StatsGridItemProps> = ({
	stats,
	timestamp,
	user,
	assignments,
	users,
	training,
	selectedTrainingExams,
	setSelectedTrainingExams,
	setExams,
	setShowSolutions,
	setUserSolutions,
	setSelectedModules,
	setInactivity,
	setTimeSpent,
	renderPdfIcon,
	width = undefined,
	height = undefined,
	examNumber = undefined,
	maxTrainingExams = undefined,
}) => {
	const router = useRouter();
	const correct = stats.reduce((accumulator, current) => accumulator + current.score.correct, 0);
	const total = stats.reduce((accumulator, current) => accumulator + current.score.total, 0);
	const aggregatedScores = aggregateScoresByModule(stats).filter((x) => x.total > 0);
	const assignmentID = stats.reduce((_, current) => current.assignment as any, "");
	const assignment = assignments.find((a) => a.id === assignmentID);
	const isDisabled = stats.some((x) => x.isDisabled);

	const aiUsage = Math.round(ai_usage(stats) * 100);

	const aggregatedLevels = aggregatedScores.map((x) => ({
		module: x.module,
		level: calculateBandScore(x.correct, x.total, x.module, user.focus),
	}));

	const textColor = clsx(
		correct / total >= 0.7 && "text-mti-purple",
		correct / total >= 0.3 && correct / total < 0.7 && "text-mti-red",
		correct / total < 0.3 && "text-mti-rose",
	);

	const {timeSpent, inactivity, session} = stats[0];

	const selectExam = () => {
		if (
			training &&
			!isDisabled &&
			typeof maxTrainingExams !== "undefined" &&
			typeof setSelectedTrainingExams !== "undefined" &&
			typeof timestamp == "string"
		) {
			setSelectedTrainingExams((prevExams) => {
				const uniqueExams = [...new Set(stats.map((stat) => `${stat.module}-${stat.date}`))];
				const indexes = uniqueExams.map((exam) => prevExams.indexOf(exam)).filter((index) => index !== -1);
				if (indexes.length > 0) {
					const newExams = [...prevExams];
					indexes
						.sort((a, b) => b - a)
						.forEach((index) => {
							newExams.splice(index, 1);
						});
					return newExams;
				} else {
					if (prevExams.length + uniqueExams.length <= maxTrainingExams) {
						return [...prevExams, ...uniqueExams];
					} else {
						return prevExams;
					}
				}
			});
		} else {
			const examPromises = uniqBy(stats, "exam").map((stat) => {
				return getExamById(stat.module, stat.exam);
			});

			if (isDisabled) return;

			Promise.all(examPromises).then((exams) => {
				if (exams.every((x) => !!x)) {
					if (!!timeSpent) setTimeSpent(timeSpent);
					if (!!inactivity) setInactivity(inactivity);
					setUserSolutions(convertToUserSolutions(stats));
					setShowSolutions(true);
					setExams(exams.map((x) => x!).sort(sortByModule));
					setSelectedModules(
						exams
							.map((x) => x!)
							.sort(sortByModule)
							.map((x) => x!.module),
					);
					router.push("/exercises");
				}
			});
		}
	};

	const shouldRenderPDFIcon = () => {
		if (assignment) {
			return assignment.released;
		}

		return true;
	};

	const content = (
		<>
			<div className="w-full flex justify-between -md:items-center 2xl:items-center">
				<div className="flex flex-col md:gap-1 -md:gap-2 2xl:gap-2">
					<span className="font-medium">{formatTimestamp(timestamp)}</span>
					<div className="flex items-center gap-2">
						{!!timeSpent && (
							<span className="text-sm flex gap-2 items-center tooltip" data-tip="Time Spent">
								<BsClock /> {Math.floor(timeSpent / 60)} minutes
							</span>
						)}
						{!!inactivity && (
							<span className="text-sm flex gap-2 items-center tooltip" data-tip="Inactivity">
								<BsXCircle /> {Math.floor(inactivity / 60)} minutes
							</span>
						)}
					</div>
				</div>
				<div className="flex flex-col gap-2">
					<div className="flex flex-row gap-2">
						<span className={textColor}>
							Level{" "}
							{(aggregatedLevels.reduce((accumulator, current) => accumulator + current.level, 0) / aggregatedLevels.length).toFixed(1)}
						</span>
						{shouldRenderPDFIcon() && renderPdfIcon(session, textColor, textColor)}
					</div>
					{examNumber === undefined ? (
						<>
							{aiUsage >= 50 && user.type !== "student" && (
								<div
									className={clsx("ml-auto border px-1 rounded w-fit mr-1", {
										"bg-orange-100 border-orange-400 text-orange-700": aiUsage < 80,
										"bg-red-100 border-red-400 text-red-700": aiUsage >= 80,
									})}>
									<span className="text-xs">AI Usage</span>
								</div>
							)}
						</>
					) : (
						<div className="flex justify-end">
							<span className="font-semibold bg-gray-200 text-gray-800 px-2.5 py-0.5 rounded-full mt-0.5">{examNumber}</span>
						</div>
					)}
				</div>
			</div>

			<div className="w-full flex flex-col gap-1">
				<div className={clsx("grid grid-cols-4 gap-2 place-items-start w-full -md:mt-2", examNumber !== undefined && "pr-10")}>
					{aggregatedLevels.map(({module, level}) => (
						<ModuleBadge key={module} module={module} level={level} />
					))}
				</div>

				{assignment && (
					<span className="font-light text-sm">
						Assignment: {assignment.name}, Teacher: {users.find((u) => u.id === assignment.assigner)?.name}
					</span>
				)}
			</div>
		</>
	);

	return (
		<>
			<div
				key={uuidv4()}
				className={clsx(
					"flex flex-col justify-between gap-4 border border-mti-gray-platinum p-4 cursor-pointer rounded-xl transition ease-in-out duration-300 -md:hidden",
					(isDisabled || (!!assignment && !assignment.released)) && "grayscale tooltip",
					correct / total >= 0.7 && "hover:border-mti-purple",
					correct / total >= 0.3 && correct / total < 0.7 && "hover:border-mti-red",
					correct / total < 0.3 && "hover:border-mti-rose",
					typeof selectedTrainingExams !== "undefined" &&
						typeof timestamp === "string" &&
						selectedTrainingExams.some((exam) => exam.includes(timestamp)) &&
						"border-2 border-slate-600",
				)}
				onClick={examNumber === undefined ? selectExam : undefined}
				style={{
					...(width !== undefined && {width}),
					...(height !== undefined && {height}),
				}}
				data-tip={isDisabled ? "This exam is still being evaluated..." : "This exam is still locked by its assigner..."}
				role="button">
				{content}
			</div>
			<div
				key={uuidv4()}
				className={clsx(
					"flex flex-col gap-4 border border-mti-gray-platinum p-4 cursor-pointer rounded-xl transition ease-in-out duration-300 -md:tooltip md:hidden",
					correct / total >= 0.7 && "hover:border-mti-purple",
					correct / total >= 0.3 && correct / total < 0.7 && "hover:border-mti-red",
					correct / total < 0.3 && "hover:border-mti-rose",
				)}
				data-tip="Your screen size is too small to view previous exams."
				style={{
					...(width !== undefined && {width}),
					...(height !== undefined && {height}),
				}}
				role="button">
				{content}
			</div>
		</>
	);
};

export default StatsGridItem;
