import React, {useCallback, useEffect, useMemo, useRef} from 'react';
import {
  FlatList,
  Keyboard,
  ListRenderItem,
  ScrollViewProps,
  View,
} from 'react-native';
import {useTranslation} from 'react-i18next';
import {
  NavigationAction,
  useNavigation,
  usePreventRemove,
} from '@react-navigation/native';
import {FieldErrors, FormProvider} from 'react-hook-form';
import {useMutation} from '@tanstack/react-query';
import {KeyboardAwareScrollView} from 'react-native-keyboard-controller';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {
  Typography,
  Dialog,
  Alert,
  BottomModalFooter,
  BackButton,
  CloseButton,
} from '@components';
import {useModalHandler} from '@hooks/useModalHandler';
import {Question} from '@interfaces/questions';
import {FormAttributes} from '@modules/form/interfaces';
import {useLegacyForms} from '@modules/surveys/hooks/useLegacyForms';
import {createForm} from '@modules/surveys/services';
import {FormChattable} from '@modules/chat/interfaces';
import {showSnackbar} from '@redux/dispatchers';
import {FILE_ERROR_PREFIX} from '@services/attachments';
import {useTheme} from '@shared/theme';
import {DynamicFormValues, hasRequiredFieldError} from '@shared/dynamicForms';
import {commonStyles} from '@shared/styles';

import FormInput, {HIDE_REQUIRED_LABEL_INPUT_TYPES} from '../FormInput';
import {styles} from './styles';

interface Props {
  form: FormAttributes;
  onSuccess?: (props: FormChattable) => void;
  isCompleted?: boolean;
  renderHeaderRight?: () => React.ReactNode;
}

const keyExtractor = (item: Question) => `${item.id}`;

const renderScrollComponent = (props: ScrollViewProps) => (
  <KeyboardAwareScrollView {...props} keyboardShouldPersistTaps="handled" />
);

function FormContainer({
  form,
  onSuccess,
  isCompleted = false,
  renderHeaderRight,
}: Props) {
  const {theme} = useTheme();
  const navigation = useNavigation();
  const canExit = useRef(false);
  const {t} = useTranslation();
  const flatlistRef = useRef<FlatList>(null);
  const exitAction = useRef<Nullable<NavigationAction>>(null);
  const {top: paddingTop} = useSafeAreaInsets();

  const {
    isVisible: isWarningVisible,
    onCloseModal: onCloseWarning,
    onOpenModal: onOpenWarning,
  } = useModalHandler();

  const {
    mutate: createFormMutation,
    isPending: isCreatingForm,
    isSuccess: isCreateFormSuccess,
  } = useMutation({
    mutationFn: createForm,
    onSuccess: data => {
      onSuccess?.(data);
      canExit.current = true;
    },
  });

  const onStepChange = useCallback(() => {
    flatlistRef.current?.scrollToOffset({animated: true, offset: 0});
  }, []);

  const {onPressContinue, onPressBack, ...formMethods} = useLegacyForms({
    form,
    createFormMutation,
    onStepChange,
  });

  const isUploading = !!formMethods.formState.errors[FILE_ERROR_PREFIX];
  const isFirstSection = form.steps[0].id === formMethods.extra.currentStep.id;
  const isLastSection =
    form.steps[form.steps.length - 1].id === formMethods.extra.currentStep.id;
  const canLeaveForm =
    isFirstSection &&
    !formMethods.extra.isDirty &&
    !formMethods.extra.isCurrentStepAnswered;
  const allowExit = canLeaveForm || canExit.current || isCompleted;
  const showFooter = !isLastSection || !isCompleted;

  usePreventRemove(!allowExit, ({data}) => {
    Keyboard.dismiss();
    exitAction.current = data.action;
    onOpenWarning();
  });

  const onExitWarning = useCallback(() => {
    onCloseWarning();
    if (exitAction.current) {
      navigation.dispatch(exitAction.current);
      return;
    }
    navigation.goBack();
  }, [navigation, onCloseWarning]);

  const {
    formState: {errors},
    handleSubmit,
    extra: {currentStep},
  } = formMethods;

  const onInvalidForm = useCallback(
    (fieldErrors: FieldErrors<Record<string, unknown>>) => {
      if (!currentStep) {
        return;
      }
      const firstErrorKey = Object.keys(fieldErrors)[0];
      const {questions} = currentStep;

      if (!firstErrorKey || !questions) {
        return;
      }

      const firstErrorIndex = questions.findIndex(
        component => component.id.toString() === firstErrorKey,
      );

      if (
        firstErrorIndex !== -1 &&
        hasRequiredFieldError(fieldErrors as FieldErrors<DynamicFormValues>)
      ) {
        flatlistRef.current?.scrollToIndex({
          index: firstErrorIndex,
          animated: true,
        });
      }
    },
    [currentStep],
  );

  useEffect(() => {
    navigation.setOptions({
      gestureEnabled: allowExit,
      headerBackButtonMenuEnabled: false,
    });
  }, [allowExit, navigation]);

  useEffect(() => {
    const {requiredErrorsCount, otherErrorsCount} = Object.keys(errors).reduce(
      (acc, key) => {
        // Forms erros should not be empty, so we can ignore them
        if (!errors[key]?.message) {
          return acc;
        }
        const message = errors[key]?.message;
        const isRequiredError =
          message === t('service_management.required_error') ||
          message === t('service_management.required_error_file');
        if (isRequiredError) {
          acc.requiredErrorsCount++;
        } else {
          acc.otherErrorsCount++;
        }
        return acc;
      },
      {requiredErrorsCount: 0, otherErrorsCount: 0},
    );

    requiredErrorsCount &&
      showSnackbar({
        title: t('service_management.required_fields_helper_text', {
          count: requiredErrorsCount,
        }),
        description: t(
          requiredErrorsCount > 1
            ? 'service_management.incomplete_fields_helper_text'
            : 'service_management.single_incomplete_fields_helper_text',
        ),
        variant: 'error',
      });

    otherErrorsCount &&
      showSnackbar({
        title: t('surveys.invalid_fields_title', {
          count: otherErrorsCount,
        }),
        description: t(
          otherErrorsCount > 1
            ? 'surveys.invalid_fields_description'
            : 'surveys.single_invalid_fields_description',
        ),
        variant: 'error',
      });
  }, [errors, t]);

  const stepHasRequired = useMemo(
    () =>
      !!currentStep?.questions?.some(
        q =>
          q.required && !HIDE_REQUIRED_LABEL_INPUT_TYPES.includes(q.inputType),
      ),
    [currentStep],
  );

  const renderItem: ListRenderItem<Question> = useCallback(
    ({item}) => (
      <FormInput
        question={item}
        isCompleted={isCompleted}
        stepHasRequired={stepHasRequired}
      />
    ),
    [isCompleted, stepHasRequired],
  );

  const commonContainerStyle = useMemo(
    () => [
      styles.commonContainer,
      {backgroundColor: theme.background.layout.tertiary},
    ],
    [theme.background.layout.tertiary],
  );

  return (
    <View style={commonStyles.flex}>
      <View
        style={[
          styles.headerContainer,
          {
            paddingTop,
            backgroundColor: theme.background.layout.tertiary,
            borderBottomColor: theme.border.neutral.default,
          },
        ]}>
        <View style={styles.leftButtonContainer}>
          {!isFirstSection && <BackButton onPress={onPressBack} />}
        </View>
        <View
          pointerEvents="none"
          style={[
            styles.titleContainer,
            {
              top: paddingTop,
            },
          ]}>
          <Typography
            weight="semiBold"
            adjustsFontSizeToFit
            numberOfLines={2}
            align="center"
            style={styles.titleText}>
            {form.title}
          </Typography>
        </View>
        <View style={styles.rightButtonContainer}>
          {renderHeaderRight ? (
            renderHeaderRight()
          ) : (
            <CloseButton onPress={navigation.goBack} />
          )}
        </View>
      </View>
      <FormProvider {...formMethods}>
        <FlatList
          ref={flatlistRef}
          renderScrollComponent={renderScrollComponent}
          showsVerticalScrollIndicator={false}
          removeClippedSubviews={false}
          ListHeaderComponent={
            <>
              <View style={[commonContainerStyle, styles.sectionHeader]}>
                {form.isAnonymous && (
                  <Alert
                    title={t('surveys.anonymous_banner_title')}
                    description={t('surveys.anonymous_banner_description')}
                    withIcon={false}
                    variant="highLight"
                  />
                )}
                <View>
                  {currentStep?.title && (
                    <Typography variant="m" weight="semiBold">
                      {currentStep.title}
                    </Typography>
                  )}
                  {!!currentStep?.description?.trim() && (
                    <Typography variant="xs" color={theme.text.neutral.lighter}>
                      {currentStep.description}
                    </Typography>
                  )}
                  {stepHasRequired && (
                    <Typography variant="xs" color={theme.text.neutral.lighter}>
                      {t('service_management.required_field_disclaimer')}
                    </Typography>
                  )}
                </View>
              </View>
            </>
          }
          data={currentStep?.questions}
          renderItem={renderItem}
          keyExtractor={keyExtractor}
          style={{backgroundColor: theme.background.layout.default}}
          contentContainerStyle={styles.flatListContent}
        />
        {showFooter ? (
          <BottomModalFooter
            footer={{
              primaryButton: {
                onPress: handleSubmit(onPressContinue, onInvalidForm),
                text: isLastSection
                  ? t('general.finish')
                  : t('general.continue'),
                disabled: isUploading,
                isLoading: isCreatingForm || isCreateFormSuccess,
              },
            }}
          />
        ) : null}
      </FormProvider>
      <Dialog
        title={t('service_management.close_form_title')}
        isVisible={isWarningVisible}
        onClose={onCloseWarning}
        footer={{
          primaryButton: {
            onPress: onCloseWarning,
            text: t('service_management.continue_form'),
          },
          secondaryButton: {
            onPress: onExitWarning,
            text: t('general.exit'),
          },
        }}>
        <Typography
          variant="xs"
          align="center"
          color={theme.text.neutral.lighter}>
          {t('service_management.close_form_description')}
        </Typography>
      </Dialog>
    </View>
  );
}

export default FormContainer;
