import {ListeningExam, UserSolution} from "@/interfaces/exam";
import {useEffect, useState} from "react";
import {renderExercise} from "@/components/Exercises";
import {renderSolution} from "@/components/Solutions";
import ModuleTitle from "@/components/Medium/ModuleTitle";
import AudioPlayer from "@/components/Low/AudioPlayer";
import Button from "@/components/Low/Button";
import BlankQuestionsModal from "@/components/BlankQuestionsModal";
import useExamStore from "@/stores/examStore";
import {defaultUserSolutions} from "@/utils/exams";
import {countExercises} from "@/utils/moduleUtils";

interface Props {
	exam: ListeningExam;
	showSolutions?: boolean;
	onFinish: (userSolutions: UserSolution[]) => void;
}

export default function Listening({exam, showSolutions = false, onFinish}: Props) {
	const [questionIndex, setQuestionIndex] = useState(0);
	const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
	const [exerciseIndex, setExerciseIndex] = useState(showSolutions ? 0 : -1);
	const [partIndex, setPartIndex] = useState(0);
	const [timesListened, setTimesListened] = useState(0);
	const [userSolutions, setUserSolutions] = useState<UserSolution[]>(
		exam.parts.flatMap((x) => x.exercises).map((x) => defaultUserSolutions(x, exam)),
	);
	const [showBlankModal, setShowBlankModal] = useState(false);

	const [hasExamEnded, setHasExamEnded] = useExamStore((state) => [state.hasExamEnded, state.setHasExamEnded]);

	useEffect(() => {
		if (hasExamEnded && exerciseIndex === -1) {
			setExerciseIndex((prev) => prev + 1);
		}
	}, [hasExamEnded, exerciseIndex]);

	useEffect(() => {
		setCurrentQuestionIndex(0);
	}, [questionIndex]);

	const confirmFinishModule = (keepGoing?: boolean) => {
		if (!keepGoing) {
			setShowBlankModal(false);
			return;
		}

		onFinish(userSolutions.map((x) => ({...x, module: "listening", exam: exam.id})));
	};

	const nextExercise = (solution?: UserSolution) => {
		if (solution) {
			setUserSolutions((prev) => [...prev.filter((x) => x.exercise !== solution.exercise), solution]);
		}
		setQuestionIndex((prev) => prev + currentQuestionIndex);

		if (exerciseIndex + 1 < exam.parts[partIndex].exercises.length && !hasExamEnded) {
			setExerciseIndex((prev) => prev + 1);
			return;
		}

		if (partIndex + 1 < exam.parts.length && !hasExamEnded) {
			setPartIndex((prev) => prev + 1);
			setExerciseIndex(showSolutions ? 0 : -1);
			return;
		}

		if (
			solution &&
			![...userSolutions.filter((x) => x.exercise !== solution?.exercise).map((x) => x.score.missing), solution?.score.missing].every(
				(x) => x === 0,
			) &&
			!showSolutions &&
			!hasExamEnded
		) {
			setShowBlankModal(true);
			return;
		}

		setHasExamEnded(false);

		if (solution) {
			onFinish(
				[...userSolutions.filter((x) => x.exercise !== solution.exercise), solution].map((x) => ({...x, module: "listening", exam: exam.id})),
			);
		} else {
			onFinish(userSolutions.map((x) => ({...x, module: "listening", exam: exam.id})));
		}
	};

	const previousExercise = (solution?: UserSolution) => {
		if (solution) {
			setUserSolutions((prev) => [...prev.filter((x) => x.exercise !== solution.exercise), solution]);
		}

		setExerciseIndex((prev) => prev - 1);
	};

	const getExercise = () => {
		const exercise = exam.parts[partIndex].exercises[exerciseIndex];
		return {
			...exercise,
			userSolutions: userSolutions.find((x) => x.exercise === exercise.id)?.solutions || [],
		};
	};

	const renderAudioPlayer = () => (
		<div className="flex flex-col gap-8 w-full bg-mti-gray-seasalt rounded-xl py-8 px-16">
			<div className="flex flex-col w-full gap-2">
				<h4 className="text-xl font-semibold">Please listen to the following audio attentively.</h4>
				<span className="text-base">
					{exam.parts[partIndex].audio.repeatableTimes > 0
						? `You will only be allowed to listen to the audio ${exam.parts[partIndex].audio.repeatableTimes - timesListened} time(s).`
						: "You may listen to the audio as many times as you would like."}
				</span>
			</div>
			<div className="rounded-xl flex flex-col gap-4 items-center w-full h-fit">
				<AudioPlayer
					key={partIndex}
					src={exam.parts[partIndex].audio.source}
					color="listening"
					onEnd={() => setTimesListened((prev) => prev + 1)}
					disabled={timesListened === exam.parts[partIndex].audio.repeatableTimes}
					disablePause
				/>
			</div>
		</div>
	);

	return (
		<>
			<BlankQuestionsModal isOpen={showBlankModal} onClose={confirmFinishModule} />
			<div className="flex flex-col h-full w-full gap-8 justify-between">
				<ModuleTitle
					exerciseIndex={
						(exam.parts
							.flatMap((x) => x.exercises)
							.findIndex(
								(x) => x.id === exam.parts[partIndex].exercises[exerciseIndex === -1 ? exerciseIndex + 1 : exerciseIndex]?.id,
							) || 0) +
						(exerciseIndex === -1 ? 0 : 1) +
						questionIndex +
						currentQuestionIndex
					}
					minTimer={exam.minTimer}
					module="listening"
					totalExercises={countExercises(exam.parts.flatMap((x) => x.exercises))}
					disableTimer={showSolutions}
				/>
				{renderAudioPlayer()}
				{exerciseIndex > -1 &&
					exerciseIndex < exam.parts[partIndex].exercises.length &&
					!showSolutions &&
					renderExercise(getExercise(), nextExercise, previousExercise, setCurrentQuestionIndex)}
				{exerciseIndex > -1 &&
					exerciseIndex < exam.parts[partIndex].exercises.length &&
					showSolutions &&
					renderSolution(exam.parts[partIndex].exercises[exerciseIndex], nextExercise, previousExercise, setCurrentQuestionIndex)}
			</div>
			{exerciseIndex === -1 && partIndex > 0 && (
				<div className="self-end flex justify-between w-full gap-8 absolute bottom-8 left-0 px-8">
					<Button
						color="purple"
						variant="outline"
						onClick={() => {
							setExerciseIndex(exam.parts[partIndex - 1].exercises.length - 1);
							setPartIndex((prev) => prev - 1);
						}}
						className="max-w-[200px] w-full">
						Back
					</Button>

					<Button color="purple" onClick={() => nextExercise()} className="max-w-[200px] self-end w-full">
						Next
					</Button>
				</div>
			)}
			{exerciseIndex === -1 && partIndex === 0 && (
				<Button color="purple" onClick={() => nextExercise()} className="max-w-[200px] self-end w-full justify-self-end">
					Start now
				</Button>
			)}
		</>
	);
}
