// @flow
import React, { useCallback, useState, useEffect } from 'react';
import { injectIntl } from 'react-intl';
import { v4 } from 'uuid';
import type { InjectIntlProvidedProps } from 'react-intl';
import styled from 'styled-components';
import moment from 'moment';
import DayPicker from 'react-day-picker';
import type { DatepickerProps } from './datepicker.proptypes';
import { datePickerStyles } from './datepicker.css-rules';
import type { SpaceProps } from '../../mixins/spacing/spacing.proptypes';
import { Box } from '../../primitives/box';
import { TextInput } from '../../core/forms/text-input';
import { ClickOutside } from '../../core/behaviors';
import { Popper } from '../../core/overlays/popper';
import { Card } from '../../core/structures/card';
import { getPaletteColor } from '../../mixins/branding';

// we put the date picker styles here so it's specific to this instance rather than globally
const StyledBox = styled(Box)`
  && {
    ${datePickerStyles};
  }
`;

const PickerContainer = styled(Card)`
  border: 1px solid ${getPaletteColor('greyscale-light')};
  z-index: 100;
`;

type DatePickerProps = {|
  ...DatepickerProps,
  ...SpaceProps,
  ...InjectIntlProvidedProps,
|};

const intlDateFormat = {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
};

const datePickerInputId = (label: string) => {
  if (typeof label === 'string') return `Datepicker-input-${label}`;

  return `Datepicker-input-${v4()}`;
};

const supportedDateFormats = {
  'en-GB': 'DD/MM/YYYY',
  'en-CA': 'YYYY-MM-DD',
  'en-US': 'MM/DD/YYYY',
};

const localeMaskOptions = {
  'en-GB': {
    datePattern: ['d', 'm', 'Y'],
    delimiter: '/',
  },
  'en-CA': {
    datePattern: ['Y', 'm', 'd'],
    delimiter: '-',
  },
  'en-US': {
    datePattern: ['m', 'd', 'Y'],
    delimiter: '/',
  },
};

const maskOptions = (
  locale: string,
): {| datePattern: string[], delimiter: string |} => {
  return localeMaskOptions[locale] || localeMaskOptions['en-CA'];
};

const dateFormat = (locale: string): string => {
  return supportedDateFormats[locale] || supportedDateFormats['en-CA'];
};

export const Datepicker = injectIntl(
  ({
    intl,
    label,
    onChange,
    value,
    disabledDates = [],
    disableWeekends = false,
    disablePastDates = false,
    className,
    'data-qa': dataQa,
    'data-cy': dataCy,
    id,
    ...otherProps
  }: DatePickerProps) => {
    const [isCalendarVisible, setIsCalendarVisible] = useState<boolean>(false);
    const [inputText, setInputText] = useState<string>(
      value ? moment(value).format(dateFormat(intl.locale)) : '',
    );

    const [inputId] = useState(datePickerInputId(label));

    const handleDayClick = useCallback(
      (day: Date) => {
        onChange(day);
        setInputText(intl.formatDate(day, intlDateFormat));
        setIsCalendarVisible(false);
      },
      [onChange, intl],
    );

    useEffect(() => {
      if (supportedDateFormats[intl.locale]) {
        moment.locale(intl.locale);
      }
    }, [intl.locale]);

    const handleInputChange = useCallback(
      (text: string) => {
        setInputText(text);

        const date = moment(text, dateFormat(intl.locale));

        if (date.isValid()) {
          onChange(date.toDate());
        }
      },
      [onChange, intl.locale],
    );

    return (
      <StyledBox
        stacked="column"
        {...otherProps}
        data-cy={dataCy}
        data-qa={dataQa}
        id={id}
      >
        <ClickOutside onClickOutside={() => setIsCalendarVisible(false)}>
          <Popper
            reference={({ referenceProps, ref }) => (
              <>
                <TextInput
                  {...referenceProps}
                  id={inputId}
                  onRef={ref}
                  onFocus={() => setIsCalendarVisible(true)}
                  onChange={handleInputChange}
                  value={inputText}
                  label={label}
                  placeholder={dateFormat(intl.locale)}
                  mask
                  maskOptions={{
                    date: true,
                    ...maskOptions(intl.locale),
                  }}
                  className={className}
                />
              </>
            )}
            isVisible={isCalendarVisible}
            placement="bottom-start"
          >
            {({ ref, style }) => (
              <PickerContainer style={style} ref={ref}>
                <DayPicker
                  month={value}
                  selectedDays={value}
                  onDayClick={handleDayClick}
                  locale={intl.locale}
                  disabledDays={[
                    ...disabledDates,
                    { ...(disableWeekends ? { daysOfWeek: [0, 6] } : {}) },
                    { ...(disablePastDates ? { before: new Date() } : {}) },
                  ]}
                  showOutsideDays
                  enableOutsideDaysClick
                />
              </PickerContainer>
            )}
          </Popper>
        </ClickOutside>
      </StyledBox>
    );
  },
);

Datepicker.displayName = 'Datepicker';
