import { clsx } from 'clsx';
import { PureComponent, createRef } from 'react';
import '@transferwise/formatting';
import { moveToWithinRange } from '../common/dateUtils/moveToWithinRange/moveToWithinRange.mjs';
import { isWithinRange } from '../common/dateUtils/isWithinRange/isWithinRange.mjs';
import { withInputAttributes } from '../inputs/contexts.mjs';
import { OverlayIdProvider } from '../provider/overlay/OverlayIdProvider.mjs';
import DateTrigger from './dateTrigger/DateTrigger.mjs';
import DayCalendar from './dayCalendar/DayCalendar.mjs';
import { getStartOfDay } from './getStartOfDay/getStartOfDay.mjs';
import MonthCalendar from './monthCalendar/MonthCalendar.mjs';
import YearCalendar from './yearCalendar/YearCalendar.mjs';
import { jsxs, jsx } from 'react/jsx-runtime';
import { MonthFormat } from '../common/propsValues/monthFormat.mjs';
import { Breakpoint } from '../common/propsValues/breakpoint.mjs';
import ResponsivePanel from '../common/responsivePanel/ResponsivePanel.mjs';
import { Size } from '../common/propsValues/size.mjs';
import { Position } from '../common/propsValues/position.mjs';

class DateLookup extends PureComponent {
  static defaultProps = {
    value: null,
    min: null,
    max: null,
    size: Size.MEDIUM,
    placeholder: '',
    label: '',
    monthFormat: MonthFormat.LONG,
    disabled: false,
    clearable: false
  };
  element = /*#__PURE__*/createRef();
  dropdown = /*#__PURE__*/createRef();
  constructor(props) {
    super(props);
    this.state = {
      selectedDate: getStartOfDay(props.value),
      originalDate: null,
      min: getStartOfDay(props.min),
      max: getStartOfDay(props.max),
      viewMonth: (props.value || new Date()).getMonth(),
      viewYear: (props.value || new Date()).getFullYear(),
      open: false,
      mode: 'day',
      isMobile: false
    };
  }
  static getDerivedStateFromProps(props, state) {
    const propsSelected = getStartOfDay(props.value);
    const propsMin = getStartOfDay(props.min);
    const propsMax = getStartOfDay(props.max);
    const hasSelectedChanged = state.selectedDate?.getTime() !== propsSelected?.getTime();
    const hasMinChanged = state.min?.getTime() !== propsMin?.getTime();
    const hasMaxChanged = state.max?.getTime() !== propsMax?.getTime();
    if (hasSelectedChanged || hasMinChanged || hasMaxChanged) {
      const selectedDate = hasSelectedChanged ? propsSelected : state.selectedDate;
      const min = hasMinChanged ? propsMin : state.min;
      const max = hasMaxChanged ? propsMax : state.max;
      if (selectedDate && !isWithinRange(selectedDate, min, max)) {
        props.onChange(moveToWithinRange(selectedDate, min, max));
        return null;
      }
      const viewDateThatIsWithinRange = selectedDate || (min || max) && moveToWithinRange(new Date(), min, max) || new Date();
      const viewMonth = viewDateThatIsWithinRange.getMonth();
      const viewYear = viewDateThatIsWithinRange.getFullYear();
      return {
        selectedDate,
        min,
        max,
        viewMonth,
        viewYear
      };
    }
    return null;
  }
  componentDidUpdate(previousProps) {
    if (this.props.value?.getTime() !== previousProps.value?.getTime() && this.state.open) {
      this.focusOn('.active');
    }
    const mediaQuery = window.matchMedia(`(max-width: ${Breakpoint.SMALL}px)`);
    this.setState({
      isMobile: mediaQuery.matches
    });
  }
  componentWillUnmount() {
    // Prevents memory leak by cleaning state.
    this.setState = () => {};
  }
  open = () => {
    const {
      onFocus
    } = this.props;
    this.setState({
      open: true,
      mode: 'day'
    });
    if (onFocus) {
      onFocus();
    }
  };
  discard = () => {
    const {
      originalDate
    } = this.state;
    if (originalDate !== null) {
      this.props.onChange(originalDate);
    }
    this.close();
  };
  close = () => {
    const {
      onBlur
    } = this.props;
    this.setState({
      open: false,
      originalDate: null
    });
    if (onBlur) {
      onBlur();
    }
  };
  handleKeyDown = event => {
    const {
      open,
      originalDate
    } = this.state;
    switch (event.key) {
      case 'ArrowLeft':
        if (open) {
          this.adjustDate(-1, -1, -1);
        } else {
          this.open();
        }
        event.preventDefault();
        break;
      case 'ArrowUp':
        if (open) {
          this.adjustDate(-7, -4, -4);
        } else {
          this.open();
        }
        event.preventDefault();
        break;
      case 'ArrowRight':
        if (open) {
          this.adjustDate(1, 1, 1);
        } else {
          this.open();
        }
        event.preventDefault();
        break;
      case 'ArrowDown':
        if (open) {
          this.adjustDate(7, 4, 4);
        } else {
          this.open();
        }
        event.preventDefault();
        break;
      case 'Escape':
        if (originalDate !== null) {
          this.props.onChange(originalDate);
        }
        this.close();
        event.preventDefault();
        break;
    }
  };
  adjustDate = (daysToAdd, monthsToAdd, yearsToAdd) => {
    const {
      selectedDate,
      min,
      max,
      mode,
      originalDate
    } = this.state;
    if (originalDate === null) {
      this.setState({
        originalDate: selectedDate
      });
    }
    let date;
    if (selectedDate) {
      date = new Date(mode === 'year' ? selectedDate.getFullYear() + yearsToAdd : selectedDate.getFullYear(), mode === 'month' ? selectedDate.getMonth() + monthsToAdd : selectedDate.getMonth(), mode === 'day' ? selectedDate.getDate() + daysToAdd : selectedDate.getDate());
    } else {
      date = getStartOfDay(new Date());
    }
    if (date) {
      date = moveToWithinRange(date, min, max);
    }
    if (date?.getTime() !== selectedDate?.getTime()) {
      this.props.onChange(date);
    }
  };
  focusOn = (preferredElement, fallbackElement) => {
    const element = this.element.current?.querySelector(preferredElement);
    if (element) {
      element.focus();
    } else if (fallbackElement) {
      this.focusOn(fallbackElement);
    }
  };
  switchMode = mode => {
    this.setState({
      mode
    }, () => {
      this.focusOn('.active', '.today');
    });
  };
  switchToDays = () => this.switchMode('day');
  switchToMonths = () => this.switchMode('month');
  switchToYears = () => this.switchMode('year');
  handleSelectedDateUpdate = selectedDate => {
    this.setState({
      selectedDate
    }, () => {
      this.props.onChange(selectedDate);
      this.close();
      this.focusOn('.btn');
    });
  };
  handleViewDateUpdate = ({
    month = this.state.viewMonth,
    year = this.state.viewYear
  }) => {
    this.setState({
      viewMonth: month,
      viewYear: year
    });
  };
  getCalendar = () => {
    const {
      selectedDate,
      min,
      max,
      viewMonth,
      viewYear,
      mode,
      isMobile
    } = this.state;
    const {
      placeholder,
      monthFormat
    } = this.props;
    return /*#__PURE__*/jsxs("div", {
      className: clsx({
        'p-a-1': !isMobile
      }),
      children: [mode === 'day' && /*#__PURE__*/jsx(DayCalendar, {
        selectedDate: selectedDate,
        min: min,
        max: max,
        viewMonth: viewMonth,
        viewYear: viewYear,
        monthFormat: monthFormat,
        onSelect: this.handleSelectedDateUpdate,
        onLabelClick: this.switchToYears,
        onViewDateUpdate: this.handleViewDateUpdate
      }), mode === 'month' && /*#__PURE__*/jsx(MonthCalendar, {
        selectedDate: selectedDate,
        min: min,
        max: max,
        viewYear: viewYear,
        placeholder: placeholder,
        onSelect: this.switchToDays,
        onLabelClick: this.switchToYears,
        onViewDateUpdate: this.handleViewDateUpdate
      }), mode === 'year' && /*#__PURE__*/jsx(YearCalendar, {
        selectedDate: selectedDate,
        min: min,
        max: max,
        viewYear: viewYear,
        placeholder: placeholder,
        onSelect: this.switchToMonths,
        onViewDateUpdate: this.handleViewDateUpdate
      })]
    });
  };
  handleClear = () => {
    this.props.onChange(null);
    this.focusOn('.np-date-trigger');
  };
  render() {
    const {
      selectedDate,
      open
    } = this.state;
    const {
      inputAttributes,
      id: idProp,
      'aria-labelledby': ariaLabelledByProp,
      size,
      placeholder,
      label,
      monthFormat,
      disabled,
      clearable,
      value
    } = this.props;
    const id = idProp ?? inputAttributes?.id;
    const ariaLabelledBy = ariaLabelledByProp ?? inputAttributes?.['aria-labelledby'];
    return /*#__PURE__*/jsx("div", {
      ref: this.element,
      ...inputAttributes,
      id: id,
      className: "input-group",
      onKeyDown: this.handleKeyDown,
      children: /*#__PURE__*/jsxs(OverlayIdProvider, {
        open: open,
        children: [/*#__PURE__*/jsx(DateTrigger, {
          ariaLabelledBy: ariaLabelledBy,
          selectedDate: selectedDate,
          size: size,
          placeholder: placeholder,
          label: label,
          monthFormat: monthFormat,
          disabled: disabled || false,
          onClick: this.open,
          onClear: !disabled && clearable && value ? this.handleClear : undefined
        }), /*#__PURE__*/jsx(ResponsivePanel, {
          anchorRef: this.element,
          open: open,
          className: "tw-date-lookup-menu",
          position: Position.BOTTOM,
          onClose: this.discard,
          children: this.getCalendar()
        })]
      })
    });
  }
}
var DateLookup$1 = withInputAttributes(DateLookup, {
  nonLabelable: true
});

export { DateLookup$1 as default };
//# sourceMappingURL=DateLookup.mjs.map
