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

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

import useSnackbar from '@material-hu/components/design-system/Snackbar';
import { useDialogLayer } from '@material-hu/components/layers/Dialogs';

import { logEvent } from 'src/config/amplitude';
import useFormatDate from 'src/hooks/useFormatDate';
import {
  createShiftTemplate,
  editShiftTemplate,
  type ShiftTemplateParams,
} from 'src/services/shifts';
import { EventName } from 'src/types/amplitude';
import { type Shift } from 'src/types/shifts';
import { setTimeString } from 'src/utils/date';
import { useLokaliseTranslation } from 'src/utils/i18n';

import {
  SHIFT_TEMPLATE_INITIAL_VALUES,
  type ShiftTemplateFormData,
} from '../../form';
import { invalidateShiftsRepository } from '../../queries';
import { parseShiftTemplateData } from '../../utils';

import EditTemplate from './EditTemplate';

const CREATING_TEMPLATE = 0;

type ShowRepositoryDrawerOptions = {
  template?: Shift;
};

type UseRepositoryDrawerParams = {
  /**
   * Optional callback fired after a new template is successfully created.
   * Receives the freshly created shift returned by the API.
   */
  onTemplateCreated?: (shift: Shift) => void;
  /**
   * Optional callback fired when the create mutation fails. Useful when the
   * caller wants to render its own context-specific snackbar.
   */
  onTemplateCreateError?: () => void;
  /**
   * Disable the default success / error snackbars triggered by this hook.
   * When `true`, the caller is responsible for surfacing feedback (typically
   * inside the `onTemplateCreated` / `onTemplateCreateError` callbacks).
   */
  disableDefaultSnackbar?: boolean;
};

export const useRepositoryDrawer = ({
  onTemplateCreated,
  onTemplateCreateError,
  disableDefaultSnackbar,
}: UseRepositoryDrawerParams = {}) => {
  const { t } = useLokaliseTranslation('shifts');
  const [editingTemplate, setEditingTemplate] = useState<number | null>(null);
  const { enqueueSnackbar } = useSnackbar();
  const { formatDate } = useFormatDate();
  const { openDialog, closeDialog } = useDialogLayer();

  const form = useForm<ShiftTemplateFormData>({
    defaultValues: { ...SHIFT_TEMPLATE_INITIAL_VALUES },
    mode: 'onSubmit',
  });

  const handleDrawerCleanup = () => {
    closeRepositoryDrawer();
    form.reset({ ...SHIFT_TEMPLATE_INITIAL_VALUES });
    setEditingTemplate(null);
  };

  const { mutate: createTemplateMutation, isLoading: isCreatingMutation } =
    useMutation({
      mutationFn: (data: ShiftTemplateParams) => createShiftTemplate(data),
      onSuccess: async response => {
        logEvent(EventName.SHIFT_MANAGEMENT_REPOSITORY_CREATE_SHIFT, {});
        await invalidateShiftsRepository();
        if (!disableDefaultSnackbar) {
          enqueueSnackbar({
            title: t('actions.create_shift.success'),
            variant: 'success',
          });
        }
        handleDrawerCleanup();
        onTemplateCreated?.(response.data);
      },
      onError: () => {
        if (!disableDefaultSnackbar) {
          enqueueSnackbar({
            title: t('actions.create_shift.error'),
            description: t('actions.try_again'),
            variant: 'error',
          });
        }
        onTemplateCreateError?.();
      },
    });

  const { mutate: updateTemplateMutation, isLoading: isUpdatingMutation } =
    useMutation({
      mutationFn: ({ id, ...data }: ShiftTemplateParams & { id: number }) =>
        editShiftTemplate(id, data),
      onSuccess: async () => {
        await invalidateShiftsRepository();
        enqueueSnackbar({
          title: t('actions.edit_shift.success'),
          variant: 'success',
        });
        handleDrawerCleanup();
      },
      onError: () => {
        enqueueSnackbar({
          title: t('actions.edit_shift.error'),
          description: t('actions.try_again'),
          variant: 'error',
        });
      },
    });

  const submitForm = form.handleSubmit((data: ShiftTemplateFormData) => {
    if (editingTemplate === CREATING_TEMPLATE) {
      createTemplateMutation(parseShiftTemplateData(data, formatDate));
    } else if (editingTemplate) {
      updateTemplateMutation({
        id: editingTemplate,
        ...parseShiftTemplateData(data, formatDate),
      });
    }
  });

  const handlePrimaryClick = () => {
    const isCreatingTemplate = editingTemplate === CREATING_TEMPLATE;
    if (isCreatingTemplate) {
      submitForm();
      return;
    }
    openDialog({
      title: t('actions.edit_shift.title'),
      textBody: t('actions.edit_shift.description'),
      onClose: () => closeDialog(),
      primaryButtonProps: {
        children: t('general:save_changes'),
        onClick: () => {
          closeDialog();
          submitForm();
        },
      },
      secondaryButtonProps: {
        children: t('general:exit_without_saving'),
        onClick: () => closeDialog(),
      },
      dialogProps: { fullWidth: true, maxWidth: 'sm' },
    });
  };

  const {
    showDrawer,
    drawer: RepositoryDrawer,
    closeDrawer: closeRepositoryDrawer,
  } = useDrawerV2(() => {
    const isCreatingTemplate = editingTemplate === CREATING_TEMPLATE;

    return {
      title: t(isCreatingTemplate ? 'create_shift' : 'edit_shift'),
      children: (
        <FormProvider {...form}>
          <EditTemplate />
        </FormProvider>
      ),
      onClose: handleDrawerCleanup,
      primaryButtonProps: {
        children: t(
          isCreatingTemplate ? 'create_shift' : 'general:save_changes',
        ),
        fullWidth: true,
        loading: isCreatingMutation || isUpdatingMutation,
        onClick: handlePrimaryClick,
      },
      secondaryButtonProps: {
        children: t(
          isCreatingTemplate ? 'discard_shift' : 'general:exit_without_saving',
        ),
        fullWidth: true,
        disabled: isCreatingMutation || isUpdatingMutation,
        onClick: handleDrawerCleanup,
      },
    };
  });

  const showRepositoryDrawer = useCallback(
    (options?: ShowRepositoryDrawerOptions) => {
      const template = options?.template;
      if (template) {
        setEditingTemplate(template.id);
        form.reset({
          shiftName: template.name,
          color: template.color || '',
          timeSlots: template.timeSlots.map(ts => ({
            id: ts.id,
            startTime: setTimeString(new Date(), ts.startTime),
            endTime: setTimeString(new Date(), ts.endTime),
          })),
          notes: template.description,
        });
      } else {
        setEditingTemplate(CREATING_TEMPLATE);
        form.reset({ ...SHIFT_TEMPLATE_INITIAL_VALUES });
      }
      showDrawer({});
    },
    [showDrawer, form],
  );

  return {
    RepositoryDrawer,
    showRepositoryDrawer,
  };
};
