import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
import SortableSection from "../../Shared/SortableSection";
import { Exercise, InteractiveSpeakingExercise, LevelPart, ListeningPart, ReadingPart, SpeakingExercise, WritingExercise } from "@/interfaces/exam";
import ExerciseItem from "./types";
import Dropdown from "@/components/Dropdown";
import useExamEditorStore from "@/stores/examEditor";
import Writing from "../../Exercises/Writing";
import Speaking from "../../Exercises/Speaking";
import { ReactElement, ReactNode, useEffect, useState } from "react";
import {
    DndContext,
    PointerSensor,
    useSensor,
    useSensors,
    closestCenter,
} from '@dnd-kit/core';
import GenLoader from "../../Exercises/Shared/GenLoader";
import { ExamPart, Generating } from "@/stores/examEditor/types";
import React from "react";
import getExerciseItems from "./exercises";
import { Action } from "@/stores/examEditor/reducers";
import { writingTask } from "@/stores/examEditor/sections";
import { createSpeakingExercise } from "./speaking";


interface QuestionItemsResult {
    ids: string[];
    items: ExerciseItem[];
}

const SectionExercises: React.FC<{ sectionId: number; }> = ({ sectionId }) => {
    const dispatch = useExamEditorStore(state => state.dispatch);
    const currentModule = useExamEditorStore(state => state.currentModule);

    const sections = useExamEditorStore(state => state.modules[currentModule].sections);
    const expandedSections = useExamEditorStore(state => state.modules[currentModule].expandedSections);

    const section = useExamEditorStore(
        state => state.modules[currentModule].sections.find(
            section => section.sectionId === sectionId
        )
    );

    const genResult = section?.genResult;
    const generating = section?.generating;
    const levelGenResults = section?.levelGenResults
    const levelGenerating = section?.levelGenerating;
    const sectionState = section?.state;

    useEffect(() => {
        if (genResult && genResult.generating === "exercises" && genResult.module === currentModule) {
            const newExercises = genResult.result[0].exercises;
            dispatch({
                type: "UPDATE_SECTION_STATE", payload: {
                    sectionId,
                    module: genResult.module,
                    update: {
                        exercises: [...(sectionState as ExamPart).exercises, ...newExercises]
                    }
                }
            })
            dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: currentModule, field: "generating", value: undefined } })
            dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: currentModule, field: "genResult", value: undefined } })
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [genResult, dispatch, sectionId, currentModule]);


    useEffect(() => {
        if (levelGenResults && levelGenResults.some(res => res.generating.startsWith("exercises"))) {
            const newExercises = levelGenResults
                .filter(res => res.generating.startsWith("exercises"))
                .map(res => res.result[0].exercises)
                .flat();

            const updates = [
                {
                    type: "UPDATE_SECTION_STATE",
                    payload: {
                        sectionId,
                        module: "level",
                        update: {
                            exercises: [...(sectionState as ExamPart).exercises, ...newExercises]
                        }
                    }
                },
                {
                    type: "UPDATE_SECTION_SINGLE_FIELD",
                    payload: {
                        sectionId,
                        module: currentModule,
                        field: "levelGenerating",
                        value: levelGenerating?.filter(g => !g?.startsWith("exercises"))
                    }
                },
                {
                    type: "UPDATE_SECTION_SINGLE_FIELD",
                    payload: {
                        sectionId,
                        module: currentModule,
                        field: "levelGenResults",
                        value: levelGenResults.filter(res => !res.generating.startsWith("exercises"))
                    }
                }
            ] as Action[];

            updates.forEach(update => dispatch(update));
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [levelGenResults, sectionState, levelGenerating, sectionId, currentModule]);

    useEffect(() => {
        if (levelGenResults && levelGenResults.some(res => res.generating === "writing_letter" || res.generating === "writing_2")) {
            const results = levelGenResults.filter(res => res.generating === "writing_letter" || res.generating === "writing_2");

            const updates = [
                {
                    type: "UPDATE_SECTION_STATE",
                    payload: {
                        sectionId,
                        module: "level",
                        update: {
                            exercises: [...(sectionState as ExamPart).exercises,
                            ...results.map((res) => {
                                return {
                                    ...writingTask(res.generating === "writing_letter" ? 1 : 2),
                                    prompt: res.result[0].prompt,
                                    variant: res.generating === "writing_letter" ? "letter" : "essay"
                                } as WritingExercise;
                            })
                            ]
                        }
                    }
                },
                {
                    type: "UPDATE_SECTION_SINGLE_FIELD",
                    payload: {
                        sectionId,
                        module: currentModule,
                        field: "levelGenerating",
                        value: levelGenerating?.filter(g => !results.flatMap(res => res.generating as Generating).includes(g))
                    }
                },
                {
                    type: "UPDATE_SECTION_SINGLE_FIELD",
                    payload: {
                        sectionId,
                        module: currentModule,
                        field: "levelGenResults",
                        value: levelGenResults.filter(res => !results.flatMap(res => res.generating as Generating).includes(res.generating))
                    }
                }
            ] as Action[];

            updates.forEach(update => dispatch(update));
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [levelGenResults, sectionState, levelGenerating, sectionId, currentModule]);

    useEffect(() => {
        if (levelGenResults && levelGenResults.some(res => res.generating.startsWith("speaking"))) {
            const results = levelGenResults.filter(res => res.generating.startsWith("speaking"));
            const updates = [
                {
                    type: "UPDATE_SECTION_STATE",
                    payload: {
                        sectionId,
                        module: "level",
                        update: {
                            exercises: [...(sectionState as ExamPart).exercises,
                            ...results.map(createSpeakingExercise)
                            ]
                        }
                    }
                },
                {
                    type: "UPDATE_SECTION_SINGLE_FIELD",
                    payload: {
                        sectionId,
                        module: currentModule,
                        field: "levelGenerating",
                        value: levelGenerating?.filter(g => !results.flatMap(res => res.generating as Generating).includes(g))
                    }
                },
                {
                    type: "UPDATE_SECTION_SINGLE_FIELD",
                    payload: {
                        sectionId,
                        module: currentModule,
                        field: "levelGenResults",
                        value: levelGenResults.filter(res => !results.flatMap(res => res.generating as Generating).includes(res.generating))
                    }
                }
            ] as Action[];

            updates.forEach(update => dispatch(update));
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [levelGenResults, sectionState, levelGenerating, sectionId, currentModule]);

    const currentSection = sections.find((s) => s.sectionId === sectionId)!;

    const sensors = useSensors(
        useSensor(PointerSensor),
    );

    const questionItems = (): QuestionItemsResult => {
        const part = currentSection.state as ReadingPart | ListeningPart | LevelPart;
        const items = getExerciseItems(part.exercises, sectionId);
        return {
            items,
            ids: items.map(item => item.id)
        }
    };

    const background = (component: ReactNode) => {
        return (
            <div className="p-8 shadow-inner border border-gray-200 bg-gray-50 rounded-xl">
                {component}
            </div>
        );
    }

    if (currentModule == "writing") return background(<Writing sectionId={sectionId} exercise={currentSection.state as WritingExercise} module="writing" />);
    if (currentModule == "speaking") return background(<Speaking sectionId={sectionId} exercise={currentSection.state as SpeakingExercise} module="speaking" />);

    const questions = questionItems();

    // #############################################################################
    // Typescript checks so that the compiler and builder don't freak out
    const filteredIds = (questions.ids ?? []).filter(Boolean);

    function isValidItem(item: ExerciseItem | undefined): item is ExerciseItem {
        return item !== undefined &&
            typeof item.id === 'string' &&
            typeof item.sectionId === 'number' &&
            React.isValidElement(item.label) &&
            React.isValidElement(item.content);
    }
    const filteredItems = (questions.items ?? []).filter(isValidItem);
    // #############################################################################


    const onFocus = (questionId: string, id: string | undefined) => {
        if (id) {
            dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { module: currentModule, sectionId, field: "focusedExercise", value: { questionId, id} } })
        }
    }

    return (
        <DndContext
            sensors={sensors}
            collisionDetection={closestCenter}
            onDragEnd={(e) => dispatch({ type: "REORDER_EXERCISES", payload: { event: e, sectionId, module: currentModule } })}
        >
            {expandedSections.includes(sectionId) &&
                questions.items &&
                questions.items.length > 0 &&
                questions.ids &&
                questions.ids.length > 0 && (
                    <div className="mt-4 p-6 rounded-xl shadow-inner border bg-gray-50">
                        <SortableContext
                            items={filteredIds}
                            strategy={verticalListSortingStrategy}
                        >
                            {filteredItems.map(item => (
                                <SortableSection key={item.id} id={item.id}>
                                    <Dropdown
                                        className={`w-full text-left p-4 mb-2 bg-gradient-to-r from-ielts-${currentModule}/60 to-ielts-${currentModule} text-white rounded-lg shadow-lg transition-transform transform hover:scale-102`}
                                        customTitle={item.label}
                                        contentWrapperClassName="rounded-xl"
                                    >
                                        <div tabIndex={4} className="p-4 shadow-inner border border-gray-200 bg-gray-50 rounded-xl" onFocus={() => onFocus(item.id, item.exerciseId)}>
                                            {item.content}
                                        </div>
                                    </Dropdown>
                                </SortableSection>
                            ))}
                        </SortableContext>
                    </div>
                )
            }
            {generating === "exercises" && <GenLoader module={currentModule} className="mt-4" />}
            {currentModule === "level" && (
                <>
                    {
                        questions.ids?.length === 0 && !levelGenerating?.some((g) => g?.startsWith("exercises") || g?.startsWith("writing") ||  g?.startsWith("speaking")) && generating !== "exercises"
                        && background(<span className="flex justify-center">Generated exercises will appear here!</span>)}
                    {levelGenerating?.some((g) => g?.startsWith("exercises") || g?.startsWith("writing") ||  g?.startsWith("speaking")) && <GenLoader module={currentModule} className="mt-4" />}
                </>)
            }
        </DndContext >
    );
}

export default SectionExercises;
