import useExamEditorStore from "@/stores/examEditor";
import { LevelSectionSettings, SpeakingSectionSettings } from "@/stores/examEditor/types";
import { useCallback, useEffect, useState } from "react";
import { generate } from "../Shared/Generate";
import Dropdown from "../Shared/SettingsDropdown";
import Input from "@/components/Low/Input";
import GenerateBtn from "../Shared/GenerateBtn";
import clsx from "clsx";
import { FaFemale, FaMale } from "react-icons/fa";
import { Difficulty, InteractiveSpeakingExercise, LevelPart, SpeakingExercise } from "@/interfaces/exam";
import { toast } from "react-toastify";
import { generateVideos } from "../Shared/generateVideos";
import { Module } from "@/interfaces";
import useCanGenerate from "./useCanGenerate";
import ReactSelect, { components } from "react-select";
import { capitalize } from "lodash";
import Option from "@/interfaces/option";
import { MdSignalCellularAlt } from "react-icons/md";

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

interface Props {
    localSettings: SpeakingSectionSettings | LevelSectionSettings;
    updateLocalAndScheduleGlobal: (updates: Partial<SpeakingSectionSettings | LevelSectionSettings>, schedule?: boolean) => void;
    section: SpeakingExercise | InteractiveSpeakingExercise | LevelPart;
    level?: boolean;
    module?: Module;
    id?: string;
    sectionId?: number;
}

const SpeakingComponents: React.FC<Props> = ({ localSettings, updateLocalAndScheduleGlobal, section, level = false, module = "speaking", id, sectionId }) => {

    const { currentModule, speakingAvatars, dispatch, modules } = useExamEditorStore();
    const { focusedSection, difficulty, sections } = useExamEditorStore((store) => store.modules[level ? "level" : currentModule])
    const state = sections.find((s) => s.sectionId === sectionId);

    const [selectedAvatar, setSelectedAvatar] = useState<Avatar | null>(null);

    const randomDiff = difficulty.length === 1 
        ? capitalize(difficulty[0]) 
        : `Random (${difficulty.map(dif => capitalize(dif)).join(", ")})` as Difficulty;
        
    const DIFFICULTIES = difficulty.length === 1 
        ? ["A1", "A2", "B1", "B2", "C1", "C2"]
        : ["A1", "A2", "B1", "B2", "C1", "C2", randomDiff];
    
    const difficultyOptions: Option[] = DIFFICULTIES.map(level => ({
        label: level,
        value: level
    }));
    const [specificDiff, setSpecificDiff] = useState(randomDiff);

    const generateScript = useCallback((scriptSectionId: number) => {
        const queryParams: {
            difficulty: string[];
            first_topic?: string;
            second_topic?: string;
            topic?: string;
        } = { difficulty };

        if (scriptSectionId === 1) {
            if (localSettings.speakingTopic) {
                queryParams['first_topic'] = localSettings.speakingTopic;
            }
            if (localSettings.speakingSecondTopic) {
                queryParams['second_topic'] = localSettings.speakingSecondTopic;
            }
        } else {
            if (localSettings.speakingTopic) {
                queryParams['topic'] = localSettings.speakingTopic;
            }
        }
        generate(
            level ? section.sectionId! : focusedSection,
            "speaking",
            `${id ? `${id}-` : ''}speakingScript`,
            {
                method: 'GET',
                queryParams
            },
            (data: any) => {
                switch (level ? section.sectionId! : focusedSection) {
                    case 1:
                        return [{
                            prompts: data.questions,
                            first_topic: data.first_topic,
                            second_topic: data.second_topic,
                            difficulty: specificDiff.length == 2 ? specificDiff : difficulty,
                        }];
                    case 2:
                        return [{
                            topic: data.topic,
                            question: data.question,
                            prompts: data.prompts,
                            suffix: data.suffix,
                            difficulty: specificDiff.length == 2 ? specificDiff : difficulty,
                        }];
                    case 3:
                        return [{
                            title: data.topic,
                            prompts: data.questions,
                            difficulty: specificDiff.length == 2 ? specificDiff : difficulty,
                        }];
                    default:
                        return [data];
                }
            },
            sectionId,
            level
        );

    }, [difficulty, level, section.sectionId, focusedSection, id, sectionId, localSettings.speakingTopic, localSettings.speakingSecondTopic, specificDiff]);

    const onTopicChange = useCallback((speakingTopic: string) => {
        updateLocalAndScheduleGlobal({ speakingTopic });
    }, [updateLocalAndScheduleGlobal]);

    const onSecondTopicChange = useCallback((speakingSecondTopic: string) => {
        updateLocalAndScheduleGlobal({ speakingSecondTopic });
    }, [updateLocalAndScheduleGlobal]);

    const canGenerate = useCanGenerate({
        section,
        sections,
        id,
        focusedSection
    });

    useEffect(() => {
        if (!canGenerate) {
            updateLocalAndScheduleGlobal({ isGenerateVideoOpen: false }, false);
        }
    }, [canGenerate, updateLocalAndScheduleGlobal]);

    const generateVideoCallback = useCallback((sectionId: number) => {
        if (level) {
            dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: "level", field: "levelGenerating", value: [...state!.levelGenerating, `${id ? `${id}-` : ''}video`] } })
        } else {
            dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId: focusedSection, module: "speaking", field: "generating", value: "video" } })
        }

        generateVideos(
            section as InteractiveSpeakingExercise | SpeakingExercise,
            level ? section.sectionId! : focusedSection,
            selectedAvatar,
            speakingAvatars
        ).then((results) => {
            switch (level ? section.sectionId! : focusedSection) {
                case 1:
                case 3: {
                    const interactiveSection = section as InteractiveSpeakingExercise;
                    const updatedPrompts = interactiveSection.prompts.map((prompt, index) => ({
                        ...prompt,
                        video_url: results[index].url || ''
                    }));
                    if (level) {
                        dispatch({
                            type: "UPDATE_SECTION_SINGLE_FIELD", payload: {
                                sectionId, field: "levelGenResults", value: [...state!.levelGenResults,
                                { generating: `${id ? `${id}-` : ''}video`, result: [{ prompts: updatedPrompts }] }], module: "level"
                            }
                        })
                    } else {
                        dispatch({
                            type: "UPDATE_SECTION_SINGLE_FIELD", payload: {
                                sectionId: focusedSection, module: "speaking", field: "genResult", value:
                                    { generating: "video", result: [{ prompts: updatedPrompts }], module: module }
                            }
                        })
                    }
                    break;
                }
                case 2: {
                    if (results[0]?.url) {
                        if (level) {
                            dispatch({
                                type: "UPDATE_SECTION_SINGLE_FIELD", payload: {
                                    sectionId, field: "levelGenResults", value: [...state!.levelGenResults,
                                    { generating: `${id ? `${id}-` : ''}video`, result: [{ video_url: results[0].url }] }], module: "level"
                                }
                            })
                        } else {
                            dispatch({
                                type: "UPDATE_SECTION_SINGLE_FIELD", payload: {
                                    sectionId: focusedSection, module, field: "genResult", value:
                                        { generating: 'video', result: [{ video_url: results[0].url }], module: "speaking" }
                                }
                            })
                        }
                    }
                    break;
                }
            }
        }).catch((error) => {
            toast.error("Failed to generate the video, try again later!")
        });
        
    }, [level, section, focusedSection, selectedAvatar, speakingAvatars, dispatch, module, state, id]);

    const secId = level ? section.sectionId! : focusedSection;

    return (
        <>
            <Dropdown
                title="Generate Script"
                module="speaking"
                open={localSettings.isSpeakingTopicOpen}
                setIsOpen={(isOpen: boolean) => updateLocalAndScheduleGlobal({ isSpeakingTopicOpen: isOpen }, false)}
                contentWrapperClassName={level ? `border border-ielts-speaking` : ''}
            >

                <div className="gap-4 px-2 pb-4 flex flex-col w-full">
                    <div className="flex flex-col flex-grow gap-4 px-2">
                        <label className="font-normal text-base text-mti-gray-dim">{`${secId === 1 ? "First Topic" : "Topic"}`} (Optional)</label>
                        <Input
                            key={`section-${secId}`}
                            type="text"
                            placeholder="Topic"
                            name="category"
                            onChange={onTopicChange}
                            roundness="xl"
                            value={localSettings.speakingTopic}
                            thin
                        />
                    </div>
                    {secId === 1 &&
                        <div className="flex flex-col flex-grow gap-4 px-2">
                            <label className="font-normal text-base text-mti-gray-dim">Second Topic (Optional)</label>
                            <Input
                                key={`section-${secId}`}
                                type="text"
                                placeholder="Topic"
                                name="category"
                                onChange={onSecondTopicChange}
                                roundness="xl"
                                value={localSettings.speakingSecondTopic}
                                thin
                            />
                        </div>
                    }
                    <div className="flex flex-col gap-2 px-2">
                        <label className="block font-normal text-base text-mti-gray-dim mb-2">Difficulty (Optional)</label>
                        <ReactSelect
                            options={difficultyOptions}
                            value={difficultyOptions.find(opt => opt.value === specificDiff)}
                            onChange={(value) => setSpecificDiff(value!.value as Difficulty)}
                            menuPortalTarget={document?.body}
                            components={{
                                IndicatorSeparator: null,
                                ValueContainer: ({ children, ...props }) => (
                                    <components.ValueContainer {...props}>
                                        <div className="flex flex-row gap-2 items-center pl-4">
                                            <MdSignalCellularAlt size={14} className="text-gray-600" />
                                            {children}
                                        </div>
                                    </components.ValueContainer>
                                )
                            }}
                            styles={{
                                menuPortal: (base) => ({ ...base, zIndex: 9999 }),
                                control: (styles) => ({
                                    ...styles,
                                    minHeight: '50px',
                                    border: '1px solid #e5e7eb',
                                    borderRadius: '0.5rem',
                                    boxShadow: 'none',
                                    backgroundColor: 'white',
                                    cursor: 'pointer',
                                    '&:hover': {
                                        border: '1px solid #e5e7eb',
                                    }
                                }),
                                valueContainer: (styles) => ({
                                    ...styles,
                                    padding: '0 8px',
                                    display: 'flex',
                                    alignItems: 'center'
                                }),
                                input: (styles) => ({
                                    ...styles,
                                    margin: '0',
                                    padding: '0'
                                }),
                                dropdownIndicator: (styles) => ({
                                    ...styles,
                                    padding: '8px'
                                }),
                                option: (styles, state) => ({
                                    ...styles,
                                    backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white",
                                    color: state.isFocused ? "black" : styles.color,
                                }),
                            }}
                            className="text-sm"
                        />
                    </div>
                    <div className="flex h-16 mb-1 justify-center mt-4">
                        <GenerateBtn
                            module="speaking"
                            genType={`${id ? `${id}-` : ''}speakingScript`}
                            sectionId={focusedSection}
                            generateFnc={generateScript}
                            level={level}
                        />
                    </div>
                </div>
            </Dropdown>
            <Dropdown
                title="Generate Video"
                module="speaking"
                open={localSettings.isGenerateVideoOpen}
                disabled={!canGenerate}
                setIsOpen={(isOpen: boolean) => updateLocalAndScheduleGlobal({ isGenerateVideoOpen: isOpen }, false)}
                contentWrapperClassName={level ? `border border-ielts-speaking` : ''}
            >
                <div className={clsx("flex items-center justify-between gap-4 px-2 pb-4")}>
                    <div className="relative flex-1 max-w-xs">
                        <select
                            value={selectedAvatar ? `${selectedAvatar.name}-${selectedAvatar.gender}` : ""}
                            onChange={(e) => {
                                if (e.target.value === "") {
                                    setSelectedAvatar(null);
                                } else {
                                    const [name, gender] = e.target.value.split("-");
                                    const avatar = speakingAvatars.find(a => a.name === name && a.gender === gender);
                                    if (avatar) setSelectedAvatar(avatar);
                                }
                            }}
                            className="w-full appearance-none px-4 py-2 border border-gray-200 rounded-full text-base bg-white focus:ring-1 focus:ring-blue-500 focus:outline-none"
                        >
                            <option value="">Select an avatar (Optional)</option>
                            {speakingAvatars.map((avatar) => (
                                <option
                                    key={`${avatar.name}-${avatar.gender}`}
                                    value={`${avatar.name}-${avatar.gender}`}
                                >
                                    {avatar.name}
                                </option>
                            ))}
                        </select>
                        <div className="absolute right-2.5 top-2.5 pointer-events-none">
                            {selectedAvatar && (
                                selectedAvatar.gender === 'male' ? (
                                    <FaMale className="w-5 h-5 text-blue-500" />
                                ) : (
                                    <FaFemale className="w-5 h-5 text-pink-500" />
                                )
                            )}
                        </div>
                    </div>

                    <GenerateBtn
                        module="speaking"
                        genType={`${id ? `${id}-` : ''}video`}
                        sectionId={focusedSection}
                        generateFnc={generateVideoCallback}
                        level={level}
                    />
                </div>
            </Dropdown>
        </>
    );
};

export default SpeakingComponents;
