import { FillBlanksExercise, FillBlanksMCOption } from "@/interfaces/exam";
import useExamStore from "@/stores/examStore";
import clsx from "clsx";
import { Fragment, useCallback, useEffect, useMemo, useState } from "react";
import reactStringReplace from "react-string-replace";
import { CommonProps } from "..";
import Button from "../../Low/Button";
import { v4 } from "uuid";


const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
    id,
    type,
    prompt,
    solutions,
    text,
    words,
    userSolutions,
    variant,
    onNext,
    onBack,
}) => {
    const { shuffles, exam, partIndex, questionIndex, exerciseIndex } = useExamStore((state) => state);
    const [answers, setAnswers] = useState<{ id: string; solution: string }[]>(userSolutions);
    const hasExamEnded = useExamStore((state) => state.hasExamEnded);
    const setCurrentSolution = useExamStore((state) => state.setCurrentSolution);
    const shuffleMaps = shuffles.find((x) => x.exerciseID == id)?.shuffles;

    const [currentMCSelection, setCurrentMCSelection] = useState<{ id: string, selection: FillBlanksMCOption }>();

    const typeCheckWordsMC = (words: any[]): words is FillBlanksMCOption[] => {
        return Array.isArray(words) && words.every(
            word => word && typeof word === 'object' && 'id' in word && 'options' in word
        );
    }

    const excludeWordMCType = (x: any) => {
        return typeof x === "string" ? x : x as { letter: string; word: string };
    }

    useEffect(() => {
        if (hasExamEnded) onNext({ exercise: id, solutions: answers, score: calculateScore(), type });
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [hasExamEnded]);


    let correctWords: any;
    if (exam && (exam.module === "level" || exam.module === "reading") && exam.parts[partIndex].exercises[exerciseIndex].type === "fillBlanks") {
        correctWords = (exam.parts[partIndex].exercises[exerciseIndex] as FillBlanksExercise).words;
    }

    const calculateScore = () => {
        const total = text.match(/({{\d+}})/g)?.length || 0;
        const correct = answers!.filter((x) => {
            const solution = solutions.find((y) => x.id.toString() === y.id.toString())?.solution;
            if (!solution) return false;
            const option = correctWords!.find((w: any) => {
                if (typeof w === "string") {
                    return w.toLowerCase() === x.solution.toLowerCase();
                } else if ('letter' in w) {
                    return w.letter.toLowerCase() === x.solution.toLowerCase();
                } else {
                    return w.id.toString() === x.id.toString();
                }
            });
            if (!option) return false;

            if (typeof option === "string") {
                return solution.toLowerCase() === option.toLowerCase();
            } else if ('letter' in option) {
                return solution.toLowerCase() === option.word.toLowerCase();
            } else if ('options' in option) {
                return option.options[solution as keyof typeof option.options] == x.solution;
            }
            return false;
        }).length;
        const missing = total - answers!.filter((x) => solutions.find((y) => x.id.toString() === y.id.toString())).length;
        return { total, correct, missing };
    };
    const renderLines = useCallback((line: string) => {
        return (
            <div className="text-base leading-5" key={v4()}>
                {reactStringReplace(line, /({{\d+}})/g, (match) => {
                    const id = match.replaceAll(/[\{\}]/g, "");
                    const userSolution = answers.find((x) => x.id === id);
                    const styles = clsx(
                        "rounded-full hover:text-white transition duration-300 ease-in-out my-1 px-5 py-2 text-center",
                        currentMCSelection?.id == id && "!bg-mti-purple !text-white !outline-none !ring-0",
                        !userSolution && "text-center text-mti-purple-light bg-mti-purple-ultralight",
                        userSolution && "text-center text-mti-purple-dark bg-mti-purple-ultralight",
                    )
                    return (
                        variant === "mc" ? (
                            <>
                                {/*<span className="mr-2">{`(${id})`}</span>*/}
                                <button
                                    className={styles}
                                    onClick={() => {
                                        setCurrentMCSelection(
                                            {
                                                id: id,
                                                selection: words.find((x) => {
                                                    if (typeof x !== "string" && 'id' in x) {
                                                        return (x as FillBlanksMCOption).id.toString() == id.toString();
                                                    }
                                                    return false;
                                                }) as FillBlanksMCOption
                                            }
                                        );
                                    }}
                                >
                                    {userSolution?.solution === undefined ? <span className="text-transparent select-none">placeholder</span> : <span> {userSolution.solution} </span>}
                                </button>
                            </>
                        ) : (
                            <input
                                className={styles}
                                onChange={(e) => setAnswers((prev) => [...prev.filter((x) => x.id !== id), { id, solution: e.target.value }])}
                                value={userSolution?.solution} />
                        )
                    );
                })}
            </div>
        );
    }, [variant, words, setCurrentMCSelection, answers, currentMCSelection]);

    const memoizedLines = useMemo(() => {
        return text.split("\\n").map((line, index) => (
          <p key={index} className={clsx(variant === "mc" && "whitespace-pre-wrap")}>
            {renderLines(line)}
            <br />
          </p>
        ));
        // eslint-disable-next-line react-hooks/exhaustive-deps
      }, [text, variant, renderLines, currentMCSelection]);


    const onSelection = (questionID: string, value: string) => {
        setAnswers((prev) => [...prev.filter((x) => x.id !== questionID), { id: questionID, solution: value }]);
    }

    useEffect(() => {
        if (variant === "mc") {
            setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps });
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [answers])

    return (
        <>
            <div className="flex flex-col gap-4 mt-4 h-full w-full mb-20">
                {variant !== "mc" && <span className="text-sm w-full leading-6">
                    {prompt.split("\\n").map((line, index) => (
                        <Fragment key={index}>
                            {line}
                            <br />
                        </Fragment>
                    ))}
                </span>}
                <span className="bg-mti-gray-smoke rounded-xl px-5 py-6">
                    {memoizedLines}
                </span>
                {variant === "mc" && typeCheckWordsMC(words) ? (
                    <>
                        {currentMCSelection && (
                            <div className="bg-mti-gray-smoke rounded-xl flex flex-col gap-4 px-16 py-8">
                                <span className="font-medium text-lg text-mti-purple-dark mb-4 px-2">{`${currentMCSelection.id} - Select the appropriate word.`}</span>
                                <div className="flex gap-4 flex-wrap justify-between">
                                    {currentMCSelection.selection?.options && Object.entries(currentMCSelection.selection.options).sort((a, b) => a[0].localeCompare(b[0])).map(([key, value]) => {
                                        return <div
                                            key={v4()}
                                            onClick={() => onSelection(currentMCSelection.id, value)}
                                            className={clsx(
                                                "flex border p-4 rounded-xl gap-2 cursor-pointer bg-white text-base",
                                                !!answers.find((x) => x.solution.toLocaleLowerCase() === value.toLocaleLowerCase() && x.id === currentMCSelection.id) &&
                                                "border-mti-purple-light",
                                            )}>
                                            <span className="font-semibold">{key}.</span>
                                            <span>{value}</span>
                                        </div>

                                        /*<button
                                            className={clsx(
                                                "border border-mti-purple-light rounded-full px-3 py-0.5 transition ease-in-out duration-300",
                                                !!answers.find((x) => x.solution.toLocaleLowerCase() === value.toLocaleLowerCase() && x.id === currentMCSelection.id) &&
                                                "bg-mti-purple-dark text-white",
                                            )}
                                            key={v4()}
                                            onClick={() => onSelection(currentMCSelection.id, value)}
                                        >
                                            {value}
                                        </button>;*/
                                    })}
                                </div>
                            </div>
                        )}
                    </>
                ) : (
                    <div className="bg-mti-gray-smoke rounded-xl px-5 py-6 flex flex-col gap-4">
                        <span className="font-medium text-mti-purple-dark">Options</span>
                        <div className="flex gap-4 flex-wrap">
                            {words.map((v) => {
                                v = excludeWordMCType(v);
                                const text = typeof v === "string" ? v : `${v.letter} - ${v.word}`;

                                return (
                                    <span
                                        className={clsx(
                                            "border border-mti-purple-light rounded-full px-3 py-0.5 transition ease-in-out duration-300",
                                            !!answers.find((x) => x.solution.toLowerCase() === (typeof v === "string" ? v : ("letter" in v ? v.letter : "")).toLowerCase()) &&
                                            "bg-mti-purple-dark text-white",
                                        )}
                                        key={v4()}
                                    >
                                        {text}
                                    </span>
                                )
                            })}
                        </div>
                    </div >
                )}
            </div>
            <div className="self-end flex justify-between w-full gap-8 absolute bottom-8 left-0 px-8">
                <Button
                    color="purple"
                    variant="outline"
                    onClick={() => onBack({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps })}
                    className="max-w-[200px] w-full"
                    disabled={
                        exam && exam.module === "level" &&
                        typeof exam.parts[0].intro === "string" &&
                        partIndex === 0 &&
                        questionIndex === 0
                    }
                >
                    Back
                </Button>

                <Button
                    color="purple"
                    onClick={() => { onNext({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps }) }}
                    className="max-w-[200px] self-end w-full">
                    Next
                </Button>
            </div>
        </>
    );
}

export default FillBlanks;
