import { Dispatch, SetStateAction, useEffect } from 'react';
import { FormProvider, useForm } from 'react-hook-form';

import Stack from '@material-hu/mui/Stack';
import { SxProps, useTheme } from '@material-hu/mui/styles';
import { typographyClasses } from '@material-hu/mui/Typography';

import HuAlert from '@material-hu/components/design-system/Alert';
import Button from '@material-hu/components/design-system/Buttons/Button';
import HuFormInputClassic from '@material-hu/components/design-system/Inputs/Classic/form';
import HuProgressBar from '@material-hu/components/design-system/ProgressIndicators/ProgressBar';
import HuTitle from '@material-hu/components/design-system/Title';
import {
  Question,
  ManagerSurvey,
  SurveyFormValues,
  QuestionType,
} from '../../types';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { CONTENT_WIDTH } from '../../constants';
import { getFormProgress, getInitAnswerValue } from '../../utils';
import QuestionField from '../QuestionField';

import {
  formResolver,
  toMultiChoiceFormData,
  toMultiChoiceServerData,
  toUniqChoiceFormData,
  toUniqChoiceServerData,
} from './utils';

type QuestionFormProps = {
  question: Question;
  questionIndex: number;
  questionsCount: number;
  sx?: SxProps;
  onChangeIndex: Dispatch<SetStateAction<number>>;
  surveyId: ManagerSurvey['id'];
  isLoading?: boolean;
  onSubmit: (formValues: SurveyFormValues) => void;
  onBackupAnswer: any;
};

const QuestionForm = ({
  question,
  sx,
  questionIndex,
  questionsCount,
  onChangeIndex,
  surveyId,
  isLoading,
  onSubmit,
  onBackupAnswer,
}: QuestionFormProps) => {
  const { title, isMandatory, type, allowComments, options } = question;
  const { t } = useLokaliseTranslation('people_experience');
  const theme = useTheme();
  const isMultiChoice = type === QuestionType.MULTI_CHOICE;
  const isUniqChoice = type === QuestionType.UNIQ_CHOICE;

  const form = useForm<SurveyFormValues>({
    mode: 'onSubmit',
    defaultValues: {
      answer: (() => {
        if (question.answer !== null) {
          if (isMultiChoice) {
            return toMultiChoiceFormData({
              value: question.answer as number[],
              optionsLength: options?.length,
            });
          }

          if (isUniqChoice) {
            return toUniqChoiceFormData({
              value: question.answer as number,
              optionsLength: options?.length,
            });
          }

          return question.answer;
        }

        return getInitAnswerValue(type, options?.length);
      })(),
      comment: question.comment ?? '',
    },
    resolver: isMandatory ? formResolver : undefined,
  });

  const { handleSubmit, formState, trigger, getValues, clearErrors, watch } =
    form;

  const { errors } = formState;

  const hasRequiredError = errors.answer?.type === 'required';
  const isFirstQuestion = questionIndex === 0;
  const isLastQuestion = questionIndex === questionsCount - 1;

  const formAnswerValue = watch('answer');

  const shoulClearSelectError =
    isUniqChoice || isMultiChoice
      ? (formAnswerValue as boolean[])?.some(Boolean)
      : false;

  useEffect(() => {
    if (shoulClearSelectError) {
      clearErrors('answer');
    }
  }, [shoulClearSelectError]);

  const parseValues = (values: SurveyFormValues) => {
    if (isMultiChoice) {
      return {
        ...values,
        answer: toMultiChoiceServerData(values.answer as boolean[]),
      };
    }

    if (isUniqChoice) {
      const answer = toUniqChoiceServerData(values.answer as boolean[]);
      return {
        ...values,
        answer: answer === -1 ? null : answer,
      };
    }

    return values;
  };

  const validateAnswer = (parsedValues: SurveyFormValues) => {
    if (
      isMultiChoice &&
      isMandatory &&
      !(parsedValues.answer as number[])?.length
    ) {
      form.setError('answer', {
        type: 'required',
      });
      return false;
    }

    if (isUniqChoice && isMandatory && (parsedValues.answer as number) === -1) {
      form.setError('answer', {
        type: 'required',
      });
      return false;
    }

    return true;
  };

  const handleNextQuestion = (values: SurveyFormValues) => {
    const parsedValues = parseValues(values);

    if (!validateAnswer(parsedValues)) {
      return;
    }

    if (isLastQuestion) {
      onSubmit(parsedValues);
      return;
    }

    onChangeIndex(prev => prev + 1);
    onBackupAnswer({
      questionId: question.id,
      surveyId,
      answer: parsedValues.answer,
      comment: parsedValues.comment,
    });
  };

  const handlePrevQuestion = async () => {
    const isValid = await trigger(); // Manually validate form
    const values = getValues();
    const parsedValues = parseValues(values);

    if (validateAnswer(parsedValues) && isValid) {
      onBackupAnswer({
        questionId: question.id,
        surveyId: Number(surveyId),
        answer: parsedValues.answer,
        comment: parsedValues.comment,
      });
    }

    onChangeIndex(prev => prev - 1);
  };

  const isLikertQuestion = [QuestionType.NPS, QuestionType.LIKERT].includes(
    type,
  );

  const questionTitleElement = (
    <HuTitle
      variant="S"
      title={title}
      description={isMandatory && `* ${t('MANDATORY_QUESTION')}`}
      sx={{
        [`& .${typographyClasses.root}`]: {
          color: hasRequiredError
            ? theme.palette.new.text.feedback.error
            : theme.palette.new.text.neutral.default,
        },
      }}
    />
  );

  return (
    <FormProvider {...form}>
      <Stack
        component="form"
        sx={{
          flex: 1,
          minHeight: 0,
          bgcolor: theme.palette.new.background.layout.default,
          alignItems: 'center',
          overflowY: 'auto',
          ...sx,
        }}
      >
        <Stack
          sx={{
            flex: 1,
            width: '100%',
            gap: 5,
            maxWidth: CONTENT_WIDTH,
            p: 2,
          }}
        >
          <HuProgressBar
            current={getFormProgress(questionIndex + 1, questionsCount)}
            variant="determinate"
            helper={t('QUESTION_PROGRESS', {
              index: questionIndex + 1,
              total: questionsCount,
            })}
          />
          {hasRequiredError && (
            <HuAlert
              severity="error"
              title={t('MANDATORY_QUESTION_ALERT')}
            />
          )}
          <Stack sx={{ gap: 4 }}>
            {!isLikertQuestion && questionTitleElement}
            <QuestionField
              type={type}
              name="answer"
              required={!!isMandatory}
              questionTitleElement={questionTitleElement}
              options={options ?? []}
            />
            {allowComments && type !== QuestionType.TEXT && (
              <HuFormInputClassic
                name="comment"
                inputProps={{
                  label: t('optional_comment'),
                  hasCounter: true,
                  multiline: true,
                  maxLength: 2500,
                  placeholder: t('general:write_something'),
                }}
              />
            )}
          </Stack>
        </Stack>
        <Stack
          sx={{
            bgcolor: theme.palette.new.background.layout.tertiary,
            width: '100%',
            alignItems: 'center',
            position: 'sticky',
            bottom: 0,
          }}
        >
          <Stack
            sx={{
              gap: 1.5,
              flexDirection: 'row',
              justifyContent: 'flex-end',
              width: '100%',
              maxWidth: CONTENT_WIDTH,
              py: 2,
            }}
          >
            {!isFirstQuestion && (
              <Button
                size="large"
                onClick={handlePrevQuestion}
              >
                {t('general:back')}
              </Button>
            )}
            <Button
              variant="primary"
              onClick={handleSubmit(handleNextQuestion)}
              loading={!!isLoading}
              size="large"
            >
              {t(isLastQuestion ? 'SEND' : 'CONTINUE')}
            </Button>
          </Stack>
        </Stack>
      </Stack>
    </FormProvider>
  );
};

export default QuestionForm;
