import { type FC, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { Button, Divider, Popover, Stack } from '@mui/material';
import { StaticDatePicker } from '@mui/x-date-pickers-v6';
import { IconChevronLeft, IconChevronRight } from '@tabler/icons-react';
import { addDays, startOfDay } from 'date-fns';

import { Periods, SelectedDate } from '../../types';
import { recognizePeriod } from '../../utils';
import CustomCalendarHeader from '../CustomCalendarHeader';
import PickerDay from '../PickerDay';
import YearsSelector from '../YearsSelector';

import { type CustomRangeSelectorProps } from './types';

const CustomRangeSelector: FC<CustomRangeSelectorProps> = props => {
  const {
    anchorElement,
    fromDate,
    toDate,
    handleClose,
    handleFromDateChange,
    handleToDateChange,
    updatePeriodType,
    minMaxDatesDifference = 0,
  } = props;
  // IMPORTANT: after updating MUI-X date picker version, the expected type for the value props is Date
  // Since we used it to pass an array of dates, we need to use any as the type avoid type errors
  const [customDates, setCustomDates] = useState<any>([
    startOfDay(fromDate),
    startOfDay(toDate),
  ]);
  const { t } = useTranslation('material_hu_only');
  const [currentSelection, setCurrentSelection] = useState(SelectedDate.END);
  const [hoveredDate, setHoveredDate] = useState<Date | null>(null);

  const applyCustomDates = () => {
    const [start, end] = customDates;
    const onlyCompletedFromDate = start && end === null;
    if (onlyCompletedFromDate) {
      handleFromDateChange(start);
      handleToDateChange(start);
      updatePeriodType(Periods.DAILY);
    } else {
      handleFromDateChange(start);
      handleToDateChange(end);
      updatePeriodType(recognizePeriod(start, end));
    }
    handleClose();
  };

  const clearDates = () => {
    setCustomDates([null, null]);
    setCurrentSelection(SelectedDate.START);
  };

  const closeWithoutSaving = () => {
    handleClose();
    setCustomDates([fromDate, toDate]);
    setCurrentSelection(SelectedDate.END);
  };

  const handleRangeChange = (value: any) => {
    if (currentSelection === SelectedDate.START) {
      setCustomDates([value, value > customDates[1] ? value : customDates[1]]);
      setCurrentSelection(SelectedDate.END);
    } else {
      // In case the start date is not set, set it to the end date to avoid errors
      const dateAfterStart = value > customDates[0];
      setCustomDates(dateAfterStart ? [customDates[0], value] : [value, value]);
      setCurrentSelection(
        dateAfterStart ? SelectedDate.START : SelectedDate.END,
      );
    }
  };

  const selectableDates = (date: Date | null, range: number) => {
    if (!range) return null;
    return date ? addDays(date, range) : null;
  };

  useEffect(() => {
    setCustomDates([fromDate, toDate]);
  }, [fromDate, toDate]);

  // Clear hovered date when customDates changes
  useEffect(() => {
    setHoveredDate(null);
  }, [customDates]);

  return (
    <Popover
      open={Boolean(anchorElement)}
      anchorEl={anchorElement}
      onClose={closeWithoutSaving}
      anchorOrigin={{
        vertical: 'bottom',
        horizontal: 'center',
      }}
      transformOrigin={{
        vertical: 'top',
        horizontal: 'center',
      }}
    >
      <Stack>
        <StaticDatePicker
          displayStaticWrapperAs="desktop"
          views={['year', 'day']}
          slots={{
            leftArrowIcon: IconChevronLeft,
            rightArrowIcon: IconChevronRight,
            day: dayProps => (
              <PickerDay
                {...dayProps}
                customDates={customDates}
                currentSelection={currentSelection}
                hoveredDate={hoveredDate}
                setHoveredDate={setHoveredDate}
                setCustomDates={setCustomDates}
                setCurrentSelection={setCurrentSelection}
              />
            ),
            calendarHeader: CustomCalendarHeader,
          }}
          viewRenderers={{
            year: yearProps => (
              <YearsSelector
                customDates={customDates}
                setCustomDates={setCustomDates}
                {...yearProps}
              />
            ),
          }}
          openTo="day"
          value={customDates}
          referenceDate={fromDate}
          onChange={handleRangeChange}
          minDate={
            selectableDates(customDates[1], -minMaxDatesDifference) ?? undefined
          }
          maxDate={
            selectableDates(customDates[0], minMaxDatesDifference) ?? undefined
          }
          sx={{
            p: 2,
            backgroundColor: ({ palette }) =>
              palette.new.background.elements.default,
            '& .MuiDayCalendar-header': {
              backgroundColor: ({ palette }) =>
                palette.new.background.elements.default,
              borderBottom: ({ palette }) =>
                `1px solid ${palette.new.border.neutral.divider}`,
              mb: 0.5,
              '.MuiDayCalendar-weekDayLabel': {
                fontSize: 14,
                fontWeight: 600,
                color: ({ palette }) => palette.new.text.neutral.brand,
              },
            },
          }}
        />
        <Divider />
        <Stack
          sx={{
            alignItems: 'center',
            flexDirection: 'row',
            justifyContent: 'space-between',
            p: 3,
            py: 2,
          }}
        >
          <Button onClick={clearDates}>
            {t('date_period_selector.clear')}
          </Button>
          <Button
            variant="contained"
            onClick={applyCustomDates}
            disabled={customDates.every((date: any) => date === null)}
            sx={{ px: 6 }}
          >
            {t('date_period_selector.apply')}
          </Button>
        </Stack>
      </Stack>
    </Popover>
  );
};

export default CustomRangeSelector;
