import { useCallback } from 'react';
import { useMutation } from 'react-query';

import { AxiosError } from 'axios';

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

import useGeneralError from 'src/hooks/useGeneralError';
import {
  bulkDeleteShift,
  BulkDeleteShiftParams,
  removeDayAssignment,
  RemoveDayAssignmentParams,
} from 'src/services/shifts';
import { ResponseError } from 'src/types/services';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { useShiftsSelectionActions } from '../contexts/ShiftsSelectionContext';
import { invalidateShiftsCalendar } from '../queries';
import { getBulkDeleteParams, ShiftFilters } from '../utils';

type Props = {
  filters?: ShiftFilters;
  onSuccess?: () => void;
};

export const useShiftBulkDelete = ({ filters = {}, onSuccess }: Props = {}) => {
  const { t } = useLokaliseTranslation('shifts');
  const showGeneralError = useGeneralError();
  const { enqueueSnackbar } = useHuSnackbar();
  const {
    selectedDates,
    selectedCells,
    excludeCells,
    selectedShifts,
    excludeShifts,
    copiedCells,
    clearAllSelections,
  } = useShiftsSelectionActions();

  const { mutate: individualDeleteMutation, isLoading: isDeletingAssignment } =
    useMutation({
      mutationFn: (data: RemoveDayAssignmentParams) =>
        removeDayAssignment(data),
      onSuccess: async (_, variables: RemoveDayAssignmentParams) => {
        const copiedCellWasDeleted = copiedCells.some(cell =>
          cell.shiftIds.includes(variables.shiftAssignedShiftId),
        );
        await invalidateShiftsCalendar();
        clearAllSelections({ keepCopiedCells: !copiedCellWasDeleted });
        if (onSuccess) {
          onSuccess();
        }
        enqueueSnackbar({
          title: t('shifts:actions.remove_assignment.success'),
          variant: 'success',
        });
      },
      onError: (error: AxiosError<ResponseError>) => {
        showGeneralError(
          error,
          t('shifts:actions.remove_assignment.error'),
          true,
          {
            description: t(
              'shifts:actions.remove_assignment.error_description',
            ),
          },
        );
      },
    });

  const { mutate: bulkDeleteMutation, isLoading: isDeletingBulk } = useMutation(
    {
      mutationFn: (data: BulkDeleteShiftParams) => bulkDeleteShift(data),
      onSuccess: async (_, variables: BulkDeleteShiftParams) => {
        const copiedCellWasDeleted = copiedCells.reduce(
          (acc, cell) =>
            acc ||
            cell.shiftIds.some(
              shiftId => variables.assignedShiftIds?.includes(shiftId) ?? false,
            ),
          false,
        );
        await invalidateShiftsCalendar();
        clearAllSelections({ keepCopiedCells: !copiedCellWasDeleted });
        if (onSuccess) {
          onSuccess();
        }
        enqueueSnackbar({
          title: t('shifts:actions.bulk_remove_assignment.success'),
          variant: 'success',
        });
      },
      onError: (error: AxiosError<ResponseError>) => {
        showGeneralError(
          error,
          t('shifts:actions.bulk_remove_assignment.error'),
          true,
          {
            description: t(
              'shifts:actions.bulk_remove_assignment.error_description',
            ),
          },
        );
      },
    },
  );

  const executeBulkDelete = useCallback(
    (shiftIds?: number[]) => {
      // If specific shift ids are provided, use them, otherwise use selected shifts
      const assignedShiftIds = shiftIds || Array.from(selectedShifts.keys());

      const params = getBulkDeleteParams({
        selectedDates,
        selectedCells,
        excludeCells,
        filters,
        assignedShiftIds,
        excludeAssignedShiftIds: Array.from(excludeShifts.keys()),
      });

      bulkDeleteMutation(params);
    },
    [
      selectedShifts,
      selectedDates,
      selectedCells,
      excludeCells,
      excludeShifts,
      filters,
      bulkDeleteMutation,
    ],
  );

  const executeIndividualDelete = useCallback(
    (params: RemoveDayAssignmentParams) => {
      individualDeleteMutation(params);
    },
    [individualDeleteMutation],
  );

  return {
    executeBulkDelete,
    isDeletingBulk,
    executeIndividualDelete,
    isDeletingAssignment,
    isDeletingShifts: isDeletingAssignment || isDeletingBulk,
  };
};
