import clsx from "clsx";
import SectionRenderer from "./SectionRenderer";
import Checkbox from "../Low/Checkbox";
import Input from "../Low/Input";
import Select from "../Low/Select";
import { capitalize } from "lodash";
import { Difficulty } from "@/interfaces/exam";
import { useCallback, useEffect, useMemo, useState } from "react";
import { toast } from "react-toastify";
import { ModuleState, SectionState } from "@/stores/examEditor/types";
import { Module } from "@/interfaces";
import useExamEditorStore from "@/stores/examEditor";
import WritingSettings from "./SettingsEditor/writing";
import ReadingSettings from "./SettingsEditor/reading";
import LevelSettings from "./SettingsEditor/level";
import ListeningSettings from "./SettingsEditor/listening";
import SpeakingSettings from "./SettingsEditor/speaking";
import ImportOrStartFromScratch from "./ImportExam/ImportOrFromScratch";
import { defaultSectionSettings } from "@/stores/examEditor/defaults";
import Button from "../Low/Button";
import ResetModule from "./ResetModule";

const DIFFICULTIES: Difficulty[] = ["easy", "medium", "hard"];

const ExamEditor: React.FC<{ levelParts?: number }> = ({ levelParts = 0 }) => {
    const { currentModule, dispatch } = useExamEditorStore();
    const {
        sections,
        minTimer,
        expandedSections,
        examLabel,
        isPrivate,
        difficulty,
        sectionLabels,
        importModule
    } = useExamEditorStore(state => state.modules[currentModule]);

    const [numberOfLevelParts, setNumberOfLevelParts] = useState(levelParts !== 0 ? levelParts : 1);
    const [isResetModuleOpen, setIsResetModuleOpen] = useState(false);

    // For exam edits
    useEffect(() => {
        if (levelParts !== 0) {
            setNumberOfLevelParts(levelParts);
            dispatch({
                type: 'UPDATE_MODULE',
                payload: {
                    updates: {
                        sectionLabels: Array.from({ length: levelParts }).map((_, i) => ({
                            id: i + 1,
                            label: `Part ${i + 1}`
                        }))
                    },
                    module: "level"
                }
            })
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [levelParts])

    useEffect(() => {
        const currentSections = sections;
        const currentLabels = sectionLabels;
        let updatedSections: SectionState[];
        let updatedLabels: any;
        if (currentModule === "level" && currentSections.length !== currentLabels.length || numberOfLevelParts !== currentSections.length) {
            const newSections = [...currentSections];
            const newLabels = [...currentLabels];
            for (let i = currentLabels.length; i < numberOfLevelParts; i++) {
                if (currentSections.length !== numberOfLevelParts) newSections.push(defaultSectionSettings(currentModule, i + 1));
                newLabels.push({
                    id: i + 1,
                    label: `Part ${i + 1}`
                });
            }
            updatedSections = newSections;
            updatedLabels = newLabels;
        } else if (numberOfLevelParts < currentSections.length) {
            updatedSections = currentSections.slice(0, numberOfLevelParts);
            updatedLabels = currentLabels.slice(0, numberOfLevelParts);
        } else {
            return;
        }

        const updatedExpandedSections = expandedSections.filter(
            sectionId => updatedSections.some(section => section.sectionId === sectionId)
        );

        dispatch({
            type: 'UPDATE_MODULE',
            payload: {
                updates: {
                    sections: updatedSections,
                    sectionLabels: updatedLabels,
                    expandedSections: updatedExpandedSections
                }
            }
        });
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [numberOfLevelParts]);

    const sectionIds = sections.map((section) => section.sectionId)

    const updateModule = useCallback((updates: Partial<ModuleState>) => {
        dispatch({ type: 'UPDATE_MODULE', payload: { updates } });
    }, [dispatch]);

    const toggleSection = (sectionId: number) => {
        if (expandedSections.length === 1 && sectionIds.includes(sectionId)) {
            toast.error("Include at least one section!");
            return;
        }
        dispatch({ type: 'TOGGLE_SECTION', payload: { sectionId } });
    };

    const ModuleSettings: Record<Module, React.ComponentType> = {
        reading: ReadingSettings,
        writing: WritingSettings,
        speaking: SpeakingSettings,
        listening: ListeningSettings,
        level: LevelSettings
    };

    const Settings = ModuleSettings[currentModule];
    const showImport = importModule && ["reading", "listening", "level"].includes(currentModule);

    const updateLevelParts = (parts: number) => {
        setNumberOfLevelParts(parts);
    }

    return (
        <>
            {showImport ? <ImportOrStartFromScratch module={currentModule} setNumberOfLevelParts={updateLevelParts} /> : (
                <>
                    {isResetModuleOpen && <ResetModule module={currentModule} isOpen={isResetModuleOpen} setIsOpen={setIsResetModuleOpen} setNumberOfLevelParts={setNumberOfLevelParts}/>}
                    <div className="flex gap-4 w-full items-center">
                        <div className="flex flex-col gap-3">
                            <label className="font-normal text-base text-mti-gray-dim">Timer</label>
                            <Input
                                type="number"
                                name="minTimer"
                                onChange={(e) => updateModule({ minTimer: parseInt(e) < 15 ? 15 : parseInt(e) })}
                                value={minTimer}
                                className="max-w-[300px]"
                            />
                        </div>
                        <div className="flex flex-col gap-3 flex-grow">
                            <label className="font-normal text-base text-mti-gray-dim">Difficulty</label>
                            <Select
                                options={DIFFICULTIES.map((x) => ({ value: x, label: capitalize(x) }))}
                                onChange={(value) => value && updateModule({ difficulty: value.value as Difficulty })}
                                value={{ value: difficulty, label: capitalize(difficulty) }}
                            />
                        </div>
                        {(sectionLabels.length != 0 && currentModule !== "level") ? (
                            <div className="flex flex-col gap-3">
                                <label className="font-normal text-base text-mti-gray-dim">{sectionLabels[0].label.split(" ")[0]}</label>
                                <div className="flex flex-row gap-8">
                                    {sectionLabels.map(({ id, label }) => (
                                        <span
                                            key={id}
                                            className={clsx(
                                                "px-6 py-4 w-48 h-[72px] flex justify-center items-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer",
                                                "transition duration-300 ease-in-out",
                                                sectionIds.includes(id)
                                                    ? `bg-ielts-${currentModule}/70 border-ielts-${currentModule} text-white`
                                                    : "bg-white border-mti-gray-platinum"
                                            )}
                                            onClick={() => toggleSection(id)}
                                        >
                                            {label}
                                        </span>
                                    ))}
                                </div>
                            </div>

                        ) : (
                            <div className="flex flex-col gap-3 w-1/3">
                                <label className="font-normal text-base text-mti-gray-dim">Number of Parts</label>
                                <Input type="number" name="Number of Parts" min={1} onChange={(v) => setNumberOfLevelParts(parseInt(v))} value={numberOfLevelParts} />
                            </div>
                        )}
                        <div className="flex flex-col gap-3 w-fit h-fit">
                            <div className="h-6" />
                            <Checkbox isChecked={isPrivate} onChange={(checked) => updateModule({ isPrivate: checked })}>
                                Privacy (Only available for Assignments)
                            </Checkbox>
                        </div>
                    </div>
                    <div className="flex flex-row gap-3 w-full">
                        <div className="flex flex-col gap-3 flex-grow">
                        <label className="font-normal text-base text-mti-gray-dim">Exam Label *</label>
                        <Input
                            type="text"
                            placeholder="Exam Label"
                            name="label"
                            onChange={(text) => updateModule({ examLabel: text })}
                            roundness="xl"
                            value={examLabel}
                            required
                        />
                        </div>
                        {["reading", "listening", "level"].includes(currentModule) && <Button onClick={() => setIsResetModuleOpen(true)} customColor={`bg-ielts-${currentModule}/70 hover:bg-ielts-${currentModule} border-ielts-${currentModule}`} className={`text-white self-end`}>
                                Reset Module
                        </Button>}
                    </div>
                    <div className="flex flex-row gap-8">
                        <Settings />
                        <div className="flex-grow max-w-[66%]">
                            <SectionRenderer />
                        </div>
                    </div>
                </>
            )}
        </>
    );
};

export default ExamEditor;
