import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import dayjs from 'dayjs';
import durationPlugin from 'dayjs/plugin/duration';

import { DAY, EXTERNAL_ENDPOINT, MONTH, NON_RECURRING, WEEK } from '../../constants';

import validateField from '../../helpers/validation';
import {
  deliverySelector,
  errorsSelector,
  recurrentEndDateSelector,
  recurrentPeriodSelector,
} from '../../redux/selectors';
import { setErrorAction, updateLiveEventFormAction } from '../../redux/slices';

import { FormGroup, FormRow, useFormSettings } from '@/modules/@common/Form';
import {
  Button,
  DatePicker,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  FormControl,
  InputLabel,
  MenuItem,
  Select,
} from '@/mui/components';

dayjs.extend(durationPlugin);

const weekOfMonth = {
  1: 'first',
  2: 'second',
  3: 'third',
  4: 'fourth',
  5: 'last',
};

function Recurring({ eventStartDate = null, eventEndDate = null, ...props }) {
  const { size } = useFormSettings();
  const dispatch = useDispatch();
  const recurrentPeriod = useSelector(recurrentPeriodSelector);
  const recurrentEndDate = useSelector(recurrentEndDateSelector);
  const errors = useSelector(errorsSelector);
  const delivery = useSelector(deliverySelector);
  const [isDialogOpen, setDialogOpen] = useState(false);

  useEffect(() => {
    if (eventStartDate && !recurrentEndDate) {
      props.handleOnChange('recurrentEndDate', dayjs(eventStartDate).add(1, 'year').toDate().getTime());
    }
  }, [eventStartDate]);

  useEffect(() => {
    if (!eventStartDate || !eventEndDate) {
      return;
    }

    validateField(
      {
        fieldName: 'recurrentPeriod',
        fieldValue: recurrentPeriod,
      },
      (params) => dispatch(setErrorAction(params)),
      {
        duration: Math.ceil(dayjs.duration(dayjs(eventEndDate).diff(dayjs(eventStartDate))).asDays()),
      },
    );
  }, [eventStartDate, eventEndDate, recurrentPeriod]);

  useEffect(() => {
    if (!eventEndDate || recurrentPeriod === NON_RECURRING) {
      return;
    }

    validateField(
      {
        fieldName: 'recurrentEndDate',
        fieldValue: recurrentEndDate,
      },
      (params) => dispatch(setErrorAction(params)),
      {
        recurrentPeriod,
        timeDifference: Math.floor(dayjs.duration(dayjs(recurrentEndDate).diff(dayjs(eventEndDate))).asDays()),
        daysInMonth: dayjs(eventEndDate).daysInMonth(),
      },
    );
  }, [eventEndDate, recurrentPeriod, recurrentEndDate]);

  useEffect(() => {
    if (delivery === EXTERNAL_ENDPOINT) {
      dispatch(
        updateLiveEventFormAction({
          recurrentPeriod: NON_RECURRING,
          recurrentEndDate: 0,
        }),
      );
    }
  }, [delivery]);

  const getRecurrentPeriod = (startTime, endTime) => {
    if (!startTime || !endTime) return [];

    const labels = {
      [NON_RECURRING]: 'Non recurring event',
      [DAY]: 'Day',
      [WEEK]: `Week on ${dayjs(startTime).format('dddd')}`,

      [MONTH]: `Month on the ${weekOfMonth[Math.ceil(dayjs(startTime).date() / 7)]} ${dayjs(startTime).format('dddd')}`,
    };

    const duration = Math.ceil(dayjs.duration(dayjs(endTime).diff(dayjs(startTime))).asDays());

    if (duration > 1 && duration < 7) {
      return [
        {
          value: NON_RECURRING,
          label: labels[NON_RECURRING],
        },
        {
          value: WEEK,
          label: labels[WEEK],
        },
        {
          value: MONTH,
          label: labels[MONTH],
        },
      ];
    }

    if (duration > 7 && duration < dayjs(endTime).daysInMonth()) {
      return [
        {
          value: NON_RECURRING,
          label: labels[NON_RECURRING],
        },
        {
          value: MONTH,
          label: labels[MONTH],
        },
      ];
    }

    return [
      {
        value: NON_RECURRING,
        label: labels[NON_RECURRING],
      },
      {
        value: DAY,
        label: labels[DAY],
      },
      {
        value: WEEK,
        label: labels[WEEK],
      },
      {
        value: MONTH,
        label: labels[MONTH],
      },
    ];
  };

  const getMinEndDate = (endDate, recurrentPeriod$) => {
    const daysInMonth = ![DAY, WEEK].includes(recurrentPeriod$) ? dayjs(endDate).daysInMonth() : 1;
    const addType = recurrentPeriod$ === WEEK ? 'week' : 'day';

    return dayjs(endDate).add(daysInMonth, addType).endOf('day').toDate().getTime();
  };

  const handleChangeRecurrent = (value) => {
    if (value === NON_RECURRING) {
      return setDialogOpen(true);
    }

    return props.handleOnChange('recurrentPeriod', value);
  };

  const handleConfirm = () => {
    props.handleOnChange('recurrentPeriod', NON_RECURRING);
    setDialogOpen(false);
  };

  return (
    <FormGroup>
      <FormRow label="Repeat every">
        <FormControl fullWidth size={size}>
          <InputLabel size={size} required>
            Required
          </InputLabel>
          <Select
            size={size}
            error={errors.recurrentPeriod && !errors.recurrentPeriod?.isValid}
            helperText={errors.recurrentPeriod?.message}
            disabled={props.disabled}
            defaultValue={NON_RECURRING}
            label="Required"
            required
            value={recurrentPeriod}
            onChange={(e) => handleChangeRecurrent(e.target.value)}
          >
            {getRecurrentPeriod(eventStartDate, eventEndDate).map(({ label, value }) => (
              <MenuItem key={value} value={value}>
                {label}
              </MenuItem>
            ))}
          </Select>
        </FormControl>
      </FormRow>
      {recurrentPeriod !== NON_RECURRING && (
        <FormRow label="End Date" tooltip="Add one or more sessions for this live event.">
          <DatePicker
            size={size}
            disabled={props.disabled}
            minDate={eventEndDate && recurrentPeriod ? dayjs(getMinEndDate(eventEndDate, recurrentPeriod)) : undefined}
            minDateMessage={errors.recurrentEndDate?.message}
            value={dayjs(recurrentEndDate)}
            onChange={(date) => props.handleOnChange('recurrentEndDate', date.endOf('day').toDate().getTime())}
            format="MM/DD/YYYY"
            slotProps={{
              textField: {
                required: true,
                placeholder: 'Enter End Date',
              },
            }}
          />
        </FormRow>
      )}
      {isDialogOpen && (
        <Dialog
          open={isDialogOpen}
          onClose={() => setDialogOpen(false)}
          aria-labelledby="alert-dialog-title"
          aria-describedby="alert-dialog-description"
        >
          <DialogTitle onClose={() => setDialogOpen(false)}>Recurring events</DialogTitle>
          <DialogContent>Are you sure you would like to cancel all future recurring events?</DialogContent>
          <DialogActions>
            <Button size="small" onClick={() => setDialogOpen(false)} variant="outlined">
              Cancel
            </Button>
            <Button size="small" autoFocus onClick={() => handleConfirm()}>
              Confirm
            </Button>
          </DialogActions>
        </Dialog>
      )}
    </FormGroup>
  );
}

Recurring.propTypes = {
  handleOnChange: PropTypes.func.isRequired,
  eventStartDate: PropTypes.number,
  eventEndDate: PropTypes.number,
  disabled: PropTypes.bool.isRequired,
};

export default Recurring;
