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

import { useDrawerV2 } from '@material-hu/hooks/useDrawerV2';
import { useModal } from '@material-hu/hooks/useModal';
import {
  IconBed,
  IconCalendarDue,
  IconChevronRight,
} from '@material-hu/icons/tabler';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import HuAvatar from '@material-hu/components/design-system/Avatar';
import HuCardContainer from '@material-hu/components/design-system/CardContainer';
import HuDialog from '@material-hu/components/design-system/Dialog';
import HuSpinner from '@material-hu/components/design-system/ProgressIndicators/Spinner';
import HuTitle from '@material-hu/components/design-system/Title';

import { logEvent } from 'src/config/amplitude';
import { useAuth } from 'src/contexts/JWTContext';
import useFormatDate from 'src/hooks/useFormatDate';
import { EventName } from 'src/types/amplitude';
import {
  type AssignmentType,
  type ShiftAssignDrawerFilters,
} from 'src/types/shifts';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { useShiftsSelectionActions } from '../../contexts/ShiftsSelectionContext';
import {
  checkIfTemplateValuesWereModified,
  CUSTOM_SHIFT_INITIAL_VALUES,
  type ShiftFormData,
} from '../../form';
import { prefetchShiftsRepositoryFirstPage } from '../../queries';
import {
  getAssignmentParams,
  calculateAffectedCounts,
  getCellsFromShifts,
  checkIfUserIsShiftManager,
} from '../../utils';
import TemplateList from '../ShiftsRepository/TemplateList';

import { useAssignmentMutation } from './useAssignmentMutation';

import CustomShiftDrawer from '.';

type DrawerProps = {
  openOn?: AssignmentType;
  isDrawerOpen?: boolean;
};

type Props = {
  form: UseFormReturn<ShiftFormData>;
  debouncedValues: ShiftAssignDrawerFilters;
  totalUserCount: number;
  onClearSelections?: () => void;
};

export const useAssignShiftDrawer = (props: Props) => {
  const { form, onClearSelections, debouncedValues, totalUserCount } = props;
  const { user, permissions } = useAuth();

  const { formatDate } = useFormatDate();
  const { selectedDates, selectedCells, excludeCells, excludeShifts } =
    useShiftsSelectionActions();

  const { t } = useLokaliseTranslation([
    'shifts',
    'general',
    'validations',
    'time_tracking_common',
  ]);
  const [assignmentType, setAssignmentType] = useState<AssignmentType | null>(
    null,
  );
  const [usingRepository, setUsingRepository] = useState(false);
  const [templateShiftName, setTemplateShiftName] = useState('');

  const handleDrawerCleanup = () => {
    closeCustomShiftDrawer();
    form.reset({ ...CUSTOM_SHIFT_INITIAL_VALUES });
    setAssignmentType(null);
    setUsingRepository(false);
    setTemplateShiftName('');
  };

  const {
    modal: assignmentErrorModal,
    showModal: showAssignmentErrorModal,
    closeModal: closeAssignmentErrorModal,
  } = useModal(
    HuDialog,
    { fullWidth: true, maxWidth: 'sm' },
    {
      title: t('conflicts.could_not_assign'),
      textBody: t('conflicts.check_for_conflicts'),
      primaryButtonProps: {
        children: t('edit_assignment'),
        onClick: () => {
          closeAssignmentErrorModal();
        },
      },
      secondaryButtonProps: {
        children: t('go_back_to_shifts'),
        onClick: () => {
          closeAssignmentErrorModal();
          handleDrawerCleanup();
        },
      },
    },
  );

  const { assignShiftMutation, isAssigningShift } = useAssignmentMutation({
    onSuccessCleanup: () => {
      const { affectedUsers, affectedDates } = calculateAffectedCounts(
        selectedDates,
        selectedCells,
        totalUserCount,
        form.getValues(),
      );

      logEvent(EventName.SHIFT_MANAGEMENT_SHIFT_ASSIGNED, {
        type: assignmentType === 'shift' ? 'SHIFT' : 'RESTDAY',
        affectedUsers: affectedUsers,
        affectedDates: affectedDates,
        origin: templateShiftName ? 'from_repository' : 'custom_shift',
      });
      handleDrawerCleanup();
      onClearSelections?.();
      closeAssigningModal();
    },
    onError: () => {
      closeAssigningModal();
    },
    onConflictError: () => {
      showAssignmentErrorModal();
    },
  });

  // For assignments we need to remove the cells which have excluded shifts
  const mergedExcludedCells = Array.from(
    // Using Map to remove duplicates
    new Map(
      [...excludeCells, ...getCellsFromShifts(excludeShifts)].map(cell => [
        `${cell.userId}-${cell.date}`,
        cell,
      ]),
    ).values(),
  );

  const submitForm = form.handleSubmit((data: ShiftFormData) => {
    // If there are no completed time slots, its a day off
    const completedTimeSlots = data.timeSlots.filter(
      timeSlot => timeSlot.startTime && timeSlot.endTime,
    );
    const templateValuesModified = checkIfTemplateValuesWereModified(
      // Applied assertion here because for TS defaultValues may be undefined
      form.formState.defaultValues as ShiftFormData,
      data,
    );
    const shiftSuitableForTemplate =
      completedTimeSlots.length !== 0 && templateValuesModified;
    const userIsShiftManager = checkIfUserIsShiftManager(permissions);
    // If color, shiftName, timeSlots or notes are dirty and user is shift manager, show save shift in repository modal
    // Do not show save shift in repository modal for day off
    if (userIsShiftManager && shiftSuitableForTemplate) {
      showSaveShiftInRepositoryModal();
    } else {
      assignShiftMutation(
        getAssignmentParams({
          data,
          formatDate,
          saveAsTemplate: false,
          selectedDates,
          selectedCells,
          excludeCells: mergedExcludedCells,
          filters: debouncedValues,
        }),
      );
    }
  });

  const {
    modal: saveShiftInRepositoryModal,
    showModal: showSaveShiftInRepositoryModal,
    closeModal: closeSaveShiftInRepositoryModal,
  } = useModal(
    HuDialog,
    { fullWidth: true, maxWidth: 'sm' },
    {
      title: t('wish_to_save_shift'),
      textBody: t('wish_to_save_shift_description'),
      secondaryButtonProps: {
        children: t('save_shift_and_assign'),
        onClick: () => {
          assignShiftMutation(
            getAssignmentParams({
              data: form.getValues(),
              formatDate,
              saveAsTemplate: true,
              selectedDates,
              selectedCells,
              excludeCells: mergedExcludedCells,
              filters: debouncedValues,
            }),
          );
          closeSaveShiftInRepositoryModal();
        },
      },
      primaryButtonProps: {
        children: t('general:assign'),
        loading: isAssigningShift,
        onClick: () => {
          assignShiftMutation(
            getAssignmentParams({
              data: form.getValues(),
              formatDate,
              saveAsTemplate: false,
              selectedDates,
              selectedCells,
              excludeCells: mergedExcludedCells,
              filters: debouncedValues,
            }),
          );
          closeSaveShiftInRepositoryModal();
        },
      },
    },
  );

  const {
    modal: assigningModal,
    showModal: showAssigningModal,
    closeModal: closeAssigningModal,
  } = useModal(
    HuDialog,
    { fullWidth: true, maxWidth: 'sm' },
    {
      title: t('assigning_day_off'),
      body: (
        <Stack sx={{ flexDirection: 'row', alignItems: 'center', gap: 2 }}>
          <HuSpinner />
          <Typography variant="globalS">
            {t('time_tracking_common:this_may_take_a_while_please_wait')}
          </Typography>
        </Stack>
      ),
    },
  );

  const {
    showDrawer: showAssignShiftDrawer,
    drawer: AssignShiftDrawer,
    closeDrawer: closeCustomShiftDrawer,
  } = useDrawerV2<DrawerProps>(({ openOn, isDrawerOpen: drawerOpen }) => {
    const selectedAssignmentType = openOn ?? assignmentType;
    const isAssigningDayOff = selectedAssignmentType === 'day_off';
    const drawerTitle = !selectedAssignmentType
      ? t('assign_shift_day_off')
      : t(isAssigningDayOff ? 'assign_day_off' : 'assign_shift');

    // This constant is to help with the children/primaryContent workaround
    const primaryContent = selectedAssignmentType ? (
      <CustomShiftDrawer
        isAssigningDayOff={isAssigningDayOff}
        isDrawerOpen={drawerOpen}
        setUsingRepository={setUsingRepository}
        templateShiftName={templateShiftName}
      />
    ) : (
      <Stack sx={{ gap: 3 }}>
        <HuCardContainer
          role="button"
          onClick={() => {
            prefetchShiftsRepositoryFirstPage();
            setAssignmentType('shift');
          }}
          fullWidth
        >
          <Stack sx={{ flexDirection: 'row', alignItems: 'center', gap: 1 }}>
            <HuAvatar Icon={IconCalendarDue} />
            <HuTitle
              variant="S"
              title={t('create_or_assign_shift')}
              description={t('create_or_assign_shift_description')}
              sx={{ flex: 1 }}
            />
            <IconChevronRight />
          </Stack>
        </HuCardContainer>
        <HuCardContainer
          role="button"
          onClick={() => {
            showAssigningModal();
            assignShiftMutation(
              getAssignmentParams({
                data: form.getValues(),
                formatDate,
                selectedDates,
                selectedCells,
                excludeCells: mergedExcludedCells,
                filters: debouncedValues,
                saveAsTemplate: false,
              }),
            );
          }}
          fullWidth
        >
          <Stack sx={{ flexDirection: 'row', alignItems: 'center', gap: 1 }}>
            <HuAvatar Icon={IconBed} />
            <HuTitle
              variant="S"
              title={t('assign_day_off')}
              description={t('assign_day_off_description')}
              sx={{ flex: 1 }}
            />
          </Stack>
        </HuCardContainer>
      </Stack>
    );

    return {
      title: drawerTitle,
      primaryContent: primaryContent,
      ...(usingRepository && {
        secondaryContent: (
          <TemplateList
            onCustomShiftPrefill={(name: string) => {
              setTemplateShiftName(name);
              setUsingRepository(false);
            }}
          />
        ),
      }),
      onClose: handleDrawerCleanup,
      PaperProps: {
        sx: { maxWidth: usingRepository ? 1061 : 600 },
      },
      slotProps: {
        primaryContent: {
          flexGrow: 1,
          ...(usingRepository && { maxWidth: 'calc(100% - 395px)' }),
        },
        secondaryContent: {
          maxWidth: 395,
          display: usingRepository ? 'block' : 'none',
        },
      },
      ...(!!selectedAssignmentType && {
        primaryButtonProps: {
          children: t('general:assign'),
          size: 'large',
          fullWidth: !usingRepository,
          loading: isAssigningShift,
          onClick: () => {
            submitForm();
          },
        },
        secondaryButtonProps: {
          children: t(isAssigningDayOff ? 'general:clean' : 'discard_shift'),
          size: 'large',
          fullWidth: !usingRepository,
          disabled: isAssigningShift,
          onClick: handleDrawerCleanup,
        },
      }),
    };
  });

  const memoizedShowDrawer = useCallback(
    ({ openOn }: DrawerProps) => {
      showAssignShiftDrawer({
        openOn,
        isDrawerOpen: true,
      });
    },
    [showAssignShiftDrawer],
  );

  return {
    assignmentErrorModal,
    AssignShiftDrawer,
    saveShiftInRepositoryModal,
    runningAssignmentModal: assigningModal,
    showAssignShiftDrawer: memoizedShowDrawer,
    assignShiftMutation,
    showAssigningModal,
  };
};
