import useExamEditorStore from "@/stores/examEditor";
import useSettingsState from "../../Hooks/useSettingsState";
import { SpeakingSectionSettings } from "@/stores/examEditor/types";
import Option from "@/interfaces/option";
import SettingsEditor from "..";
import { InteractiveSpeakingExercise, SpeakingExam, SpeakingExercise } from "@/interfaces/exam";
import { toast } from "react-toastify";
import { usePersistentExamStore } from "@/stores/exam";
import { useRouter } from "next/router";
import openDetachedTab from "@/utils/popout";
import axios from "axios";
import { playSound } from "@/utils/sound";
import SpeakingComponents from "./components";
import { getExamById } from "@/utils/exams";

export interface Avatar {
    name: string;
    gender: string;
}

const SpeakingSettings: React.FC = () => {

    const router = useRouter();

    const {
        setExam,
        setExerciseIndex,
        setQuestionIndex,
        setBgColor,
    } = usePersistentExamStore();

    const { title, currentModule } = useExamEditorStore();
    const { focusedSection, difficulty, sections, minTimer, isPrivate } = useExamEditorStore((store) => store.modules[currentModule])

    const section = sections.find((section) => section.sectionId == focusedSection)?.state;

    const { localSettings, updateLocalAndScheduleGlobal } = useSettingsState<SpeakingSectionSettings>(
        currentModule,
        focusedSection,
    );

    if (section === undefined) return <></>;

    const currentSection = section as SpeakingExercise | InteractiveSpeakingExercise;

    const defaultPresets: Option[] = [
        {
            label: "Preset: Speaking Part 1",
            value: "Welcome to {part} of the {label}. You will engage in a conversation about yourself and familiar topics such as your home, family, work, studies, and interests. General questions will be asked."
          },
          {
            label: "Preset: Speaking Part 2",
            value: "Welcome to {part} of the {label}. You will be given a topic card describing a particular person, object, event, or experience."
          },
          {
            label: "Preset: Speaking Part 3",
            value: "Welcome to {part} of the {label}. You will engage in an in-depth discussion about abstract ideas and issues. The examiner will ask questions that require you to explain, analyze, and speculate about various aspects of the topic."
          }
    ];

    const canPreviewOrSubmit = (() => {
        return sections.every((s) => {
            const section = s.state as SpeakingExercise | InteractiveSpeakingExercise;
            switch (section.type) {
                case 'speaking':
                    return section.title !== '' &&
                        section.text !== '' &&
                        section.video_url !== '' &&
                        section.prompts.every(prompt => prompt !== '');

                case 'interactiveSpeaking':
                    if ('first_title' in section && 'second_title' in section) {
                        return section.first_title !== '' &&
                            section.second_title !== '' &&
                            section.prompts.every(prompt => prompt.video_url !== '') &&
                            section.prompts.length > 2;
                    }
                    return section.title !== '' &&
                        section.prompts.every(prompt => prompt.video_url !== '');

                default:
                    return false;
            }
        });
    })();

    const submitSpeaking = async () => {
        if (title === "") {
          toast.error("Enter a title for the exam!");
          return;
        }
      
        try {
          const formData = new FormData();
          const urlMap = new Map<string, string>();
      
          const sectionsWithVideos = sections.filter(s => {
            const exercise = s.state as SpeakingExercise | InteractiveSpeakingExercise;
            if (exercise.type === "speaking") {
              return exercise.video_url !== "";
            }
            if (exercise.type === "interactiveSpeaking") {
              return exercise.prompts?.some(prompt => prompt.video_url !== "");
            }
            return false;
          });
      
          if (sectionsWithVideos.length === 0) {
            toast.error('No video sections found in the exam! Please record or import videos.');
            return;
          }
      
          await Promise.all(
            sectionsWithVideos.map(async (section) => {
              const exercise = section.state as SpeakingExercise | InteractiveSpeakingExercise;
              
              if (exercise.type === "speaking") {
                const response = await fetch(exercise.video_url);
                const blob = await response.blob();
                formData.append('file', blob, 'video.mp4');
                urlMap.set(`${section.sectionId}`, exercise.video_url);
              } else {
                await Promise.all(
                  exercise.prompts.map(async (prompt, promptIndex) => {
                    if (prompt.video_url) {
                      const response = await fetch(prompt.video_url);
                      const blob = await response.blob();
                      formData.append('file', blob, 'video.mp4');
                      urlMap.set(`${section.sectionId}-${promptIndex}`, prompt.video_url);
                    }
                  })
                );
              }
            })
          );
      
          const response = await axios.post('/api/storage', formData, {
            params: {
              directory: 'speaking_videos'
            },
            headers: {
              'Content-Type': 'multipart/form-data'
            }
          });
      
          const { urls } = response.data;
      
          const exam: SpeakingExam = {
            exercises: sections.map((s) => {
              const exercise = s.state as SpeakingExercise | InteractiveSpeakingExercise;
      
              if (exercise.type === "speaking") {
                const videoIndex = Array.from(urlMap.entries())
                  .findIndex(([key]) => key === `${s.sectionId}`);
                
                return {
                  ...exercise,
                  video_url: videoIndex !== -1 ? urls[videoIndex] : exercise.video_url,
                  intro: s.settings.currentIntro,
                  category: s.settings.category
                };
              } else {
                const updatedPrompts = exercise.prompts.map((prompt, promptIndex) => {
                  const videoIndex = Array.from(urlMap.entries())
                    .findIndex(([key]) => key === `${s.sectionId}-${promptIndex}`);
                  
                  return {
                    ...prompt,
                    video_url: videoIndex !== -1 ? urls[videoIndex] : prompt.video_url
                  };
                });
      
                return {
                  ...exercise,
                  prompts: updatedPrompts,
                  intro: s.settings.currentIntro,
                  category: s.settings.category
                };
              }
            }),
            minTimer,
            module: "speaking",
            id: title,
            isDiagnostic: true, // using isDiagnostic to keep exam hidden until the respective approval workflow is completed.
            variant: undefined,
            difficulty,
            instructorGender: "varied",
            private: isPrivate,
          };
      
          const result = await axios.post('/api/exam/speaking', exam);
          playSound("sent");
          toast.success(`Submitted Exam ID: ${result.data.id}`);
      
          Array.from(urlMap.values()).forEach(url => {
            URL.revokeObjectURL(url);
          });

          const requestBody = await (async () => {
            const handledExam = await getExamById("speaking", result.data.id);
            return {
              examAuthor: handledExam?.createdBy ?? "Unknown Author",
              examEntities: handledExam?.entities ?? [],
              examId: handledExam?.id ?? "Unknown ID",
              examModule: "speaking"
            };
          })();
          await axios
            .post(`/api/approval-workflows`, requestBody)
            .then((response) => {
              if (response.status === 200) {
                toast.success(`Approval Workflows for exam have been successfully created`);
              } else if (response.status === 207) {
                toast.warning(
                  `Approval Workflows were partially created. Exam author might not have a configured workflow for all its entities.`
                );
              }
            })
            .catch((reason) => {
              if (reason.response?.status === 404) {
                toast.error("No configured workflow found for examAuthor for any of its entities.");
              } else {
                toast.error(
                  "Something went wrong while creating approval workflow, please try again later."
                );
              }
            });
      
        } catch (error: any) {
          toast.error(
            "Something went wrong while submitting, please try again later."
          );
        }
      };

    const preview = () => {
        setExam({
            exercises: sections
                .filter((s) => {
                    const exercise = s.state as SpeakingExercise | InteractiveSpeakingExercise;

                    if (exercise.type === "speaking") {
                        return exercise.video_url !== "";
                    }

                    if (exercise.type === "interactiveSpeaking") {
                        return exercise.prompts?.every(prompt => prompt.video_url !== "");
                    }

                    return false;
                })
                .map((s) => {
                    const exercise = s.state as SpeakingExercise | InteractiveSpeakingExercise;
                    return {
                        ...exercise,
                        intro: s.settings.currentIntro,
                        category: s.settings.category
                    };
                }),
            minTimer,
            module: "speaking",
            id: title,
            isDiagnostic: false,
            variant: undefined,
            difficulty,
            private: isPrivate,
        } as SpeakingExam);
        setExerciseIndex(0);
        setQuestionIndex(0);
        setBgColor("bg-white");
        openDetachedTab("popout?type=Exam&module=speaking", router)
    }

    return (
        <SettingsEditor
            sectionLabel={`Speaking ${focusedSection}`}
            sectionId={focusedSection}
            module="speaking"
            introPresets={[defaultPresets[focusedSection - 1]]}
            preview={preview}
            canPreview={canPreviewOrSubmit}
            canSubmit={canPreviewOrSubmit}
            submitModule={submitSpeaking}
        >
           <SpeakingComponents
                {...{ localSettings, updateLocalAndScheduleGlobal, section: currentSection }}
            />
        </SettingsEditor>
    );
};

export default SpeakingSettings;
