import { type UseFormReturn } from 'react-hook-form';

import { type TFunction } from 'i18next';

import { useLokaliseTranslation } from 'src/utils/i18n';

import useSnackbar from '../../hooks/useSnackbar';
import {
  type SectionCreationSteps,
  type ServiceItemDraft,
  ServiceItemStatus,
  Step,
} from '../../types';
import { dynamicFormHasChanges, isValidForm } from '../../utils';
import useExitFormCreationModal from '../components/modals/useExitFormCreationModal';

import type useDynamicForm from './useDynamicForm';
import { buildFormStepValues } from './useNewServiceItemForm';

type DynamicFormBag = ReturnType<typeof useDynamicForm>;

type Args = {
  form: UseFormReturn<SectionCreationSteps>;
  formValues: SectionCreationSteps;
  dynamic: DynamicFormBag;
  serviceItem?: ServiceItemDraft;
};

const useRegularFormFlow = ({
  form,
  formValues,
  dynamic,
  serviceItem,
}: Args) => {
  const { t } = useLokaliseTranslation(['service_management', 'general']);
  const { showSnackbar } = useSnackbar();

  const {
    formTag,
    dynamicForm,
    setShowFormValidations,
    setCreatingForm,
    updateRegularFormMutation,
    setHasModifiedFormForActiveServiceItem,
  } = dynamic;

  const handleOpenCreateForm = () => setCreatingForm(true);

  const handleResetDynamicForm = () => {
    form.reset({
      ...formValues,
      [Step.FORM]: buildFormStepValues(dynamicForm, t),
    });
  };

  type FormSubmissionCallbacks = {
    /** Called once the server-side save succeeds. */
    onServerSuccess?: () => void;
    /** Called when client-side validation fails (after the snackbar is shown). */
    onValidationFail?: () => void;
  };

  const handleFormSubmission = async ({
    onServerSuccess,
    onValidationFail,
  }: FormSubmissionCallbacks = {}) => {
    const values = form.getValues(Step.FORM);

    if (!isValidForm(values)) {
      await form.trigger(Step.FORM);
      setShowFormValidations(true);
      showSnackbar({
        title: t('form_validation_error'),
        variant: 'error',
      });
      onValidationFail?.();
      return;
    }

    if (!formTag || !dynamicForm) return;

    setShowFormValidations(false);
    updateRegularFormMutation.mutate(undefined, {
      onSuccess: () => {
        onServerSuccess?.();
        showSnackbar({
          title: t('form_save_success'),
          variant: 'success',
        });
        if (serviceItem?.status === ServiceItemStatus.ACTIVE) {
          setHasModifiedFormForActiveServiceItem(true);
        }
      },
      onError: () => {
        setShowFormValidations(true);
        showSnackbar({
          title: t('form_save_error'),
          variant: 'error',
        });
      },
    });
  };

  const { open: openExitFormCreationModal, modal: exitFormCreationModal } =
    useExitFormCreationModal({
      isLoading: updateRegularFormMutation.isLoading,
      onSave: closeModal =>
        handleFormSubmission({
          onServerSuccess: () => {
            setCreatingForm(false);
            closeModal();
          },
          // Close the modal on validation failure too — the inline error is
          // surfaced inside the form, so keeping the modal open is redundant.
          onValidationFail: closeModal,
        }),
      onExitWithoutSaving: () => {
        handleResetDynamicForm();
        setCreatingForm(false);
      },
    });

  const handleCloseCreateForm = () => {
    if (!dynamicForm) return;
    if (
      !dynamicFormHasChanges(
        form.getValues(Step.FORM)?.sections ?? [],
        dynamicForm,
        t as TFunction,
      )
    ) {
      setCreatingForm(false);
      return;
    }
    openExitFormCreationModal();
  };

  return {
    handlers: {
      onOpenCreateForm: handleOpenCreateForm,
      onCloseCreateForm: handleCloseCreateForm,
      onFormSubmission: handleFormSubmission,
      onResetDynamicForm: handleResetDynamicForm,
    },
    modal: exitFormCreationModal,
  };
};

export default useRegularFormFlow;
