import React, { useCallback, useEffect, useMemo, useState } from 'react';
import type { Dispatch, SetStateAction } from 'react';
import dayjs from 'dayjs';
import { ReactSVG } from 'react-svg';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';
import Box from '@mui/material/Box';
import Divider from '@mui/material/Divider';
import clsx from 'clsx';
import Fade from '@mui/material/Fade';
import { ASSETS_URL } from '../../../../../consts/common';
import { generateYearsRange, getFullMonthName, getSmallMonthName, months } from './helpers';
import createClasses from './styles';

const years = generateYearsRange();

export interface SelectMMYYProps {
  setSelectDate: Dispatch<SetStateAction<Date | undefined>>;
  setIsOpenMMYY: Dispatch<SetStateAction<boolean>>;
  isOpenMMYY: boolean;
  minDate?: string | Date;
  maxDate?: string | Date;
  width: number;
  height: number;
}

// eslint-disable-next-line
const SelectMMYY = React.forwardRef<unknown, SelectMMYYProps>((props, ref) => {
  const { setIsOpenMMYY, isOpenMMYY, setSelectDate, minDate, maxDate, width, height } = props;

  const styles = createClasses();

  const [selectedMonth, setSelectedMonth] = useState(dayjs(new Date()).format('MM'));
  const [selectedYear, setSelectedYear] = useState(dayjs(new Date()).format('YYYY'));
  const [yearsEnabled, setYearsEnabled] = useState(!!(minDate || maxDate));
  const [monthEnabled, setMonthEnabled] = useState(!(minDate || maxDate));

  const formatMinDateYear = useMemo(
    () => (minDate ? dayjs(new Date(minDate)).format('YYYY') : undefined),
    [minDate]
  );
  const formatMinDateMonth = useMemo(
    () => (minDate ? dayjs(new Date(minDate)).format('MM') : undefined),
    [minDate]
  );
  const formatMaxDateYear = useMemo(
    () => (maxDate ? dayjs(new Date(maxDate)).format('YYYY') : undefined),
    [maxDate]
  );
  const formatMaxDateMonth = useMemo(
    () => (maxDate ? dayjs(new Date(maxDate)).format('MM') : undefined),
    [maxDate]
  );

  useEffect(() => {
    setSelectDate(new Date(`${selectedMonth}/01/${selectedYear}`));
    if (!minDate && !maxDate) {
      if (yearsEnabled) {
        setIsOpenMMYY(false);
      }
    }
    // eslint-disable-next-line
  }, [selectedYear]);

  useEffect(() => {
    setSelectDate(new Date(`${selectedMonth}/01/${selectedYear}`));
    if (minDate || maxDate) {
      if (monthEnabled) {
        setIsOpenMMYY(false);
      }
    }
    // eslint-disable-next-line
  }, [selectedMonth]);

  const handleMonth = useCallback(
    (month: string) => () => {
      if (!minDate && !maxDate) {
        setYearsEnabled(true);
        setSelectedMonth(month);
      } else {
        if (month === selectedMonth) {
          setIsOpenMMYY(false);
          return;
        }
        setSelectedMonth(month);
      }
    },
    [maxDate, minDate, selectedMonth, setIsOpenMMYY]
  );

  const handleYear = useCallback(
    (year: string) => {
      if (!minDate && !maxDate) {
        if (year === selectedYear) {
          setIsOpenMMYY(false);
          return;
        }
        setSelectedYear(year);
      } else {
        setMonthEnabled(true);
        setSelectedYear(year);
      }
    },
    [maxDate, minDate, selectedYear, setIsOpenMMYY]
  );

  const validationCheckedM = useCallback(
    (month: string) => {
      if ((minDate || maxDate) && monthEnabled) {
        if (
          formatMinDateYear &&
          formatMaxDateYear &&
          selectedYear > formatMinDateYear &&
          selectedYear < formatMaxDateYear
        ) {
          return true;
        }
        if (selectedYear === formatMinDateYear && selectedYear !== formatMaxDateYear) {
          if (Number(month) >= Number(formatMinDateMonth)) {
            return true;
          }
          return false;
        }
        if (selectedYear === formatMaxDateYear && selectedYear !== formatMinDateYear) {
          if (Number(month) <= Number(formatMaxDateMonth)) {
            return true;
          }
          return false;
        }
        if (selectedYear === formatMinDateYear && selectedYear === formatMaxDateYear) {
          if (
            Number(month) >= Number(formatMinDateMonth) &&
            Number(month) <= Number(formatMaxDateMonth)
          ) {
            return true;
          }
          return false;
        }
        return true;
      }
      return !!monthEnabled;
    },
    [
      formatMaxDateMonth,
      formatMaxDateYear,
      formatMinDateMonth,
      formatMinDateYear,
      maxDate,
      minDate,
      monthEnabled,
      selectedYear
    ]
  );

  const blockMM = useMemo(
    () =>
      months.map(month => (
        <Button
          key={month}
          data-testid={`month_${month}`}
          disabled={!validationCheckedM(month)}
          className={clsx([
            styles.item,
            (!monthEnabled || !validationCheckedM(month)) &&
              (!(month === selectedMonth) ? styles.disabledItem : styles.disabledSelectedItem),
            month === selectedMonth && monthEnabled && styles.selectedItem
          ])}
          onKeyDown={validationCheckedM(month) ? handleMonth(month) : undefined}
          onClick={validationCheckedM(month) ? handleMonth(month) : undefined}
        >
          <Typography className={styles.itemText}>{getSmallMonthName(month)}</Typography>
        </Button>
      )),
    [
      handleMonth,
      monthEnabled,
      selectedMonth,
      styles.disabledItem,
      styles.disabledSelectedItem,
      styles.item,
      styles.itemText,
      styles.selectedItem,
      validationCheckedM
    ]
  );

  const validationCheckedY = useCallback(
    (year: string) => {
      if (minDate || maxDate) {
        return !!(
          (minDate ? Number(year) >= Number(formatMinDateYear) : true) &&
          (maxDate ? Number(year) <= Number(formatMaxDateYear) : true)
        );
      }
      return !!yearsEnabled;
    },
    [formatMaxDateYear, formatMinDateYear, maxDate, minDate, yearsEnabled]
  );

  const blockYY = useMemo(
    () =>
      years.map(year => (
        <Button
          key={year}
          data-testid={`year_${year}`}
          disabled={!validationCheckedY(year)}
          className={clsx(
            styles.item,
            (!yearsEnabled || !validationCheckedY(year)) &&
              (!(year === selectedYear) ? styles.disabledItem : styles.disabledSelectedItem),
            year === selectedYear && yearsEnabled && styles.selectedItem
          )}
          onKeyDown={validationCheckedY(year) ? () => handleYear(year) : undefined}
          onClick={validationCheckedY(year) ? () => handleYear(year) : undefined}
        >
          <Typography className={clsx(styles.itemText)}>{year}</Typography>
        </Button>
      )),
    [
      handleYear,
      selectedYear,
      styles.disabledItem,
      styles.disabledSelectedItem,
      styles.item,
      styles.itemText,
      styles.selectedItem,
      validationCheckedY,
      yearsEnabled
    ]
  );

  const handleChangeOpenState = useCallback(() => {
    setIsOpenMMYY(!isOpenMMYY);
  }, [isOpenMMYY, setIsOpenMMYY]);

  return (
    <Fade in={isOpenMMYY} timeout={200}>
      <Box width={width} height={height}>
        <Box pt={2} px={2} pb={2}>
          <Button
            color="primary"
            variant="text"
            data-testid="changeStateButton"
            onClick={handleChangeOpenState}
            className={styles.monthButtonText}
            endIcon={
              <ReactSVG
                size="16px"
                src={`${ASSETS_URL}/icons/icon_arrow.svg`}
                className={styles.arrow}
              />
            }
          >
            {getFullMonthName(selectedMonth)} {selectedYear}
          </Button>
          <Box className={styles.itemsContainer}>{maxDate || minDate ? blockMM : blockYY}</Box>
        </Box>
        <Divider />
        <Box p={2} className={styles.itemsContainer}>
          {maxDate || minDate ? blockYY : blockMM}
        </Box>
      </Box>
    </Fade>
  );
});

SelectMMYY.defaultProps = {
  minDate: '',
  maxDate: ''
};

export default SelectMMYY;
