import { Exercise, ListeningExam, MultipleChoiceExercise, Script, UserSolution } from "@/interfaces/exam";
import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { renderExercise } from "@/components/Exercises";
import { renderSolution } from "@/components/Solutions";
import ModuleTitle from "@/components/Medium/ModuleTitle";
import BlankQuestionsModal from "@/components/QuestionsModal";
import useExamStore, { usePersistentExamStore } from "@/stores/exam";
import PartDivider from "./Navigation/SectionDivider";
import ScriptModal from "./components/ScriptModal";
import { ExamProps } from "./types";
import useExamTimer from "@/hooks/useExamTimer";
import useExamNavigation from "./Navigation/useExamNavigation";
import RenderAudioInstructionsPlayer from "./components/RenderAudioInstructionsPlayer";
import RenderAudioPlayer from "./components/RenderAudioPlayer";
import SectionNavbar from "./Navigation/SectionNavbar";
import ProgressButtons from "./components/ProgressButtons";
import PracticeModal from "@/components/PracticeModal";


const Listening: React.FC<ExamProps<ListeningExam>> = ({ exam, showSolutions = false, preview = false }) => {
	const updateTimers = useExamTimer(exam.module, preview || showSolutions);
	const userSolutionRef = useRef<(() => UserSolution) | null>(null);
	const [solutionWasUpdated, setSolutionWasUpdated] = useState(false);

	const [showTextModal, setShowTextModal] = useState(false);
	const [timesListened, setTimesListened] = useState(0);
	const [showBlankModal, setShowBlankModal] = useState(false);

	const examState = useExamStore((state) => state);
	const persistentExamState = usePersistentExamStore((state) => state);

	const {
		partIndex, assignment,
		userSolutions, flags, timeSpentCurrentModule,
		setBgColor, setUserSolutions, setTimeIsUp,
		dispatch
	} = !preview ? examState : persistentExamState;

	const { finalizeModule, timeIsUp } = flags;

	const timer = useRef(exam.minTimer - timeSpentCurrentModule / 60);

	const {
		nextExercise, previousExercise,
		showPartDivider, setShowPartDivider,
		seenParts, setSeenParts,
		isBetweenParts, startNow
	} = useExamNavigation({
		exam, module: "listening", showBlankModal,
		setShowBlankModal, showSolutions, preview,
		allPartExercisesRender: true, disableBetweenParts: true
	});


	useEffect(() => {
		if (finalizeModule || timeIsUp) {
			updateTimers();
			if (timeIsUp) setTimeIsUp(false);
			dispatch({ type: "FINALIZE_MODULE", payload: { updateTimers: false } })
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [finalizeModule, timeIsUp])


	const registerSolution = useCallback((updateSolution: () => UserSolution) => {
		userSolutionRef.current = updateSolution;
		setSolutionWasUpdated(true);
	}, []);

	useEffect(() => {
		if (solutionWasUpdated && userSolutionRef.current) {
			const solution = userSolutionRef.current();
			setUserSolutions([...userSolutions.filter((x) => x.exercise !== solution.exercise), { ...solution, module: "listening", exam: exam.id }]);
			setSolutionWasUpdated(false);
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [solutionWasUpdated])


	const renderPartExercises = useMemo(() => {
		const exercises = exam.parts[partIndex].exercises;
		const formattedExercises = exercises.map(exercise => ({
			...exercise,
			userSolutions: userSolutions.find((x) => x.exercise === exercise.id)?.solutions || [],
		}))

		const hasPractice = exercises.some(e => e.isPractice)

		return (
			<div className="flex flex-col gap-4">
				<PracticeModal open={hasPractice} />
				{formattedExercises.map(e => showSolutions
					? renderSolution(e)
					: (!startNow && !showPartDivider && !isBetweenParts && !showSolutions) && renderExercise(e, exam.id, registerSolution, preview))}
			</div>
		)
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [partIndex, startNow, showPartDivider, isBetweenParts, showSolutions]);

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

	const handlePartDividerClick = () => {
		setShowPartDivider(false);
		setBgColor("bg-white");
		setSeenParts((prev) => new Set(prev).add(partIndex));
	}

	useEffect(() => {
		setTimesListened(0);
	}, [partIndex])

	const progressButtons = useMemo(() =>
		// Do not remove the ()=> in handle next
		<ProgressButtons handlePrevious={previousExercise} handleNext={() => nextExercise()} />
		, [nextExercise, previousExercise]);

	const memoizedRenderAudioPlayer = useMemo(() =>
		<RenderAudioPlayer
			audioSource={exam?.parts[partIndex]?.audio?.source}
			repeatableTimes={exam?.parts[partIndex]?.audio?.repeatableTimes}
			script={exam?.parts[partIndex]?.script}
			assignment={assignment}
			timesListened={timesListened}
			setShowTextModal={setShowTextModal}
			setTimesListened={setTimesListened}
		// eslint-disable-next-line react-hooks/exhaustive-deps
		/>, [partIndex, assignment, timesListened, setShowTextModal, setTimesListened])

	const memoizedInstructions = useMemo(() =>
		<RenderAudioInstructionsPlayer instructions={exam.instructions} />
		, [exam.instructions])

	return (
		<>
			{showPartDivider ?
				<PartDivider
					module="listening"
					sectionLabel="Section"
					defaultTitle="Listening exam"
					section={exam.parts[partIndex]}
					sectionIndex={partIndex}
					onNext={handlePartDividerClick}
				/> : (
					<>
						<BlankQuestionsModal isOpen={showBlankModal} onClose={confirmFinishModule} />
						{!startNow && exam.parts[partIndex].script &&
							<ScriptModal script={exam.parts[partIndex].script!} isOpen={showTextModal} onClose={() => setShowTextModal(false)} />
						}
						<div className="flex flex-col h-full w-full gap-8 justify-between">
							{exam.parts.length > 1 && <SectionNavbar
								module="listening"
								sectionLabel="Part"
								seenParts={seenParts}
								setShowPartDivider={setShowPartDivider}
								setSeenParts={setSeenParts}
								preview={preview}
							/>
							}
							<ModuleTitle
								exerciseIndex={partIndex + 1}
								minTimer={timer.current}
								module="listening"
								totalExercises={exam.parts.length}
								disableTimer={showSolutions || preview}
								indexLabel="Part"
								preview={preview}
							/>

							{/* Audio Player for the Instructions */}
							{startNow && memoizedInstructions}

							{/* Part's audio player */}
							{!startNow && memoizedRenderAudioPlayer}

							{/* Exercise renderer */}
							<>
								{(!startNow && !showPartDivider) && progressButtons}
								{renderPartExercises}
								{(!startNow && !showPartDivider && !isBetweenParts) && progressButtons}
							</>
						</div>

						{((startNow) && !showPartDivider && !showSolutions) &&
							<ProgressButtons
								hidePrevious={partIndex == 0 && startNow}
								nextLabel={startNow ? "Start now" : "Next Page"}
								handlePrevious={previousExercise}
								handleNext={() => nextExercise()} />
						}
					</>)
			}
		</>
	);
}

export default Listening;
