import { useEffect, useMemo, useState } from 'react';
import { useMutation, useQueryClient } from 'react-query';

import { debounce, isEqual } from 'lodash-es';
import Stack from '@material-hu/mui/Stack';

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

import useAuth from 'src/contexts/JWTContext';
import { pxKeys } from 'src/pages/dashboard/PeopleExperience/queries';
import { updateSurveyQuestions as updateQuestionsService } from 'src/pages/dashboard/PeopleExperience/services';
import { getTemporalId } from 'src/pages/dashboard/PeopleExperience/utils';
import {
  QuestionTypes,
  type TransformedQuestion,
} from 'src/types/peopleExperience';
import { useLokaliseTranslation } from 'src/utils/i18n';

import StepLayout from '../StepLayout';

import QuestionBuilderDrawer from '../../../QuestionsBankList/components/QuestionBuilderDrawer';

import { PreviewType } from 'src/pages/dashboard/PeopleExperience/types';

import { QuestionBank, QuestionsList } from './components';
import EnpsSwitcher from './components/EnpsSwitcher';
import { type FilledQuestionFormValues } from 'src/pages/dashboard/PeopleExperience/QuestionsBankList/forms/QuestionBuilderForm/types';
import { type QuestionsStepProps } from './types';
import {
  getQuestionCopy,
  parseQuestion,
  serializeQuestions,
} from '../../../utils/questionsUtils';

const QuestionsStep = ({
  onNext,
  onBack,
  questions: serverQuestions = [],
  surveyId,
  templateId,
  hasEnpsQuestion,
}: QuestionsStepProps) => {
  const { instance } = useAuth();
  const { enqueueSnackbar } = useHuSnackbar();
  const { t } = useLokaliseTranslation('people_experience');
  const queryClient = useQueryClient();
  const [syncPending, setSyncPending] = useState(false);
  const [enabledEnps, setEnabledEnps] = useState(hasEnpsQuestion);

  const [questions, setQuestions] =
    useState<TransformedQuestion[]>(serverQuestions);

  const [formOpen, setFormOpen] = useState(false);

  const [editingQuestion, setEditingQuestion] =
    useState<TransformedQuestion | null>(null);

  const [previewType, setPreviewType] = useState<PreviewType | null>(null);

  const { mutate: updateQuestions, isLoading: isUpdatingQuestions } =
    useMutation({
      mutationFn: () =>
        updateQuestionsService({
          surveyId,
          templateId,
          questions: serializeQuestions(questions),
        }),
      onSuccess: ({ data }) => {
        queryClient.invalidateQueries(pxKeys.surveyDetail(surveyId));
        setQuestions(
          data.formTemplate?.questionTemplates.map(item =>
            parseQuestion({ question: item, t }),
          )!,
        );
      },
      onError: () => {
        enqueueSnackbar({
          title: t('question.questions_save_error'),
          variant: 'error',
        });
        setQuestions(serverQuestions);
      },
      onSettled: () => {
        setSyncPending(false);
      },
    });

  const debouncedPersist = useMemo(() => debounce(updateQuestions, 2000), []);

  const yieldQuestions: React.Dispatch<
    React.SetStateAction<TransformedQuestion[]>
  > = (...args) => {
    setSyncPending(true);
    setQuestions(...args);
  };

  useEffect(() => {
    if (isEqual(serverQuestions, questions) || !syncPending) {
      return;
    }

    if (syncPending) {
      debouncedPersist();
    }
  }, [questions, serverQuestions, debouncedPersist, syncPending]);

  useEffect(() => {
    return () => {
      debouncedPersist.cancel();
    };
  }, [debouncedPersist]);

  const handleSort = (sortedItems: TransformedQuestion[]) => {
    yieldQuestions(sortedItems);
  };

  const handleCopy = (id: TransformedQuestion['id']) => {
    yieldQuestions(prev => {
      const questionIndex = prev.findIndex(item => item.id === id);
      if (questionIndex === -1) return prev;

      const questionToCopy = prev[questionIndex];
      const newQuestion = getQuestionCopy(t, {
        ...questionToCopy,
        isQuestionBank: false,
      });

      const newQuestions = [...prev];
      newQuestions.splice(questionIndex + 1, 0, newQuestion);
      return newQuestions;
    });

    enqueueSnackbar({
      title: t('question.copied_success'),
      variant: 'info',
    });
  };

  const handleOpenQuestionForm = () => {
    setFormOpen(true);
  };

  const handleCloseQuestionForm = () => {
    setFormOpen(false);
    setEditingQuestion(null);
    setPreviewType(null);
  };

  const handlePreview =
    (type: PreviewType) => (question: TransformedQuestion) => {
      setEditingQuestion(question);
      setPreviewType(type);
      setFormOpen(true);
    };

  const handleEdit = (question: TransformedQuestion) => {
    setEditingQuestion(question);
    if (question.type.value === QuestionTypes.NPS) {
      setPreviewType(PreviewType.NPS_QUESTION);
    }
    setFormOpen(true);
  };

  const deleteQuestion = (id: TransformedQuestion['id']) => {
    yieldQuestions(prev => prev.filter(item => item.id !== id));
  };

  const handleDelete = ({ id, type }: TransformedQuestion) => {
    deleteQuestion(id);

    if (type.value === QuestionTypes.NPS) {
      setEnabledEnps(false);
    }
  };

  const handleAppend = (
    question: TransformedQuestion | TransformedQuestion[],
  ) => {
    yieldQuestions(prev => [
      ...prev,
      ...(Array.isArray(question) ? question : [question]),
    ]);
  };

  const handlePrepend = (
    question: TransformedQuestion | TransformedQuestion[],
  ) => {
    yieldQuestions(prev => [
      ...(Array.isArray(question) ? question : [question]),
      ...prev,
    ]);
  };

  const handleUpdate = (
    questionId: TransformedQuestion['id'],
    payload: Partial<FilledQuestionFormValues>,
  ) => {
    yieldQuestions(prev =>
      prev.map(item =>
        item.id === questionId
          ? {
              ...item,
              ...payload,
            }
          : item,
      ),
    );
  };

  const handleChangeStep = (callback?: () => void) => () => {
    if (!isEqual(serverQuestions, questions)) {
      updateQuestions(undefined, {
        onSuccess: callback,
      });
    } else {
      callback?.();
    }
  };

  useEffect(() => {
    if (enabledEnps) {
      if (!questions.some(item => item.type.value === QuestionTypes.NPS)) {
        if (hasEnpsQuestion) {
          handlePrepend(
            serverQuestions.find(
              item => item.type.value === QuestionTypes.NPS,
            )!,
          );
        } else {
          handlePrepend({
            id: getTemporalId(),
            type: {
              label: t('e_nps.title'),
              value: QuestionTypes.NPS,
            },
            statement: t('e_nps_question_title', {
              name: instance?.name,
            }),
            isQuestionBank: false,
            required: true,
            allowComments: false,
            topic: null,
            answerOptions: [],
            customScale: null,
          });
        }
      }
    } else {
      const enpsQuestion = questions.find(
        item => item.type.value === QuestionTypes.NPS,
      );
      if (enpsQuestion) {
        deleteQuestion(enpsQuestion.id);
      }
    }
  }, [enabledEnps]);

  return (
    <StepLayout
      onNext={handleChangeStep(onNext)}
      onBack={handleChangeStep(onBack)}
      slotProps={{
        submitButton: {
          loading: isUpdatingQuestions,
          disabled: questions.length === 0,
        },
        backButton: {
          disabled: isUpdatingQuestions,
        },
      }}
    >
      <Stack
        sx={{
          height: '100%',
          flexDirection: 'row',
          position: 'relative',
          minHeight: 0,
        }}
      >
        <Stack
          sx={{
            gap: 2,
            width: '100%',
            p: 4,
            alignItems: 'center',
            overflowY: 'auto',
          }}
        >
          <EnpsSwitcher
            checked={enabledEnps}
            onCheck={setEnabledEnps}
          />
          <QuestionsList
            questions={questions}
            onAddNew={handleOpenQuestionForm}
            onEdit={handleEdit}
            onPreview={handlePreview(PreviewType.QUESTION_LIST)}
            onDelete={handleDelete}
            onCopy={handleCopy}
            onSort={handleSort}
          />
        </Stack>
        <QuestionBank
          onAdd={handleAppend}
          onPreview={handlePreview(PreviewType.QUESTION_BANK)}
          formQuestions={questions}
          surveyId={surveyId}
        />
      </Stack>
      <QuestionBuilderDrawer
        open={formOpen}
        onClose={handleCloseQuestionForm}
        question={editingQuestion}
        previewType={previewType}
        onAdd={handleAppend}
        onUpdate={handleUpdate}
      />
    </StepLayout>
  );
};

export default QuestionsStep;
