import React, {
  ReactElement,
  useState,
  useEffect,
  useCallback,
  ChangeEvent,
  FocusEvent,
} from 'react';
import parse from 'date-fns/fp/parse';
import isValid from 'date-fns/fp/isValid';
import formatDate from 'date-fns/fp/format';
import css from '../../utils/css';

import Input from '../Input';
import Dropdown from '../Dropdown';
import Calendar from './Calendar';
import { IconName } from '../Icon';
import { DatePickerContainer } from './StyledDatePicker';

import { CommonProps } from '../common';

export interface MonthPickerProps extends CommonProps {
  /**
   * Specify the [automated assistance](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) in filling out form field values by the browser.
   */
  autoComplete?: string;
  /**
   * Whether the picker is disabled.
   */
  disabled?: boolean;
  /**
   * Month and Year format (ex: MM/yyyy). Following date-fns's format (https://date-fns.org/v2.16.1/docs/format).
   */
  format?: string;
  /**
   * Whether the input is invalid.
   */
  invalid?: boolean;
  /**
   * The latest date user can select.
   */
  maxDate?: Date;
  /**
   * The earliest date user can select.
   */
  minDate?: Date;
  /**
   * Name of <input> element, is used to refer to the form data for submission.
   */
  name?: string;
  /**
   * onBlur event handler.
   */
  onBlur?: (e: FocusEvent) => void;
  /**
   * onChange event handler.
   */
  onChange?: (value: string) => void;
  /**
   * Placeholder text in the absence of any value.
   */
  placeholder?: string;
  /**
   * Name of Icon or an Icon element to render on the left side of the input, before the user's cursor.
   */
  prefix?: IconName | ReactElement;
  /**
   * Whether or not Input's value is read only.
   */
  readonly?: boolean;
  /**
   * The size of the input box.
   */
  size?: 'small' | 'medium' | 'large';
  /**
   * Current selected month which must be in correct format. If value is invalid, it will be skipped.
   */
  value?: string;
}

const DEFAULT_MONTH_FORMAT = 'MM/yyyy';

const MonthPicker = ({
  autoComplete,
  value,
  onChange,
  onBlur,
  minDate,
  maxDate,
  size = 'medium',
  invalid = false,
  placeholder,
  prefix,
  disabled = false,
  format = DEFAULT_MONTH_FORMAT,
  readonly,
  name,
  id,
  className,
  style,
  sx = {},
  'data-test-id': dataTestId,
}: MonthPickerProps): ReactElement => {
  const [open, setOpen] = useState<boolean>(false);
  const [selectedMonth, setSelectedMonth] = useState<Date>();
  const isValidMonth = isValid(selectedMonth);
  const dateFormat = format !== undefined ? format : DEFAULT_MONTH_FORMAT;

  const openCalendar = useCallback(() => setOpen(true), [setOpen]);
  const closeCalendar = useCallback(() => setOpen(false), [setOpen]);

  const onSelectMonth = useCallback(
    (newDate: Date): void => {
      if (onChange !== undefined) {
        const formattedDate = formatDate(dateFormat, newDate);
        onChange(formattedDate);
      }
      closeCalendar();
    },
    [dateFormat, onChange, closeCalendar]
  );

  const onInputChange = useCallback(
    (e: ChangeEvent): void => {
      const target = e.target as HTMLInputElement;
      if (target.value !== undefined && onChange !== undefined) {
        onChange(target.value);
      }
    },
    [onChange]
  );

  useEffect(() => {
    setSelectedMonth(
      parse(new Date(), dateFormat, value !== undefined ? value : '')
    );
  }, [dateFormat, setSelectedMonth, value]);

  const dateInput = (
    <Input
      suffix="calendar"
      value={value !== undefined ? value : ''}
      placeholder={placeholder === undefined ? format : placeholder}
      size={size}
      invalid={invalid}
      prefix={prefix}
      disabled={disabled}
      readonly={readonly}
      onChange={onInputChange}
      onFocus={openCalendar}
      onBlur={onBlur}
      id={id}
      name={name}
      autoComplete={autoComplete}
    />
  );

  const calendar = (
    <Calendar.Month
      maxDate={maxDate}
      minDate={minDate}
      onSelectMonth={onSelectMonth}
      selectedMonth={isValidMonth === true ? selectedMonth : undefined}
    />
  );

  return (
    <DatePickerContainer
      className={className}
      style={{ ...style, ...css(sx) }}
      data-test-id={dataTestId}
    >
      <Dropdown
        target={dateInput}
        content={calendar}
        open={open}
        onClose={closeCalendar}
        style={{ minWidth: 'unset' }}
      />
    </DatePickerContainer>
  );
};

export default MonthPicker;
