import React, { type ReactNode, useContext, useEffect, useState } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';

import { useModal } from '@material-hu/hooks/useModal';

import Dialog from '@material-hu/components/design-system/Dialog';

import { addIfNotPresent, addOrRemove } from 'src/utils/arrayUtils';
import { useLokaliseTranslation } from 'src/utils/i18n';

import {
  type QuestionType,
  type Section,
  type Selected,
  type SelectionQuestion,
} from '../../types';
import { duplicateSectionAndQuestions, isChoiceQuestion } from '../../utils';
import {
  defaultQuestionValues,
  defaultSectionValues,
  NEXT_SECTION_ID,
} from '../constants';
import { newServiceItemFields } from '../forms';

type Modal = {
  showModal: (props?: Partial<unknown>) => void;
  closeModal: () => void;
  modal: JSX.Element | ReactNode;
};

type FormCreationContextType = {
  selected: Selected;
  expanded: string[];
  openSideMenu: boolean;
  toggleSideMenu: (value: boolean) => void;
  select: (newSelected: Selected) => void;
  expand: (expandOrCollpaseSectionId: string) => void;
  createSection: () => void;
  duplicateSection: (section: number) => void;
  deleteSection: (section: number) => void;
  deleteSectionModal: Modal;
  createQuestion: (section: number, questionType: QuestionType) => void;
  deleteQuestion: (section: number, question: number) => void;
  duplicateQuestion: (section: number, question: number) => void;
  deleteQuestionModal: Modal;
  createQuestionChoice: (
    section: number,
    question: number,
    title?: string,
  ) => void;
  deleteQuestionChoice: (
    section: number,
    question: number,
    choice: number,
  ) => void;
};

const FormCreationContext = React.createContext<FormCreationContextType | null>(
  null,
);

export const useFormCreation = () => {
  return useContext(FormCreationContext) as FormCreationContextType;
};

const FormCreationProvider = ({ children }: { children: JSX.Element }) => {
  const { t } = useLokaliseTranslation(['service_management', 'general']);
  const [openSideMenu, setOpenSideMenu] = useState<boolean>(false);
  const [questionToDelete, setQuestionToDelete] = useState<Selected | null>(
    null,
  );
  const [sectionToDelete, setSectionToDelete] = useState<number | null>(null);

  const { getValues, setValue, control } = useFormContext();
  const sectionsName = newServiceItemFields.form.sections.all();

  const sections = useFieldArray({
    control,
    name: sectionsName,
  });

  const getLast = (section: number = -1) => {
    const newList =
      section < 0
        ? getValues(sectionsName)
        : getValues(newServiceItemFields.form.sections.questions.all(section));

    return {
      last: newList[newList.length - 1],
      index: newList.length - 1,
    };
  };

  const [expanded, setExpanded] = useState<string[]>(
    getLast().last ? [getLast().last.id] : [],
  );

  const [selected, setSelected] = useState<Selected>({
    section: getLast().index,
    question: -1,
  });

  const {
    showModal: showConfirmDeleteSectionModal,
    modal: confirmDeleteSectionModal,
    closeModal: closeConfirmDeleteSectionModal,
  } = useModal(() => (
    <Dialog
      title={t('confirm_delete_section_title')}
      textBody={t('confirm_delete_section_description')}
      onClose={closeConfirmDeleteSectionModal}
      primaryButtonProps={{
        variant: 'primary',
        children: t('yes_delete'),
        onClick: confirmDeleteSection,
      }}
      secondaryButtonProps={{
        variant: 'tertiary',
        children: t('general:cancel'),
        onClick: closeConfirmDeleteSectionModal,
      }}
    />
  ));

  const {
    showModal: showConfirmDeleteQuestionModal,
    modal: confirmDeleteQuestionModal,
    closeModal: closeConfirmDeleteQuestionModal,
  } = useModal(() => (
    <Dialog
      title={t('confirm_delete_question_title')}
      textBody={t('confirm_delete_question_description')}
      onClose={closeConfirmDeleteQuestionModal}
      primaryButtonProps={{
        variant: 'primary',
        children: t('yes_delete'),
        onClick: confirmDeleteQuestion,
      }}
      secondaryButtonProps={{
        variant: 'tertiary',
        children: t('general:cancel'),
        onClick: closeConfirmDeleteQuestionModal,
      }}
    />
  ));

  const createQuestion = (section: number, questionType: QuestionType) => {
    const questionsName =
      newServiceItemFields.form.sections.questions.all(section);

    const newQuestions = [...getValues(questionsName)];
    newQuestions.push({
      id: crypto.randomUUID(),
      type: questionType,
      ...defaultQuestionValues,
    });

    setValue(questionsName, newQuestions);

    const newSections = getValues(sectionsName);
    const sectionObj = newSections[section];

    if (sectionObj && !expanded.includes(sectionObj.id)) {
      expand(sectionObj.id);
    }

    select({ section, question: getLast(section).index });
  };

  const confirmDeleteQuestion = () => {
    if (!questionToDelete) {
      return;
    }
    const { section, question } = questionToDelete;
    const questionsName =
      newServiceItemFields.form.sections.questions.all(section);

    const newQuestions = [...getValues(questionsName)];
    newQuestions.splice(question, 1);

    setValue(questionsName, newQuestions);

    if (selected.question === question) {
      select({ section, question: getLast(section).index });
    } else if (selected.question > question) {
      select({ section, question: selected.question - 1 });
    }
    setQuestionToDelete(null);
    setOpenSideMenu(false);
    closeConfirmDeleteQuestionModal();
  };

  const duplicateSection = (section: number) => {
    const newSections = [...getValues(sectionsName)];

    const clonedSection = duplicateSectionAndQuestions(newSections[section]);

    newSections.splice(section + 1, 0, clonedSection);

    setValue(sectionsName, newSections);

    select({ section: section + 1, question: -1 });
  };

  const duplicateQuestion = (section: number, question: number) => {
    const questionsName =
      newServiceItemFields.form.sections.questions.all(section);

    const newQuestions = [...getValues(questionsName)];

    const newQuestion = {
      ...newQuestions[question],
      id: crypto.randomUUID(),
    };

    newQuestions.splice(question + 1, 0, newQuestion);

    setValue(questionsName, newQuestions);

    select({ section, question: question + 1 });
  };

  const createSection = () => {
    sections.append({
      id: crypto.randomUUID(),
      title: t('empty_section_title'),
      goToOnFinish: NEXT_SECTION_ID,
      ...defaultSectionValues,
    });
    select({ section: getLast().index, question: -1 });
  };

  const deleteSection = (section: number) => {
    setSectionToDelete(section);
    showConfirmDeleteSectionModal();
  };

  const confirmDeleteSection = () => {
    if (sectionToDelete == null || sections.fields.length === 1) {
      return;
    }
    const newSections: Section[] = [...getValues(sectionsName)];

    const [deleted] = newSections.splice(sectionToDelete, 1);

    // Go through all the sections and choices and remove jumps to deleted section
    newSections.forEach(section => {
      if (section.goToOnFinish === deleted.id) {
        section.goToOnFinish = NEXT_SECTION_ID;
      }

      section.questions.forEach(question => {
        if (isChoiceQuestion(question.type)) {
          const selectionQuestion = question as SelectionQuestion;

          if (selectionQuestion.choices) {
            selectionQuestion.choices.forEach(choice => {
              if (choice.sectionIfChosen === deleted.id) {
                choice.sectionIfChosen = NEXT_SECTION_ID;
              }
            });
          }
        }
      });
    });

    sections.replace(newSections);

    setExpanded(expanded.filter(id => id !== deleted.id));
    select({ section: getLast().index, question: -1 });
    setSectionToDelete(null);
    closeConfirmDeleteSectionModal();
  };

  // biome-ignore lint/correctness/useExhaustiveDependencies: selected is read but must not trigger re-sync to avoid undoing optimistic deletes
  useEffect(() => {
    if (openSideMenu) {
      if (selected.question === -1) {
        setOpenSideMenu(false);
      }
    }
  }, [selected]);

  const select = (newSelected: Selected) => {
    setSelected(newSelected);
    const sectionIdToExpand = getValues(sectionsName)[newSelected.section]?.id;
    setExpanded(addIfNotPresent(expanded, sectionIdToExpand));
  };

  const expand = (expandOrCollpaseSectionId: string) =>
    setExpanded(addOrRemove(expanded, expandOrCollpaseSectionId));

  const toggleSideMenu = (newOpen: boolean) => setOpenSideMenu(newOpen);

  const deleteQuestion = (section: number, question: number) => {
    setQuestionToDelete({ section, question });
    showConfirmDeleteQuestionModal();
  };

  const deleteQuestionModal: Modal = {
    showModal: showConfirmDeleteQuestionModal,
    closeModal: closeConfirmDeleteQuestionModal,
    modal: confirmDeleteQuestionModal,
  };

  const deleteSectionModal: Modal = {
    showModal: showConfirmDeleteSectionModal,
    closeModal: closeConfirmDeleteSectionModal,
    modal: confirmDeleteSectionModal,
  };

  const createQuestionChoice = (
    section: number,
    question: number,
    title?: string,
  ) => {
    const choicesName =
      newServiceItemFields.form.sections.questions.choices.all(
        section,
        question,
      );

    const newChoices = [...getValues(choicesName)];
    newChoices.push({
      id: crypto.randomUUID(),
      title: title ?? '',
      sectionIfChosen: NEXT_SECTION_ID,
    });

    setValue(choicesName, newChoices);
  };

  const deleteQuestionChoice = (
    section: number,
    question: number,
    choice: number,
  ) => {
    const choicesName =
      newServiceItemFields.form.sections.questions.choices.all(
        section,
        question,
      );

    const newChoices = [...getValues(choicesName)];
    newChoices.splice(choice, 1);

    setValue(choicesName, newChoices);
  };

  return (
    <FormCreationContext.Provider
      value={{
        selected,
        expanded,
        openSideMenu,
        toggleSideMenu,
        createSection,
        deleteSection,
        duplicateSection,
        deleteSectionModal,
        createQuestion,
        deleteQuestion,
        duplicateQuestion,
        select,
        expand,
        deleteQuestionModal,
        deleteQuestionChoice,
        createQuestionChoice,
      }}
    >
      {children}
    </FormCreationContext.Provider>
  );
};

export default FormCreationProvider;
