import React, { useState, useMemo, useEffect, useCallback } from 'react';
import {
  MdAdd,
  MdVisibility,
  MdVisibilityOff
} from 'react-icons/md';
import { Difficulty, MatchSentencesExercise, ReadingPart } from '@/interfaces/exam';
import Alert, { AlertItem } from '../Shared/Alert';
import ReferenceViewer from './ParagraphViewer';
import Header from '../../Shared/Header';
import SortableQuestion from '../Shared/SortableQuestion';
import QuestionsList from '../Shared/QuestionsList';
import useExamEditorStore from '@/stores/examEditor';
import useSectionEdit from '../../Hooks/useSectionEdit';
import validateMatchSentences from './validation';
import setEditingAlert from '../Shared/setEditingAlert';
import { toast } from 'react-toastify';
import { DragEndEvent } from '@dnd-kit/core';
import { handleMatchSentencesReorder } from '@/stores/examEditor/reorder/local';
import PromptEdit from '../Shared/PromptEdit';
import { uuidv4 } from '@/utils/uuid';

const MatchSentences: React.FC<{ exercise: MatchSentencesExercise, sectionId: number }> = ({ exercise, sectionId }) => {
  const { currentModule, dispatch } = useExamEditorStore();
  const difficulty = useExamEditorStore((state) => state.modules[currentModule].difficulty);
  const { state } = useExamEditorStore(
    (state) => state.modules[currentModule].sections.find((section) => section.sectionId === sectionId)!
  );

  const section = state as ReadingPart;

  const [local, setLocal] = useState(exercise);
  const [selectedParagraph, setSelectedParagraph] = useState<string | null>(null);
  const [showReference, setShowReference] = useState(false);
  const [alerts, setAlerts] = useState<AlertItem[]>([]);

  const updateLocal = (exercise: MatchSentencesExercise) => {
    setLocal(exercise);
    setEditing(true);
  };

  const { editing, setEditing, handleSave, handleDiscard, handleDelete, handlePractice } = useSectionEdit({
    sectionId,
    onSave: () => {

      const isValid = validateMatchSentences(local.sentences, setAlerts);

      if (!isValid) {
        toast.error("Please fix the errors before saving!");
        return;
      }

      setEditing(false);
      setAlerts([]);

      const newState = { ...section };
      newState.exercises = newState.exercises.map((ex) => ex.id === exercise.id ? local : ex);
      dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
    },
    onDiscard: () => {
      setLocal(exercise);
      setSelectedParagraph(null);
      setShowReference(false);
    },
    onDelete: () => {
      const newSection = {
        ...section,
        exercises: section.exercises.filter((ex) => ex.id !== local.id)
      };
      dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: newSection, module: currentModule } });
    },
    onPractice: () => {
      const updatedExercise = {
        ...local,
        isPractice: !local.isPractice
      };
      const newState = { ...section };
      newState.exercises = newState.exercises.map((ex) =>
        ex.id === exercise.id ? updatedExercise : ex
      );
      setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
      dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
    }
  });

  const usedOptions = useMemo(() => {
    return local.sentences.reduce((acc, sentence) => {
      if (sentence.solution) {
        acc.add(sentence.solution);
      }
      return acc;
    }, new Set<string>());
  }, [local.sentences]);

  const addHeading = () => {
    const newId = (parseInt(local.sentences[local.sentences.length - 1].id) + 1).toString();
    updateLocal({
      ...local,
      sentences: [
        ...local.sentences,
        {
          uuid: uuidv4(),
          id: newId,
          sentence: "",
          solution: ""
        }
      ]
    });
  };

  const updateHeading = (index: number, field: string, value: string) => {
    const newSentences = [...local.sentences];

    if (field === 'solution') {
      const oldSolution = newSentences[index].solution;
      if (oldSolution) {
        usedOptions.delete(oldSolution);
      }
    }

    newSentences[index] = { ...newSentences[index], [field]: value };
    updateLocal({ ...local, sentences: newSentences });
  };

  const deleteHeading = (index: number) => {
    if (local.sentences.length <= 1) {
      toast.error(`There needs to be at least one ${exercise.variant && exercise.variant == "ideaMatch" ? "idea/opinion" : "heading"}!`);
      return;
    }

    const deletedSolution = local.sentences[index].solution;
    if (deletedSolution) {
      usedOptions.delete(deletedSolution);
    }

    const newSentences = local.sentences.filter((_, i) => i !== index);
    updateLocal({ ...local, sentences: newSentences });
  };

  useEffect(() => {
    validateMatchSentences(local.sentences, setAlerts);
  }, [local.sentences]);

  useEffect(() => {
    setEditingAlert(editing, setAlerts);
  }, [editing]);


  const handleDragEnd = (event: DragEndEvent) => {
    updateLocal(handleMatchSentencesReorder(event, local));
  }

  const saveDifficulty = useCallback((diff: Difficulty) => {
    if (!difficulty.includes(diff)) {
        dispatch({ type: 'UPDATE_MODULE', payload: { updates: { difficulty: [...difficulty, diff]} } });
    }
    const updatedExercise = { ...exercise, difficulty: diff };
    const newState = { ...section };
    newState.exercises = newState.exercises.map((ex) => ex.id === exercise.id ? updatedExercise : ex );
    dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
}, [currentModule, difficulty, dispatch, exercise, section, sectionId]);

  return (
    <div className="flex flex-col mx-auto p-2">
      <Header
        title={exercise.variant && exercise.variant == "ideaMatch" ? "Idea Match" : "Paragraph Match"}
        description={`Edit ${exercise.variant && exercise.variant == "ideaMatch" ? "ideas/opinions" : "headings"} and their matches`}
        editing={editing}
        difficulty={exercise.difficulty}
        saveDifficulty={saveDifficulty}
        handleSave={handleSave}
        handleDelete={handleDelete}
        handleDiscard={handleDiscard}
        handlePractice={handlePractice}
        isEvaluationEnabled={!local.isPractice}
      >
        <button
          onClick={() => setShowReference(!showReference)}
          className="px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors flex items-center gap-2"
        >
          {showReference ? <MdVisibilityOff size={18} /> : <MdVisibility size={18} />}
          {showReference ? 'Hide Reference' : 'Show Reference'}
        </button>
      </Header>

      <div className="space-y-4">
        {alerts.length > 0 && <Alert alerts={alerts} />}
        <PromptEdit
          value={local.prompt}
          onChange={(text) => updateLocal({ ...local, prompt: text })}
        />
        <QuestionsList
          ids={local.sentences.map(s => s.id)}
          handleDragEnd={handleDragEnd}
        >
          {local.sentences.map((sentence, index) => (
            <SortableQuestion
              key={sentence.id}
              id={sentence.id}
              index={index}
              deleteQuestion={() => deleteHeading(index)}
              onFocus={() => setSelectedParagraph(sentence.solution)}
            >
              <>
                <input
                  type="text"
                  value={sentence.sentence}
                  onChange={(e) => updateHeading(index, 'sentence', e.target.value)}
                  className="w-full p-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none text-mti-gray-dim"
                  placeholder={`Enter ${exercise.variant && exercise.variant == "ideaMatch" ? "idea/opinion" : "heading"} ...`}
                />
                <div className="flex items-center gap-3">
                  <select
                    value={sentence.solution}
                    onChange={(e) => {
                      updateHeading(index, 'solution', e.target.value);
                      setSelectedParagraph(e.target.value);
                    }}
                    className="w-full p-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none bg-white text-mti-gray-dim"
                  >
                    <option value="">Select matching {exercise.variant == "ideaMatch" ? "author" : "paragraph"}...</option>
                    {local.options.map((option) => {
                      const isUsed = usedOptions.has(option.id);
                      const isCurrentSelection = sentence.solution === option.id;

                      return (
                        <option
                          key={option.id}
                          value={option.id}
                          disabled={isUsed && !isCurrentSelection}
                        >
                          {exercise.variant == "ideaMatch" ? "Author" : "Paragraph"} {option.id}
                        </option>
                      );
                    })}
                  </select>
                </div>
              </>
            </SortableQuestion>
          ))}
        </QuestionsList>
        {(section.text !== undefined && section.text.content.split("\n\n").length - 1) === local.sentences.length && (
          <button
            onClick={addHeading}
            className="w-full p-4 border-2 border-dashed border-gray-300 rounded-lg hover:border-blue-500 hover:bg-blue-50 transition-colors flex items-center justify-center gap-2 text-gray-600 hover:text-blue-600"
          >
            <MdAdd size={18} />
            Add New Match
          </button>
        )}
      </div>
      <ReferenceViewer
        headings={exercise.variant !== "ideaMatch"}
        showReference={showReference}
        selectedReference={selectedParagraph}
        options={local.options}
        setShowReference={setShowReference}
      />
    </div>
  );
};

export default MatchSentences;