import { MouseEvent, useEffect, useState } from 'react';

import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import { useAtomValue } from 'jotai';
import { and, cond, equals } from 'ramda';
import { useTranslation } from 'react-i18next';

import AccessTimeIcon from '@mui/icons-material/AccessTime';
import { Button, FormHelperText, Popover, Typography } from '@mui/material';
import makeStyles from '@mui/styles/makeStyles';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';

import { dateTimeFormat, useLocaleDateTimeFormat } from '@centreon/ui';
import { userAtom } from '@centreon/ui-context';

import {
  CustomTimePeriod,
  CustomTimePeriodProperty,
} from '../../../Details/tabs/Graph/models';
import {
  labelCompactTimePeriod,
  labelEndDate,
  labelEndDateGreaterThanStartDate,
  labelFrom,
  labelStartDate,
  labelTo,
} from '../../../translatedLabels';

import DateTimePickerInput from './DateTimePickerInput';

interface AcceptDateProps {
  date: Date;
  property: CustomTimePeriodProperty;
}

interface Props {
  acceptDate: (props: AcceptDateProps) => void;
  customTimePeriod: CustomTimePeriod;
  isCompact: boolean;
}

dayjs.extend(isSameOrAfter);
dayjs.extend(utc);
dayjs.extend(timezone);

const useStyles = makeStyles((theme) => ({
  button: {
    height: '100%',
    padding: theme.spacing(0, 0.5),
  },
  buttonContent: {
    alignItems: 'center',
    columnGap: theme.spacing(1),
    display: 'grid',
    gridTemplateColumns: 'min-content auto',
  },
  compactFromTo: {
    display: 'flex',
    flexDirection: 'column',
    padding: theme.spacing(0.5, 0, 0.5, 0),
  },
  date: {
    display: 'flex',
  },
  dateLabel: {
    display: 'flex',
    flex: 1,
    paddingRight: 4,
  },
  error: {
    textAlign: 'center',
  },
  fromTo: {
    alignItems: 'center',
    columnGap: theme.spacing(0.5),
    display: 'grid',
    gridTemplateColumns: 'repeat(2, auto)',
  },
  minimalFromTo: {
    display: 'grid',
    gridTemplateRows: 'repeat(2, min-content)',
    rowGap: theme.spacing(0.3),
  },
  minimalPickers: {
    alignItems: 'center',
    columnGap: theme.spacing(1),
    display: 'grid',
    gridTemplateColumns: 'min-content auto',
  },
  pickerText: {
    cursor: 'pointer',
    lineHeight: '1.2',
  },
  pickers: {
    alignItems: 'center',
    columnGap: theme.spacing(0.5),
    display: 'grid',
    gridTemplateColumns: `minmax(${theme.spacing(15)}, ${theme.spacing(
      17,
    )}px) min-content minmax(${theme.spacing(15)}, ${theme.spacing(17)})`,
  },
  popover: {
    display: 'grid',
    gridTemplateRows: 'auto auto auto',
    justifyItems: 'center',
    padding: theme.spacing(1, 2),
    rowGap: theme.spacing(1),
  },
  timeContainer: {
    alignItems: 'center',
    display: 'flex',
    flexDirection: 'row',
  },
}));

const CustomTimePeriodPickers = ({
  customTimePeriod,
  acceptDate,
  isCompact: isMinimalWidth,
}: Props): JSX.Element => {
  const classes = useStyles(isMinimalWidth);
  const { t } = useTranslation();
  const [anchorEl, setAnchorEl] = useState<Element | null>(null);
  const [start, setStart] = useState<Date>(customTimePeriod.start);
  const [end, setEnd] = useState<Date>(customTimePeriod.end);
  const { format } = useLocaleDateTimeFormat();
  const { locale } = useAtomValue(userAtom);

  const isInvalidDate = ({ startDate, endDate }): boolean =>
    dayjs(startDate).isSameOrAfter(dayjs(endDate), 'minute');

  const changeDate = ({ property, date }): void => {
    const currentDate = customTimePeriod[property];

    cond([
      [
        (): boolean => equals(CustomTimePeriodProperty.start, property),
        (): void => setStart(date),
      ],
      [
        (): boolean => equals(CustomTimePeriodProperty.end, property),
        (): void => setEnd(date),
      ],
    ])();

    if (
      dayjs(date).isSame(dayjs(currentDate)) ||
      isInvalidDate({ endDate: end, startDate: start }) ||
      !dayjs(date).isValid()
    ) {
      return;
    }
    acceptDate({
      date,
      property,
    });
  };

  useEffect(() => {
    if (
      and(
        dayjs(customTimePeriod.start).isSame(dayjs(start), 'minute'),
        dayjs(customTimePeriod.end).isSame(dayjs(end), 'minute'),
      )
    ) {
      return;
    }
    setStart(customTimePeriod.start);
    setEnd(customTimePeriod.end);
  }, [customTimePeriod.start, customTimePeriod.end]);

  const openPopover = (event: MouseEvent): void => {
    setAnchorEl(event.currentTarget);
  };

  const closePopover = (): void => {
    setAnchorEl(null);
  };

  const displayPopover = Boolean(anchorEl);

  const error = isInvalidDate({ endDate: end, startDate: start });

  return (
    <>
      <Button
        aria-label={t(labelCompactTimePeriod)}
        className={classes.button}
        color="primary"
        data-testid={labelCompactTimePeriod}
        variant="outlined"
        onClick={openPopover}
      >
        <div className={classes.buttonContent}>
          <AccessTimeIcon />
          <div
            className={isMinimalWidth ? classes.compactFromTo : classes.fromTo}
          >
            <div className={classes.timeContainer}>
              <div className={classes.dateLabel}>
                <Typography variant="caption">{t(labelFrom)}:</Typography>
              </div>
              <div className={classes.date}>
                <Typography variant="caption">
                  {format({
                    date: customTimePeriod.start,
                    formatString: dateTimeFormat,
                  })}
                </Typography>
              </div>
            </div>
            <div className={classes.timeContainer}>
              <div className={classes.dateLabel}>
                <Typography variant="caption">{t(labelTo)}:</Typography>
              </div>
              <div className={classes.date}>
                <Typography variant="caption">
                  {format({
                    date: customTimePeriod.end,
                    formatString: dateTimeFormat,
                  })}
                </Typography>
              </div>
            </div>
          </div>
        </div>
      </Button>
      <Popover
        anchorEl={anchorEl}
        anchorOrigin={{
          horizontal: 'center',
          vertical: 'top',
        }}
        open={displayPopover}
        transformOrigin={{
          horizontal: 'center',
          vertical: 'top',
        }}
        onClose={closePopover}
      >
        <LocalizationProvider
          adapterLocale={locale.substring(0, 2)}
          dateAdapter={AdapterDayjs}
        >
          <div className={classes.popover}>
            <div>
              <Typography>{t(labelFrom)}</Typography>
              <div aria-label={t(labelStartDate)}>
                <DateTimePickerInput
                  changeDate={changeDate}
                  date={start}
                  maxDate={customTimePeriod.end}
                  property={CustomTimePeriodProperty.start}
                  setDate={setStart}
                />
              </div>
            </div>
            <div>
              <Typography>{t(labelTo)}</Typography>
              <div aria-label={t(labelEndDate)}>
                <DateTimePickerInput
                  changeDate={changeDate}
                  date={end}
                  minDate={customTimePeriod.start}
                  property={CustomTimePeriodProperty.end}
                  setDate={setEnd}
                />
              </div>
            </div>

            {error && (
              <FormHelperText error className={classes.error}>
                {t(labelEndDateGreaterThanStartDate)}
              </FormHelperText>
            )}
          </div>
        </LocalizationProvider>
      </Popover>
    </>
  );
};

export default CustomTimePeriodPickers;
