import React, {
  ReactElement,
  useState,
  useEffect,
  useCallback,
  ChangeEvent,
  FocusEvent,
} from 'react';
import parseWithOptions from 'date-fns/fp/parseWithOptions';
import isValid from 'date-fns/fp/isValid';
import formatDateWithOptions from 'date-fns/fp/formatWithOptions';
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 WeekPickerProps 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;
  /**
   * Week format. Following date-fns's format (https://date-fns.org/v2.16.1/docs/format).
   */
  format?: string;
  /**
   * Whether the input is invalid.
   */
  invalid?: boolean;
  /**
   * Name of <input> element, is used to refer to the form data for submission.
   */
  name?: string;
  /**
   * Blur 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 date which must be in correct format. If value is invalid, it will be skipped.
   */
  value?: string;
}

const WeekPicker = ({
  autoComplete,
  value,
  onChange,
  onBlur,
  size = 'medium',
  invalid = false,
  placeholder,
  prefix,
  disabled = false,
  format = "'Week' ww', 'YYYY",
  readonly,
  name,
  id,
  className,
  style,
  sx = {},
  'data-test-id': dataTestId,
}: WeekPickerProps): ReactElement => {
  const [open, setOpen] = useState<boolean>(false);
  const [
    selectedFirstDateOfWeek,
    setSelectedFirstDateOfWeek,
  ] = useState<Date>();
  const isValidDate = isValid(selectedFirstDateOfWeek);

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

  const onSelectFirstDateOfWeek = useCallback(
    (newDate: Date): void => {
      if (onChange !== undefined) {
        const formattedDate = formatDateWithOptions(
          { useAdditionalWeekYearTokens: true },
          format,
          newDate
        );

        onChange(formattedDate);
      }
      closeCalendar();
    },
    [format, 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(() => {
    setSelectedFirstDateOfWeek(
      parseWithOptions(
        { useAdditionalWeekYearTokens: true },
        new Date(),
        format,
        value !== undefined ? value : ''
      )
    );
  }, [format, setSelectedFirstDateOfWeek, 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}
      onBlur={onBlur}
      onFocus={openCalendar}
      id={id}
      name={name}
      autoComplete={autoComplete}
    />
  );

  const calendar = (
    <Calendar.Week
      selectedFirstDateOfWeek={
        isValidDate === true ? selectedFirstDateOfWeek : undefined
      }
      onSelectFirstDateOfWeek={onSelectFirstDateOfWeek}
    />
  );

  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 WeekPicker;
