import React, {
  ForwardedRef,
  forwardRef,
  useCallback,
  useEffect,
  useRef,
  useState,
} from 'react';
import {FlatList, Keyboard, View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {useMutation} from '@tanstack/react-query';
import {FieldErrors, FieldValues, FormProvider} from 'react-hook-form';
import {
  NavigationAction,
  useNavigation,
  usePreventRemove,
} from '@react-navigation/native';
import {
  BackButton,
  CloseButton,
  Dialog,
  Spinner,
  BottomModalFooter,
  Typography,
} from '@components';
import {ApiErrors, HumandAPIError} from '@config/api';
import {useModalHandler} from '@hooks/useModalHandler';
import {showSnackbar} from '@redux/dispatchers';
import {FILE_ERROR_PREFIX} from '@services/attachments';
import {
  DynamicFormResponse,
  DynamicFormValues,
  SectionEvent,
} from '@shared/dynamicForms/interfaces';
import {updateDynamicFormProgression} from '@shared/dynamicForms/services';
import {useDynamicForm, useInitDynamicForm} from '@shared/dynamicForms/hooks';
import {
  getDynamicFormBody,
  getFieldName,
  hasRequiredFieldError,
} from '@shared/dynamicForms/utils';
import {differenceInSeconds} from '@shared/utils';
import {useTheme} from '@shared/theme';

import {FormSection} from '../FormSection';
import {styles} from './styles';
import PdfFormContainer from '../PdfFormContainer';
import {FormContainerProps} from './interfaces';

export interface FormContainerRef {
  initDynamicForm: ({
    formProgressionToken,
    formTag,
  }: {
    formProgressionToken: string;
    formTag: string;
  }) => void;
  getDynamicFormProgress: ({
    progressionId,
    formTag,
  }: {
    progressionId: string;
    formTag: string;
  }) => void;
  setIsFrozen: (isFrozen: boolean) => void;
}

function FormContainerForwardRef(
  {
    onSuccess,
    isLoading,
    description,
    richDescription,
    cover,
    closeFormTitle,
    closeFormDescription,
    continueButtonText,
    exitButtonText,
    showFormDescription = true,
    overrideTitle = true,
    showRequireAsterisk = true,
    onlyShowDisclaimerWhenRequired = false,
  }: FormContainerProps,
  ref: ForwardedRef<FormContainerRef>,
) {
  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 allowExitSyncRef = useRef(false);
  const [startTime, setStartTime] = useState<Date>(new Date());
  const [dynamicForm, setDynamicForm] =
    useState<Nullable<DynamicFormResponse>>(null);
  const formMethods = useDynamicForm(dynamicForm);
  const formAnswerIdRef =
    useRef<Nullable<DynamicFormResponse['formAnswerId']>>(null);
  const isPdf = formMethods.extra.isPdf;
  const {
    isVisible: isWarningVisible,
    onCloseModal: onCloseWarning,
    onOpenModal: onOpenWarning,
  } = useModalHandler();

  const {isLoadingInitForm, formTitle, isFrozen, setIsFrozen} =
    useInitDynamicForm({
      setDynamicForm,
      ref,
      onCompletedFormFb: onSuccess,
      onUnfreeze: () => {
        allowExitSyncRef.current = true;
      },
    });

  const {
    mutate: updateDynamicFormProgressionMutation,
    isPending: isUpdateDynamicFormProgressionLoading,
    variables,
  } = useMutation({
    mutationFn: updateDynamicFormProgression,
    onSuccess: data => {
      if (!data.nextSection) {
        if (data.currentSection !== 'SUCCESS') {
          showSnackbar({title: t('errors.api.404'), variant: 'error'});
          return;
        }
        setIsFrozen(true);
        formAnswerIdRef.current = data.formAnswerId;
        onSuccess?.(data.formAnswerId);
        canExit.current = true;
        return;
      }
      setDynamicForm(prev =>
        prev ? {...data, form: data.form ? data.form : prev.form} : data,
      );
      formMethods.reset();
      flatlistRef.current?.scrollToOffset({animated: true, offset: 0});
    },
    onError: (error: HumandAPIError) => {
      error.code !== ApiErrors.CONFLICT &&
        showSnackbar({
          title: t('errors.error'),
          variant: 'error',
        });
    },
  });

  const isDynamicFormLoading =
    isLoadingInitForm || isUpdateDynamicFormProgressionLoading;
  const isFormLoading = isLoadingInitForm || isLoading;
  const isUploading = !!formMethods.formState.errors[FILE_ERROR_PREFIX];

  const isFirstSection =
    dynamicForm?.nextSection.nameId === dynamicForm?.firstSection;

  const canLeaveForm = isPdf
    ? !formMethods.formState.isDirty
    : isFirstSection && !formMethods.extra.isDirty;

  const allowExit = !isFrozen && (canLeaveForm || canExit.current);
  allowExitSyncRef.current = allowExit;

  usePreventRemove(true, ({data}) => {
    if (allowExitSyncRef.current) {
      navigation.dispatch(data.action);
      return;
    }
    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: {isSubmitted, errors},
    handleSubmit,
  } = formMethods;
  const showRequiredFieldError = hasRequiredFieldError(errors);

  const onPressBack = useCallback(() => {
    if (
      dynamicForm?.currentSection ===
      dynamicForm?.nextSection.content.action.nextSection
    ) {
      return;
    }
    if (dynamicForm) {
      updateDynamicFormProgressionMutation({
        progressionId: dynamicForm.id,
        tag: dynamicForm.formTag,
        body: getDynamicFormBody({
          sectionName: dynamicForm.nextSection.nameId,
          sectionEvent: SectionEvent.Back,
          components: dynamicForm.nextSection.content.components,
          fieldValues: formMethods.getValues(),
          fillingTime: differenceInSeconds(new Date(), startTime),
        }),
      });
      setStartTime(new Date());
    }
  }, [
    dynamicForm,
    formMethods,
    startTime,
    updateDynamicFormProgressionMutation,
  ]);

  useEffect(() => {
    // When form completes successfully (isFrozen=true + canExit=true), skip
    // navigation.setOptions to prevent iOS from deferring subsequent HTTP requests
    // triggered by the native header animation this call would produce.
    if (isFrozen && canExit.current) return;
    const headerLeft = () =>
      !isFirstSection && !isFrozen && <BackButton onPress={onPressBack} />;
    const headerRight = () => <CloseButton onPress={navigation.goBack} />;
    navigation.setOptions({
      gestureEnabled: allowExit,
      headerBackButtonMenuEnabled: false,
      ...(overrideTitle && {headerTitle: formTitle}),
      ...(!isPdf && {headerLeft, headerRight}),
    });
  }, [
    navigation,
    allowExit,
    formTitle,
    overrideTitle,
    isFirstSection,
    isFrozen,
    isPdf,
    onPressBack,
  ]);

  const onPressContinue = (fieldValues: FieldValues) => {
    if (
      !dynamicForm ||
      dynamicForm.currentSection ===
        dynamicForm.nextSection.content.action.nextSection ||
      isDynamicFormLoading
    ) {
      return;
    }
    if (formAnswerIdRef.current && onSuccess) {
      return onSuccess(formAnswerIdRef.current);
    }
    updateDynamicFormProgressionMutation({
      progressionId: dynamicForm.id,
      tag: dynamicForm.formTag,
      body: getDynamicFormBody({
        sectionName: dynamicForm.nextSection.nameId,
        components: dynamicForm.nextSection.content.components,
        fieldValues,
        fillingTime: differenceInSeconds(new Date(), startTime),
      }),
    });
    setStartTime(new Date());
  };

  const onInvalidForm = useCallback(
    (fieldErrors: FieldErrors<DynamicFormValues>) => {
      if (!dynamicForm) {
        return;
      }
      const firstErrorKey = Object.keys(fieldErrors)[0];
      const {
        nameId,
        content: {components},
      } = dynamicForm.nextSection;

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

      const firstErrorIndex = components.findIndex(
        component => getFieldName(nameId, component.nameId) === firstErrorKey,
      );

      if (firstErrorIndex !== -1 && hasRequiredFieldError(fieldErrors)) {
        flatlistRef.current?.scrollToIndex({
          index: firstErrorIndex,
          animated: true,
        });
      }
    },
    [dynamicForm],
  );

  return (
    <View
      style={[
        styles.container,
        {backgroundColor: theme.background.layout.default},
      ]}>
      {!isFormLoading && dynamicForm && formMethods ? (
        <FormProvider {...formMethods}>
          <View style={styles.container}>
            {!isPdf ? (
              <>
                <FormSection
                  ref={flatlistRef}
                  description={description}
                  richDescription={richDescription}
                  nextSection={dynamicForm.nextSection}
                  isFirstSection={isFirstSection}
                  showError={showRequiredFieldError && isSubmitted}
                  cover={cover}
                  showFormDescription={showFormDescription}
                  showRequireAsterisk={showRequireAsterisk}
                  isFrozen={isFrozen}
                  onlyShowDisclaimerWhenRequired={
                    onlyShowDisclaimerWhenRequired
                  }
                />
                <BottomModalFooter
                  footer={{
                    primaryButton: {
                      onPress: handleSubmit(onPressContinue, onInvalidForm),
                      text: t('general.continue'),
                      disabled: isUploading,
                      isLoading:
                        isDynamicFormLoading &&
                        variables?.body.sectionEvent === SectionEvent.Complete,
                    },
                  }}
                />
              </>
            ) : (
              dynamicForm.form.variables && (
                <PdfFormContainer
                  pdfMeta={dynamicForm.form.variables}
                  nextSection={dynamicForm.nextSection}
                  disableSendButton={isUploading}
                  isLoading={isDynamicFormLoading}
                  onSubmit={handleSubmit(onPressContinue, onInvalidForm)}
                  description={description}
                  richDescription={richDescription}
                />
              )
            )}
          </View>
        </FormProvider>
      ) : (
        <View style={styles.spinnerContainer}>
          <Spinner />
        </View>
      )}
      <Dialog
        title={closeFormTitle || t('service_management.close_form_title')}
        isVisible={isWarningVisible}
        onClose={onCloseWarning}
        footer={{
          primaryButton: {
            onPress: onCloseWarning,
            text: continueButtonText || t('service_management.continue_form'),
          },
          secondaryButton: {
            onPress: onExitWarning,
            text: exitButtonText || t('general.exit'),
          },
        }}>
        <Typography
          variant="xs"
          align="center"
          color={theme.text.neutral.lighter}>
          {closeFormDescription ||
            t('service_management.close_form_description')}
        </Typography>
      </Dialog>
    </View>
  );
}

export const FormContainer = forwardRef(FormContainerForwardRef);
