import { FillBlanksExercise, FillBlanksMCOption } from "@/interfaces/exam";
import useExamStore from "@/stores/examStore";
import clsx from "clsx";
import { Fragment, useEffect, 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 [answers, setAnswers] = useState<{ id: string; solution: string }[]>(userSolutions);
    const hasExamEnded = useExamStore((state) => state.hasExamEnded);

    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]);

    const calculateScore = () => {
        const total = text.match(/({{\d+}})/g)?.length || 0;
        const correct = userSolutions.filter((x) => {
          const solution = solutions.find((y) => x.id.toString() === y.id.toString())?.solution;
          if (!solution) return false;
      
          const option = words.find((w) => {
            if (typeof w === "string") {
              return w.toLowerCase() === x.solution.toLowerCase();
            } else if ('letter' in w) {
              return w.word.toLowerCase() === x.solution.toLowerCase();
            } else {
              return w.id === x.id;
            }
          });
          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 solution.toLowerCase() === (option.options[x.solution as keyof typeof option.options] || '').toLowerCase();
          }
          return false;
        }).length;
      
        const missing = total - userSolutions.filter((x) => solutions.find((y) => x.id.toString() === y.id.toString())).length;
      
        return { total, correct, missing };
      };

    const renderLines = (line: string) => {
        return (
            <div className="text-base leading-5">
                {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 focus:ring-0 focus:outline-none focus:!text-white focus:bg-mti-purple transition duration-300 ease-in-out my-1 px-5 py-2 text-center",
                        !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" ? (
                            <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>
        );
    };

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

    return (
        <>
            <div className="flex flex-col gap-4 mt-4 h-full w-full mb-20">
                <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">
                    {text.split("\\n").map((line, index) => (
                        <p key={index} className={clsx(variant === "mc" && "whitespace-pre-wrap")}>
                            {renderLines(line)}
                            <br />
                        </p>
                    ))}
                </span>
                {variant === "mc" && typeCheckWordsMC(words) ? (
                    <>  
                        {currentMCSelection && (
                            <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">
                                    {currentMCSelection.selection?.options && Object.entries(currentMCSelection.selection.options).map(([key, value]) => {
                                        return <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 })}
                    className="max-w-[200px] w-full">
                    Back
                </Button>

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

export default FillBlanks;
