import { useCallback, useEffect } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useMutation } from 'react-query';

import { AxiosError } from 'axios';

import { useDrawerV2 } from '@material-hu/hooks/useDrawerV2';
import { useModal } from '@material-hu/hooks/useModal';

import Dialog from '@material-hu/components/design-system/Dialog';
import useSnackbar from '@material-hu/components/design-system/Snackbar';

import useGeneralError from 'src/hooks/useGeneralError';
import {
  duplicateShiftsInPeriod,
  DuplicateShiftsParams,
  ShiftCalendarParams,
  ShiftErrorCodes,
} from 'src/services/shifts';
import { ResponseError } from 'src/types/services';
import { useLokaliseTranslation } from 'src/utils/i18n';

import {
  DUPLICATE_SHIFTS_INITIAL_VALUES,
  DuplicateShiftsFormData,
} from '../../form';
import { removeCalendarQueryData } from '../../queries';
import { mapFilters } from '../../utils';
import { DUPLICATE_MAX_USERS_LIMIT } from '../ShiftsTable/constants';

import DuplicateShiftsForm from '.';

type FilterParams = Omit<ShiftCalendarParams, 'page' | 'limit'>;

type Props = {
  filters: FilterParams;
  filteredUsersCount: number;
};

const createInitialValues = (
  filters: FilterParams,
): DuplicateShiftsFormData => ({
  ...DUPLICATE_SHIFTS_INITIAL_VALUES,
  copyRange: {
    fromDate: new Date(`${filters.startDate}T00:00`),
    toDate: new Date(`${filters.endDate}T00:00`),
  },
  pasteRange: { fromDate: null, toDate: null },
});

export const useDuplicateShiftsDrawer = ({
  filters,
  filteredUsersCount,
}: Props) => {
  const { t } = useLokaliseTranslation('shifts');
  const { enqueueSnackbar } = useSnackbar();
  const showGeneralError = useGeneralError();

  const form = useForm<DuplicateShiftsFormData>({
    defaultValues: createInitialValues(filters),
    mode: 'onSubmit',
  });

  const handleDrawerCleanup = () => {
    closeDuplicateShiftsDrawer();
    form.reset({
      ...DUPLICATE_SHIFTS_INITIAL_VALUES,
      copyRange: {
        fromDate: new Date(`${filters.startDate}T00:00`),
        toDate: new Date(`${filters.endDate}T00:00`),
      },
    });
  };

  const { mutate: duplicateShifts, isLoading: isDuplicatingShiftPeriods } =
    useMutation({
      mutationFn: (data: DuplicateShiftsParams) =>
        duplicateShiftsInPeriod(data),
      onSuccess: async (_, variables) => {
        await removeCalendarQueryData(
          variables.targetStartDate,
          variables.targetEndDate,
        );
        enqueueSnackbar({
          title: t('actions.duplicate_shift_periods.success'),
          description: t('actions.duplicate_shift_periods.success_description'),
          variant: 'success',
        });
        handleDrawerCleanup();
      },
      onError: (error: AxiosError<ResponseError>) => {
        if (
          error.response?.data.code ===
          ShiftErrorCodes.SHIFT_MANAGEMENT_INVALID_TIME_SLOTS
        ) {
          showDuplicateConflictErrorModal();
        } else {
          showGeneralError(error, t('actions.duplicate_shift_periods.error'));
        }
      },
    });

  const submitForm = form.handleSubmit(() => {
    showConfirmDuplicateModal();
  });

  const {
    modal: ConfirmDuplicateModal,
    showModal: showConfirmDuplicateModal,
    closeModal: closeConfirmDuplicateModal,
  } = useModal(
    Dialog,
    { fullWidth: true, maxWidth: 'sm' },
    {
      title: t('duplicate_shifts_period.confirm_duplicate_planification'),
      textBody: t(
        'duplicate_shifts_period.confirm_duplicate_planification_description',
      ),
      actionInfo: `${t('general:collaborators')}: ${filteredUsersCount}`,
      primaryButtonProps: {
        children: t('general:duplicate'),
        onClick: () => {
          closeConfirmDuplicateModal();
          const { copyRange, pasteRange } = form.getValues();
          // If this point is reached, the values are not null
          duplicateShifts({
            sourceStartDate: copyRange.fromDate!.toISOString().split('T')[0],
            sourceEndDate: copyRange.toDate!.toISOString().split('T')[0],
            targetStartDate: pasteRange.fromDate!.toISOString().split('T')[0],
            targetEndDate: pasteRange.toDate!.toISOString().split('T')[0],
            filters: mapFilters(filters),
          });
        },
      },
      secondaryButtonProps: {
        children: t('general:cancel'),
        onClick: () => {
          closeConfirmDuplicateModal();
        },
      },
    },
  );

  const {
    modal: ConfirmDiscardChangesModal,
    showModal: showConfirmDiscardChangesModal,
    closeModal: closeConfirmDiscardChangesModal,
  } = useModal(
    Dialog,
    { fullWidth: true, maxWidth: 'sm' },
    {
      title: t('duplicate_shifts_period.confirm_discard_changes'),
      textBody: t(
        'duplicate_shifts_period.confirm_discard_changes_description',
      ),
      primaryButtonProps: {
        children: t('general:cancel'),
        onClick: () => {
          closeConfirmDiscardChangesModal();
          handleDrawerCleanup();
        },
      },
      secondaryButtonProps: {
        children: t('general:keep_editing'),
        onClick: () => {
          closeConfirmDiscardChangesModal();
        },
      },
    },
  );

  const {
    modal: DuplicateConflictErrorModal,
    showModal: showDuplicateConflictErrorModal,
    closeModal: closeDuplicateConflictErrorModal,
  } = useModal(
    Dialog,
    { fullWidth: true, maxWidth: 'sm' },
    {
      title: t('conflicts.could_not_duplicate_period'),
      textBody: t('conflicts.check_for_conflicts_duplicate'),
      primaryButtonProps: {
        children: t('go_back_to_shifts'),
        onClick: () => {
          closeDuplicateConflictErrorModal();
          handleDrawerCleanup();
        },
      },
      secondaryButtonProps: {
        children: t('general:keep_editing'),
        onClick: () => {
          closeDuplicateConflictErrorModal();
        },
      },
    },
  );

  const {
    showDrawer: showDuplicateShiftsDrawer,
    drawer: DuplicateShiftsDrawer,
    closeDrawer: closeDuplicateShiftsDrawer,
  } = useDrawerV2(() => ({
    title: t('duplicate_shifts_period.duplicate_planification'),
    children: (
      <FormProvider {...form}>
        <DuplicateShiftsForm
          showUsersAlert={filteredUsersCount > DUPLICATE_MAX_USERS_LIMIT}
        />
      </FormProvider>
    ),
    onClose: () => {
      if (form.formState.isDirty && !form.formState.isSubmitted) {
        showConfirmDiscardChangesModal();
      } else {
        handleDrawerCleanup();
      }
    },
    primaryButtonProps: {
      children: t('duplicate_shifts_period.duplicate_planification'),
      fullWidth: true,
      loading: isDuplicatingShiftPeriods,
      onClick: () => {
        submitForm();
      },
      disabled:
        filteredUsersCount > DUPLICATE_MAX_USERS_LIMIT ||
        !form.formState.isValid,
    },
    secondaryButtonProps: {
      children: t('general:clean_dates'),
      fullWidth: true,
      disabled: isDuplicatingShiftPeriods,
      onClick: () => {
        form.reset({ ...DUPLICATE_SHIFTS_INITIAL_VALUES });
      },
    },
  }));

  const memoizedShowDrawer = useCallback((params: FilterParams) => {
    showDuplicateShiftsDrawer(params);
  }, []);

  // Reset the form when the filters change (since hook is mounted along shifts page we need to reset the form when the filters change)
  useEffect(() => {
    form.reset(createInitialValues(filters));
  }, [filters]);

  return {
    ConfirmDuplicateModal,
    DuplicateConflictErrorModal,
    ConfirmDiscardChangesModal,
    DuplicateShiftsDrawer,
    showDuplicateShiftsDrawer: memoizedShowDrawer,
  };
};
