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

import { type FileAsset } from '@material-hu/types/attachments';

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

import useSnackbar from '../../hooks/useSnackbar';
import {
  type PdfPlacedField,
  type SectionCreationSteps,
  type ServiceItemDraft,
  ServiceItemStatus,
  Step,
} from '../../types';
import {
  findFirstInvalidPdfField,
  isValidPdfForm,
} from '../components/FormCreation/pdf/utils';

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

type PdfScrollFn = (
  pageIndex: number,
  yRel: number,
  behavior?: ScrollBehavior,
) => void;

type DynamicFormBag = ReturnType<typeof useDynamicForm>;

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

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

  const {
    dynamicForm,
    setShowFormValidations,
    setCreatingPdfForm,
    updatePdfFormMutation,
    updatePdfAssetMutation,
    restoreToEmptyDynamicFormMutation,
    setHasModifiedFormForActiveServiceItem,
    errorSensitiveFields,
    setErrorSensitiveFields,
  } = dynamic;

  // Register scroll function from PdfCreation. On mount, the context registers
  // this function so that this component (parent) can use it to scroll to the
  // first invalid field, calling the lower level context to do the actual scrolling.
  const pdfScrollRef = useRef<PdfScrollFn>();
  const handleRegisterPdfScroll = (fn: PdfScrollFn) => {
    pdfScrollRef.current = fn;
  };

  const updateErrorSensitiveFields = (fields: PdfPlacedField[]) => {
    if (!fields) return;
    const errorFields: Record<string, boolean> = {};
    fields?.forEach(field => {
      errorFields[field.id] = true;
    });
    setErrorSensitiveFields(errorFields);
  };

  const handlePdfSelected = async (pdfAsset: FileAsset) => {
    if (!dynamicForm || !pdfAsset) return;
    await updatePdfAssetMutation.mutateAsync(pdfAsset);
    setCreatingPdfForm(true);
  };

  const handleDeleteSelectedPdf = (callback?: () => void) => {
    restoreToEmptyDynamicFormMutation.mutate(undefined, {
      onSettled: callback,
    });
  };

  const submitPdfForm = async ({
    exitOnSuccess,
  }: {
    exitOnSuccess: boolean;
  }) => {
    const values = form.getValues(Step.FORM);
    const fields = values.pdf?.fields ?? [];

    if (!isValidPdfForm(values)) {
      updateErrorSensitiveFields(fields);
      await form.trigger(Step.FORM);
      setShowFormValidations(true);
      showSnackbar({
        title: t('form_pdf_validation_error'),
        variant: 'error',
      });
      const firstInvalid = findFirstInvalidPdfField(fields);
      if (firstInvalid) {
        pdfScrollRef.current?.(
          firstInvalid.pageIndex ?? 0,
          firstInvalid.y ?? 0,
          'smooth',
        );
      }
      return;
    }

    await updatePdfFormMutation.mutateAsync(undefined, {
      onSuccess: () => {
        if (serviceItem?.status === ServiceItemStatus.ACTIVE) {
          setHasModifiedFormForActiveServiceItem(true);
        }
      },
    });
    setShowFormValidations(false);
    setErrorSensitiveFields({});
    if (exitOnSuccess) setCreatingPdfForm(false);
  };

  const handleSavePdfForm = () => submitPdfForm({ exitOnSuccess: false });
  const handleSaveAndExitPdfForm = () => submitPdfForm({ exitOnSuccess: true });

  const handleExitWithoutSavingPdfForm = (callback?: () => void) => {
    if (!dynamicForm) return;

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

    setShowFormValidations(false);
    setCreatingPdfForm(false);
    callback?.();
  };

  const handleReplacePdfForm = (newPdfFile: FileAsset) => {
    if (!dynamicForm) {
      showSnackbar({
        title: t('form_save_error'),
        description: t('try_again_later'),
        variant: 'error',
      });
      return;
    }
    updatePdfAssetMutation.mutate(newPdfFile);
  };

  return {
    errorSensitiveFields,
    handlers: {
      onPdfSelected: handlePdfSelected,
      onDeleteSelectedPdf: handleDeleteSelectedPdf,
      onSavePdfForm: handleSavePdfForm,
      onSaveAndExitPdfForm: handleSaveAndExitPdfForm,
      onExitWithoutSavingPdfForm: handleExitWithoutSavingPdfForm,
      onReplacePdfForm: handleReplacePdfForm,
      onRegisterPdfScroll: handleRegisterPdfScroll,
    },
  };
};

export default usePdfFormFlow;
