import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { useToggle } from 'react-use';
import clsx from 'clsx';
import dayjs from 'dayjs';
import isEqual from 'lodash/isEqual';

import DatePickerReact from 'react-datepicker';
import Button from '@mui/material/Button';
import Menu from '@mui/material/Menu';
import IconButton from '@mui/material/IconButton';
import Divider from '@mui/material/Divider';
import Grid from '@mui/material/Grid';
import InputLabel from '@mui/material/InputLabel';
import Fade from '@mui/material/Fade';

import { ASSETS_URL } from '../../../consts/common';
import { CustomIcon } from '../../custom-icon';
import { DateRange, HeaderDatePicker, SelectMMYY } from './parts';

import createClasses from './styles';

const anchorElTopAddition = -42;

export type DateValues = Date | string | null;
export interface DatesValues {
  startDate: DateValues;
  endDate: DateValues;
}

export interface DatePickerProps {
  input: {
    value: DatesValues;
    onChange: (values: DatesValues) => void;
  };
  label?: string;
  rangeSection?: boolean;
  calendarSection?: boolean;
  triggerResetDatePicker?: boolean;
  minDate?: Date;
  maxDate?: Date;
  placeholder?: string;
  /**
   * If `true`, the popup will be opened initially.
   * @default false
   */
  openOnce?: boolean;
  /**
   * Custom class name in case you need to add custom styles to the component.
   */
  className?: string;
  /**
   * Default classes overrides.
   */
  classes?: Partial<ReturnType<typeof createClasses>>;
}

export const defaultDateObj: DatesValues = { startDate: null, endDate: null };

const DatePicker = (props: DatePickerProps) => {
  const {
    label = '',
    rangeSection,
    calendarSection = true,
    input,
    triggerResetDatePicker,
    minDate,
    maxDate,
    placeholder,
    openOnce = false,
    className,
    classes
  } = props;

  const styles = createClasses();

  const [startDate, setStartDate] = useState(
    input.value.startDate === null ? null : new Date(input.value.startDate)
  );

  const [endDate, setEndDate] = useState(
    input.value.endDate === null ? null : new Date(input.value.endDate)
  );
  const [isOpen, setIsOpen] = useState(false);
  const [selectDate, setSelectDate] = useState<Date | undefined>();
  const [isOpenMMYY, setIsOpenMMYY] = useState(false);

  const toggleMMYY = useCallback(() => setIsOpenMMYY(!isOpenMMYY), [isOpenMMYY]);

  const buttonList = useRef<HTMLDivElement>(null);

  const [fieldFocus, toggleFieldFocus] = useToggle(false);

  useEffect(() => {
    if (input.value.startDate === null && input.value.endDate === null) {
      setStartDate(null);
      setEndDate(null);
    } else if (input.value.startDate && input.value.endDate) {
      setStartDate(new Date(input.value.startDate));
      setEndDate(new Date(input.value.endDate));
    }
    // eslint-disable-next-line
  }, [triggerResetDatePicker]);

  useEffect(() => {
    const formattedStartDate = dayjs(startDate).format('MM/DD/YYYY');
    const formattedEndDate = dayjs(endDate).format('MM/DD/YYYY');
    if (
      startDate !== null &&
      endDate !== null &&
      !isEqual({ startDate: formattedStartDate, endDate: formattedEndDate }, input.value)
    ) {
      input.onChange({
        startDate: formattedStartDate,
        endDate: formattedEndDate
      });
    } else if (
      startDate === null &&
      endDate === null &&
      input.value.startDate !== null &&
      input.value.endDate !== null
    ) {
      input.onChange(defaultDateObj);
    }
    // eslint-disable-next-line
  }, [endDate]);

  useEffect(() => {
    setSelectDate(startDate || new Date());
    // eslint-disable-next-line
  }, []);

  const handleOpen = useCallback(
    (newState?: boolean | Event) => {
      if (newState && typeof newState !== 'boolean') {
        setAnchorEl((newState?.currentTarget as HTMLElement)?.parentElement);
      }
      toggleFieldFocus(true);
      setIsOpen(typeof newState === 'boolean' ? newState : !isOpen);
    },
    [isOpen, toggleFieldFocus]
  );

  const handleClear = useCallback(() => {
    input.onChange(defaultDateObj);
    setStartDate(null);
    setEndDate(null);
  }, [input]);

  const onChange = useCallback((dates: [start: Date, end: Date]) => {
    const [start, end] = dates;
    setSelectDate(start);
    setStartDate(start);
    setEndDate(end);
  }, []);

  const handleMenuClose = useCallback(() => {
    setIsOpen(false);
    setAnchorEl(null);
    setIsOpenMMYY(false);
  }, []);

  const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);

  const menuRef = useRef<HTMLUListElement>(null);
  const [menuSizes, setMenuSizes] = useState({ width: 0, height: 0 });
  useEffect(() => {
    setMenuSizes({
      width: menuRef.current?.clientWidth || 0,
      height: menuRef.current?.clientHeight || 0
    });
  }, [anchorEl]);

  useEffect(() => {
    if (openOnce) {
      setAnchorEl(buttonList?.current as HTMLElement);
      setIsOpen(true);
    }
  }, [openOnce]);

  return (
    <>
      <InputLabel className={clsx(styles.inputLabel, classes?.inputLabel, className)}>
        {label}
        <Grid ref={buttonList}>
          <HeaderDatePicker
            placeholder={placeholder}
            handleOpen={handleOpen}
            handleClear={handleClear}
            startDate={startDate}
            endDate={endDate}
            setStartDate={setStartDate}
            setEndDate={setEndDate}
            open={isOpen}
            id={label}
            fieldFocus={fieldFocus}
            toggleFieldFocus={toggleFieldFocus}
          />
        </Grid>
      </InputLabel>

      <Menu
        anchorEl={anchorEl}
        open={!!anchorEl}
        anchorPosition={{
          left: 0,
          top: 60
        }}
        data-testid="popup"
        transformOrigin={{ vertical: -50, horizontal: 0 }}
        className={clsx(styles.calendarMenu, classes?.calendarMenu)}
        MenuListProps={{
          ref: menuRef,
          className: clsx(styles.menuList, classes?.menuList),
          // eslint-disable-next-line @typescript-eslint/ban-ts-comment
          // @ts-ignore
          component: 'div'
        }}
        PaperProps={{
          className: classes?.menuPaper,
          style: {
            transform: `translate(0px ,${anchorElTopAddition}px)`
          }
        }}
        onClose={handleMenuClose}
      >
        {!isOpenMMYY ? (
          <Fade in={!isOpenMMYY} timeout={700}>
            <Grid>
              {rangeSection && (
                <>
                  <DateRange
                    setStartDate={setStartDate}
                    setEndDate={setEndDate}
                    startDate={startDate}
                    endDate={endDate}
                    setSelectDate={setSelectDate}
                  />
                  <Divider />
                </>
              )}
              {calendarSection && (
                <DatePickerReact
                  minDate={minDate}
                  maxDate={maxDate}
                  inline
                  selected={selectDate || startDate}
                  onChange={onChange}
                  startDate={startDate}
                  endDate={endDate}
                  selectsRange
                  renderCustomHeader={headerProps => {
                    const {
                      date,
                      decreaseMonth,
                      increaseMonth,
                      prevMonthButtonDisabled,
                      nextMonthButtonDisabled
                    } = headerProps;

                    return (
                      <Grid
                        className={clsx(
                          styles.customHeaderContainer,
                          classes?.customHeaderContainer
                        )}
                        container
                        justifyContent="space-between"
                      >
                        <Grid item>
                          <Button
                            color="primary"
                            variant="text"
                            onClick={toggleMMYY}
                            className={clsx(styles.monthButtonText, classes?.monthButtonText)}
                            endIcon={
                              <CustomIcon
                                color="inherit"
                                className={clsx(styles.arrow, classes?.arrow)}
                                src={`${ASSETS_URL}/icons/icon_arrow.svg`}
                              />
                            }
                          >
                            {`${dayjs(date).format('MMMM')}  ${dayjs(date).format('YYYY')}`}
                          </Button>
                        </Grid>
                        <Grid item>
                          <IconButton
                            className={clsx(styles.arrowIconButton, classes?.arrowIconButton)}
                            onClick={decreaseMonth}
                            disabled={prevMonthButtonDisabled}
                            size="large"
                          >
                            <CustomIcon
                              color="inherit"
                              className={clsx(styles.arrow, classes?.arrow)}
                              src={`${ASSETS_URL}/icons/icon_arrow.svg`}
                              style={{
                                transform: `rotate(${90}deg)`
                              }}
                            />
                          </IconButton>
                          <IconButton
                            className={clsx(styles.arrowIconButton, classes?.arrowIconButton)}
                            onClick={increaseMonth}
                            disabled={nextMonthButtonDisabled}
                            size="large"
                          >
                            <CustomIcon
                              color="inherit"
                              className={clsx(styles.arrow, classes?.arrow)}
                              src={`${ASSETS_URL}/icons/icon_arrow.svg`}
                              style={{
                                transform: `rotate(${-90}deg)`
                              }}
                            />
                          </IconButton>
                        </Grid>
                      </Grid>
                    );
                  }}
                />
              )}
            </Grid>
          </Fade>
        ) : (
          <SelectMMYY
            width={menuSizes.width}
            height={menuSizes.height}
            setIsOpenMMYY={setIsOpenMMYY}
            isOpenMMYY={isOpenMMYY}
            setSelectDate={setSelectDate}
            minDate={minDate}
            maxDate={maxDate}
          />
        )}
      </Menu>
    </>
  );
};

DatePicker.defaultProps = {
  label: '',
  placeholder: '',
  minDate: '',
  maxDate: '',
  rangeSection: true,
  calendarSection: true,
  triggerResetDatePicker: false
};

const m = memo(DatePicker);
export { m as DatePicker };
