import { useEffect } from 'react';
import { useFieldArray, useFormContext, useWatch } from 'react-hook-form';

import {
  IconArrowRight,
  IconPlus,
  IconTrash,
  IconCalendarDue,
} from '@material-hu/icons/tabler';
import Divider from '@material-hu/mui/Divider';
import IconButton from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';
import { useTheme, Theme } from '@material-hu/mui/styles';
import TextField from '@material-hu/mui/TextField';
import Typography from '@material-hu/mui/Typography';

import HuFormTimePicker from '@material-hu/components/composed-components/TimePicker/form';
import Button from '@material-hu/components/design-system/Buttons/Button';
import HuCardContainer from '@material-hu/components/design-system/CardContainer';
import HuFormDatePicker from '@material-hu/components/design-system/Inputs/DatePicker/form';

import useFormatDate from 'src/hooks/useFormatDate';
import useRules from 'src/hooks/useRules';
import { validateNoEqualDates } from 'src/pages/dashboard/timeTracking/validations';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { useShiftsSelectionActions } from '../../../contexts/ShiftsSelectionContext';
import { ShiftFormData, shiftFormFields } from '../../../form';
import { getDateRangeText } from '../../ShiftsTable/utils';

type Props = {
  isAssigningDayOff?: boolean;
  setUsingRepository?: (usingRepository: boolean) => void;
  isCreatingTemplate?: boolean;
  templateShiftName?: string;
};

const PICKER_COMMON_PROPS = {
  textFieldProps: {
    sx: {
      backgroundColor: 'unset',
      '.MuiInputBase-root': {
        backgroundColor: ({ palette }: Theme) =>
          palette.new.background.layout.tertiary,
      },
      width: '100%',
    },
  },
  timePickerProps: {
    slotProps: {
      openPickerIcon: {
        sx: {
          stroke: 'unset !important',
          color: ({ palette }: Theme) => palette.new.text.neutral.default,
        },
      },
    },
  },
};

const PeriodSection = ({
  isAssigningDayOff = false,
  setUsingRepository,
  isCreatingTemplate = false,
  templateShiftName,
}: Props) => {
  const { palette } = useTheme();
  const {
    control,
    trigger,
    formState: { isSubmitted },
  } = useFormContext<ShiftFormData>();
  // Using useWatch to get the slots because the timeSlotsFields is not updated when the slots are modified
  const timeSlots = useWatch({
    control,
    name: shiftFormFields.timeSlots.base,
  });
  const { t } = useLokaliseTranslation([
    'shifts',
    'general',
    'time_off',
    'time_tracker',
    'validations',
    'work_schedules',
  ]);
  const { selectedDates, selectedCells } = useShiftsSelectionActions();
  const { formatDate } = useFormatDate();

  // Create rules for time picker
  const getTimeRules = (index: number, time: Date | null) => {
    const validateRules = {
      requiredWithMessage:
        index === 0 || time ? t('validations:required') : false,
      validateDatesCollision: {
        datesRange: timeSlots
          .filter(timeSlot => timeSlot.startTime && timeSlot.endTime)
          .map(timeSlot => ({
            start: timeSlot.startTime?.toISOString() || '',
            end: timeSlot.endTime?.toISOString() || '',
          })),
        errorMessage: t('validations:hour.collision'),
        allowInvertedRanges: true,
      },
    };
    const customRules = {
      noRepeated: (value: Date) =>
        validateNoEqualDates(value, time) || t('validations:hour.collision'),
    };
    return useRules(validateRules, customRules);
  };

  const {
    append: appendSlotToArray,
    remove: removeTimeSlotFromArray,
    fields: timeSlotsFields,
  } = useFieldArray({
    control: control,
    name: shiftFormFields.timeSlots.base,
    keyName: 'fieldId',
  });

  const addSlot = () => {
    appendSlotToArray({
      id: Date.now(),
      startTime: null,
      endTime: null,
    });
  };

  const removeSlot = (index: number) => {
    removeTimeSlotFromArray(index);
  };

  // Need to revalidate the form in the case that a user tries to fix the error by changing the valid field
  // because in that case the form will keep showing the error, until the non valid input is changed
  useEffect(() => {
    if (isSubmitted) {
      trigger(shiftFormFields.timeSlots.base);
    }
  }, [timeSlots]);

  // Count unique dates coming from both the explicit date set and the selected cells
  const selectedDatesFromCells = new Set(selectedCells.map(c => c.date));
  const uniqueDatesCount = new Set([
    ...selectedDates,
    ...selectedDatesFromCells,
  ]).size;
  const hasMultipleDates = uniqueDatesCount > 1;

  return (
    <>
      <Typography
        variant="globalM"
        sx={{ fontWeight: 'fontWeightSemiBold' }}
      >
        {t('time_off:period')}
      </Typography>
      <HuCardContainer
        sx={{
          backgroundColor: palette.new.background.layout.default,
          border: 'unset',
          mb: 1,
          overflow: 'visible',
          '& .MuiCardContent-root': {
            display: 'flex',
            flexDirection: 'column',
            justifyContent: 'center',
          },
        }}
        fullWidth
      >
        {!isCreatingTemplate && (
          <>
            {hasMultipleDates && (
              <Stack>
                <Typography
                  variant="globalS"
                  sx={{
                    fontWeight: 'fontWeightSemiBold',
                    mb: 0.5,
                    color: palette.new.text.neutral.default,
                  }}
                >
                  {t('time_tracker:date')}
                </Typography>
                <TextField
                  value={getDateRangeText(
                    selectedDates,
                    selectedCells,
                    t,
                    formatDate,
                  )}
                  disabled
                  fullWidth
                  InputProps={{
                    endAdornment: (
                      <IconCalendarDue
                        size={26}
                        color={palette.new.text.neutral.default}
                      />
                    ),
                  }}
                  sx={{
                    '& .MuiOutlinedInput-root': {
                      backgroundColor: palette.new.background.elements.grey,
                      '& fieldset': {
                        borderColor: palette.new.border.neutral.default,
                      },
                      '&:hover fieldset': {
                        borderColor: palette.new.border.neutral.default,
                      },
                      '&.Mui-focused fieldset': {
                        borderColor: palette.new.border.neutral.default,
                      },
                      '&.Mui-disabled fieldset': {
                        borderColor: palette.new.border.neutral.default,
                      },
                    },
                  }}
                />
              </Stack>
            )}
            {!hasMultipleDates && (
              <HuFormDatePicker
                name={shiftFormFields.date}
                inputProps={{
                  label: t('time_tracker:date'),
                  disabled: selectedDates.size > 0 || selectedCells.length > 0,
                }}
                rules={{ required: t('shift_validations.required_date') }}
              />
            )}
          </>
        )}
        {!isAssigningDayOff && (
          <>
            {timeSlotsFields.map((fieldSlot, index) => {
              // Since useFieldArray doesn't update the array when the slots are modified,
              // we need to use the timeSlots array to get the latest values (default to fieldSlot if timeSlots does not exist
              const slot = timeSlots?.[index] || fieldSlot;
              return (
                <Stack
                  key={slot.id}
                  sx={{
                    mt: 2,
                    alignItems: 'center',
                    flexDirection: 'row',
                    justifyContent: 'space-between',
                    width: '100%',
                    position: 'relative',
                  }}
                >
                  <Stack
                    sx={{
                      alignItems: 'flex-start',
                      flexDirection: 'row',
                      width: '100%',
                      maxWidth: 'calc(100% - 50px)',
                      gap: 2,
                      '& > .MuiStack-root': {
                        flex: 1,
                      },
                    }}
                  >
                    <HuFormTimePicker
                      name={shiftFormFields.timeSlots.start(index)}
                      {...PICKER_COMMON_PROPS}
                      inputProps={{
                        placeholder: t('shifts:entry_hour'),
                        fullWidth: true,
                      }}
                      rules={getTimeRules(index, slot.endTime)}
                    />
                    <HuFormTimePicker
                      name={shiftFormFields.timeSlots.end(index)}
                      {...PICKER_COMMON_PROPS}
                      inputProps={{
                        placeholder: t('shifts:exit_hour'),
                        fullWidth: true,
                      }}
                      rules={getTimeRules(index, slot.startTime)}
                    />
                  </Stack>
                  {timeSlotsFields.length > 1 && index !== 0 && (
                    <IconButton
                      aria-label={t('remove_time_slot')}
                      onClick={() => {
                        removeSlot(index);
                      }}
                      sx={{
                        position: 'absolute',
                        right: 0,
                        top: '8px', // Value is fixed because conditional error messages shift the layout
                      }}
                    >
                      <IconTrash />
                    </IconButton>
                  )}
                </Stack>
              );
            })}
            {timeSlotsFields.length < 3 && (
              <IconButton
                aria-label={t('work_schedules:add_slot')}
                onClick={addSlot}
                variant="secondary"
                sx={{
                  alignSelf: 'center',
                  mt: 2,
                  borderRadius: theme => theme.shape.borderRadiusM,
                }}
              >
                <IconPlus />
              </IconButton>
            )}
            {!isCreatingTemplate && (
              <>
                <Divider sx={{ my: 3 }} />
                <Button
                  variant="secondary"
                  onClick={() => {
                    setUsingRepository?.(true);
                  }}
                  sx={{ alignSelf: 'flex-start' }}
                  endIcon={<IconArrowRight />}
                  size="large"
                  fullWidth
                >
                  {templateShiftName || t('use_shifts_repository')}
                </Button>
              </>
            )}
          </>
        )}
      </HuCardContainer>
    </>
  );
};

export default PeriodSection;
